diff --git a/[refs] b/[refs]
index e6a06235e130..59d5a105c7c6 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: 117494a1b65183f0e3fcc817b07944bc5c465050
+refs/heads/master: 43cc71eed1250755986da4c0f9898f9a635cb3bf
diff --git a/trunk/Documentation/DocBook/Makefile b/trunk/Documentation/DocBook/Makefile
index 1a7f53068ec2..08687e45e19d 100644
--- a/trunk/Documentation/DocBook/Makefile
+++ b/trunk/Documentation/DocBook/Makefile
@@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
procfs-guide.xml writing_usb_driver.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
- genericirq.xml s390-drivers.xml
+ genericirq.xml
###
# The build process is as follows (targets):
diff --git a/trunk/Documentation/DocBook/s390-drivers.tmpl b/trunk/Documentation/DocBook/s390-drivers.tmpl
deleted file mode 100644
index 254e769282a4..000000000000
--- a/trunk/Documentation/DocBook/s390-drivers.tmpl
+++ /dev/null
@@ -1,149 +0,0 @@
-
-
-
-
-
- Writing s390 channel device drivers
-
-
-
- Cornelia
- Huck
-
-
- cornelia.huck@de.ibm.com
-
-
-
-
-
-
- 2007
- IBM Corp.
-
-
-
-
- This documentation is free software; you can redistribute
- it and/or modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later
- version.
-
-
-
- This program is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
-
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
-
-
-
- For more details see the file COPYING in the source
- distribution of Linux.
-
-
-
-
-
-
-
- Introduction
-
- This document describes the interfaces available for device drivers that
- drive s390 based channel attached devices. This includes interfaces for
- interaction with the hardware and interfaces for interacting with the
- common driver core. Those interfaces are provided by the s390 common I/O
- layer.
-
-
- The document assumes a familarity with the technical terms associated
- with the s390 channel I/O architecture. For a description of this
- architecture, please refer to the "z/Architecture: Principles of
- Operation", IBM publication no. SA22-7832.
-
-
- While most I/O devices on a s390 system are typically driven through the
- channel I/O mechanism described here, there are various other methods
- (like the diag interface). These are out of the scope of this document.
-
-
- Some additional information can also be found in the kernel source
- under Documentation/s390/driver-model.txt.
-
-
-
- The ccw bus
-
- The ccw bus typically contains the majority of devices available to
- a s390 system. Named after the channel command word (ccw), the basic
- command structure used to address its devices, the ccw bus contains
- so-called channel attached devices. They are addressed via subchannels,
- visible on the css bus. A device driver, however, will never interact
- with the subchannel directly, but only via the device on the ccw bus,
- the ccw device.
-
-
- I/O functions for channel-attached devices
-
- Some hardware structures have been translated into C structures for use
- by the common I/O layer and device drivers. For more information on
- the hardware structures represented here, please consult the Principles
- of Operation.
-
-!Iinclude/asm-s390/cio.h
-
-
- ccw devices
-
- Devices that want to initiate channel I/O need to attach to the ccw bus.
- Interaction with the driver core is done via the common I/O layer, which
- provides the abstractions of ccw devices and ccw device drivers.
-
-
- The functions that initiate or terminate channel I/O all act upon a
- ccw device structure. Device drivers must not bypass those functions
- or strange side effects may happen.
-
-!Iinclude/asm-s390/ccwdev.h
-!Edrivers/s390/cio/device.c
-!Edrivers/s390/cio/device_ops.c
-
-
- The channel-measurement facility
-
- The channel-measurement facility provides a means to collect
- measurement data which is made available by the channel subsystem
- for each channel attached device.
-
-!Iinclude/asm-s390/cmb.h
-!Edrivers/s390/cio/cmf.c
-
-
-
-
- The ccwgroup bus
-
- The ccwgroup bus only contains artificial devices, created by the user.
- Many networking devices (e.g. qeth) are in fact composed of several
- ccw devices (like read, write and data channel for qeth). The
- ccwgroup bus provides a mechanism to create a meta-device which
- contains those ccw devices as slave devices and can be associated
- with the netdevice.
-
-
- ccw group devices
-!Iinclude/asm-s390/ccwgroup.h
-!Edrivers/s390/cio/ccwgroup.c
-
-
-
-
diff --git a/trunk/Documentation/filesystems/ntfs.txt b/trunk/Documentation/filesystems/ntfs.txt
index e79ee2db183a..8ee10ec88293 100644
--- a/trunk/Documentation/filesystems/ntfs.txt
+++ b/trunk/Documentation/filesystems/ntfs.txt
@@ -407,7 +407,7 @@ raiddev /dev/md0
device /dev/hda5
raid-disk 0
device /dev/hdb1
- raid-disk 1
+ raid-disl 1
For linear raid, just change the raid-level above to "raid-level linear", for
mirrors, change it to "raid-level 1", and for stripe sets with parity, change
@@ -457,8 +457,6 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
-2.1.29:
- - Fix a deadlock when mounting read-write.
2.1.28:
- Fix a deadlock.
2.1.27:
diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt
index f27cdd7125f2..a57c1f216b21 100644
--- a/trunk/Documentation/kernel-parameters.txt
+++ b/trunk/Documentation/kernel-parameters.txt
@@ -1009,10 +1009,6 @@ and is between 256 and 4096 characters. It is defined in the file
meye.*= [HW] Set MotionEye Camera parameters
See Documentation/video4linux/meye.txt.
- mfgpt_irq= [IA-32] Specify the IRQ to use for the
- Multi-Function General Purpose Timers on AMD Geode
- platforms.
-
mga= [HW,DRM]
mousedev.tap_time=
@@ -1164,9 +1160,6 @@ and is between 256 and 4096 characters. It is defined in the file
nomce [X86-32] Machine Check Exception
- nomfgpt [X86-32] Disable Multi-Function General Purpose
- Timer usage (for AMD Geode machines).
-
noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
diff --git a/trunk/Documentation/s390/00-INDEX b/trunk/Documentation/s390/00-INDEX
deleted file mode 100644
index 3a2b96302ecc..000000000000
--- a/trunk/Documentation/s390/00-INDEX
+++ /dev/null
@@ -1,26 +0,0 @@
-00-INDEX
- - this file.
-3270.ChangeLog
- - ChangeLog for the UTS Global 3270-support patch (outdated).
-3270.txt
- - how to use the IBM 3270 display system support.
-cds.txt
- - s390 common device support (common I/O layer).
-CommonIO
- - common I/O layer command line parameters, procfs and debugfs entries
-config3270.sh
- - example configuration for 3270 devices.
-DASD
- - information on the DASD disk device driver.
-Debugging390.txt
- - hints for debugging on s390 systems.
-driver-model.txt
- - information on s390 devices and the driver model.
-monreader.txt
- - information on accessing the z/VM monitor stream from Linux.
-s390dbf.txt
- - information on using the s390 debug feature.
-TAPE
- - information on the driver for channel-attached tapes.
-zfcpdump
- - information on the s390 SCSI dump tool.
diff --git a/trunk/Documentation/s390/CommonIO b/trunk/Documentation/s390/CommonIO
index 86320aa3fb0b..22f82f21bc60 100644
--- a/trunk/Documentation/s390/CommonIO
+++ b/trunk/Documentation/s390/CommonIO
@@ -1,5 +1,5 @@
-S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
-============================================================================
+S/390 common I/O-Layer - command line parameters and /proc entries
+==================================================================
Command line parameters
-----------------------
@@ -7,9 +7,9 @@ Command line parameters
* cio_msg = yes | no
Determines whether information on found devices and sensed device
- characteristics should be shown during startup or when new devices are
- found, i. e. messages of the types "Detected device 0.0.4711 on subchannel
- 0.0.0042" and "SenseID: Device 0.0.4711 reports: ...".
+ characteristics should be shown during startup, i. e. messages of the types
+ "Detected device 0.0.4711 on subchannel 0.0.0042" and "SenseID: Device
+ 0.0.4711 reports: ...".
Default is off.
@@ -26,10 +26,8 @@ Command line parameters
An ignored device can be un-ignored later; see the "/proc entries"-section for
details.
- The devices must be given either as bus ids (0.x.abcd) or as hexadecimal
- device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you
- give a device number 0xabcd, it will be interpreted as 0.0.abcd.
-
+ The devices must be given either as bus ids (0.0.abcd) or as hexadecimal
+ device numbers (0xabcd or abcd, for 2.4 backward compatibility).
You can use the 'all' keyword to ignore all devices.
The '!' operator will cause the I/O-layer to _not_ ignore a device.
The command line is parsed from left to right.
@@ -83,36 +81,31 @@ Command line parameters
will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
devices.
- The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
- compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
- numbers given as 0xabcd will be interpreted as 0.0.abcd.
-
-* For some of the information present in the /proc filesystem in 2.4 (namely,
- /proc/subchannels and /proc/chpids), see driver-model.txt.
- Information formerly in /proc/irq_count is now in /proc/interrupts.
-
+ The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward
+ compatibility, by the device number in hexadecimal (0xabcd or abcd).
-debugfs entries
----------------
-* /sys/kernel/debug/s390dbf/cio_*/ (S/390 debug feature)
+* /proc/s390dbf/cio_*/ (S/390 debug feature)
Some views generated by the debug feature to hold various debug outputs.
- - /sys/kernel/debug/s390dbf/cio_crw/sprintf
+ - /proc/s390dbf/cio_crw/sprintf
Messages from the processing of pending channel report words (machine check
- handling).
+ handling), which will also show when CONFIG_DEBUG_CRW is defined.
- - /sys/kernel/debug/s390dbf/cio_msg/sprintf
- Various debug messages from the common I/O-layer, including messages
- printed when cio_msg=yes.
+ - /proc/s390dbf/cio_msg/sprintf
+ Various debug messages from the common I/O-layer; generally, messages which
+ will also show when CONFIG_DEBUG_IO is defined.
- - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
+ - /proc/s390dbf/cio_trace/hex_ascii
Logs the calling of functions in the common I/O-layer and, if applicable,
which subchannel they were called for, as well as dumps of some data
structures (like irb in an error case).
The level of logging can be changed to be more or less verbose by piping to
- /sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the
- documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt)
- for details.
+ /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
+ the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
+
+* For some of the information present in the /proc filesystem in 2.4 (namely,
+ /proc/subchannels and /proc/chpids), see driver-model.txt.
+ Information formerly in /proc/irq_count is now in /proc/interrupts.
diff --git a/trunk/Documentation/s390/cds.txt b/trunk/Documentation/s390/cds.txt
index 3081927cc2d6..58919d6a593a 100644
--- a/trunk/Documentation/s390/cds.txt
+++ b/trunk/Documentation/s390/cds.txt
@@ -286,10 +286,10 @@ first:
timeout value
-EIO: the common I/O layer terminated the request due to an error state
-If the concurrent sense flag in the extended status word (esw) in the irb is
-set, the field erw.scnt in the esw describes the number of device specific
-sense bytes available in the extended control word irb->scsw.ecw[]. No device
-sensing by the device driver itself is required.
+If the concurrent sense flag in the extended status word in the irb is set, the
+field irb->scsw.count describes the number of device specific sense bytes
+available in the extended control word irb->scsw.ecw[0]. No device sensing by
+the device driver itself is required.
The device interrupt handler can use the following definitions to investigate
the primary unit check source coded in sense byte 0 :
diff --git a/trunk/Documentation/usb/authorization.txt b/trunk/Documentation/usb/authorization.txt
deleted file mode 100644
index 2af400609498..000000000000
--- a/trunk/Documentation/usb/authorization.txt
+++ /dev/null
@@ -1,92 +0,0 @@
-
-Authorizing (or not) your USB devices to connect to the system
-
-(C) 2007 Inaky Perez-Gonzalez Intel Corporation
-
-This feature allows you to control if a USB device can be used (or
-not) in a system. This feature will allow you to implement a lock-down
-of USB devices, fully controlled by user space.
-
-As of now, when a USB device is connected it is configured and
-it's interfaces inmediately made available to the users. With this
-modification, only if root authorizes the device to be configured will
-then it be possible to use it.
-
-Usage:
-
-Authorize a device to connect:
-
-$ echo 1 > /sys/usb/devices/DEVICE/authorized
-
-Deauthorize a device:
-
-$ echo 0 > /sys/usb/devices/DEVICE/authorized
-
-Set new devices connected to hostX to be deauthorized by default (ie:
-lock down):
-
-$ echo 0 > /sys/bus/devices/usbX/authorized_default
-
-Remove the lock down:
-
-$ echo 1 > /sys/bus/devices/usbX/authorized_default
-
-By default, Wired USB devices are authorized by default to
-connect. Wireless USB hosts deauthorize by default all new connected
-devices (this is so because we need to do an authentication phase
-before authorizing).
-
-
-Example system lockdown (lame)
------------------------
-
-Imagine you want to implement a lockdown so only devices of type XYZ
-can be connected (for example, it is a kiosk machine with a visible
-USB port):
-
-boot up
-rc.local ->
-
- for host in /sys/bus/devices/usb*
- do
- echo 0 > $host/authorized_default
- done
-
-Hookup an script to udev, for new USB devices
-
- if device_is_my_type $DEV
- then
- echo 1 > $device_path/authorized
- done
-
-
-Now, device_is_my_type() is where the juice for a lockdown is. Just
-checking if the class, type and protocol match something is the worse
-security verification you can make (or the best, for someone willing
-to break it). If you need something secure, use crypto and Certificate
-Authentication or stuff like that. Something simple for an storage key
-could be:
-
-function device_is_my_type()
-{
- echo 1 > authorized # temporarily authorize it
- # FIXME: make sure none can mount it
- mount DEVICENODE /mntpoint
- sum=$(md5sum /mntpoint/.signature)
- if [ $sum = $(cat /etc/lockdown/keysum) ]
- then
- echo "We are good, connected"
- umount /mntpoint
- # Other stuff so others can use it
- else
- echo 0 > authorized
- fi
-}
-
-
-Of course, this is lame, you'd want to do a real certificate
-verification stuff with PKI, so you don't depend on a shared secret,
-etc, but you get the idea. Anybody with access to a device gadget kit
-can fake descriptors and device info. Don't trust that. You are
-welcome.
-
diff --git a/trunk/Documentation/usb/power-management.txt b/trunk/Documentation/usb/power-management.txt
deleted file mode 100644
index 97842deec471..000000000000
--- a/trunk/Documentation/usb/power-management.txt
+++ /dev/null
@@ -1,517 +0,0 @@
- Power Management for USB
-
- Alan Stern
-
- October 5, 2007
-
-
-
- What is Power Management?
- -------------------------
-
-Power Management (PM) is the practice of saving energy by suspending
-parts of a computer system when they aren't being used. While a
-component is "suspended" it is in a nonfunctional low-power state; it
-might even be turned off completely. A suspended component can be
-"resumed" (returned to a functional full-power state) when the kernel
-needs to use it. (There also are forms of PM in which components are
-placed in a less functional but still usable state instead of being
-suspended; an example would be reducing the CPU's clock rate. This
-document will not discuss those other forms.)
-
-When the parts being suspended include the CPU and most of the rest of
-the system, we speak of it as a "system suspend". When a particular
-device is turned off while the system as a whole remains running, we
-call it a "dynamic suspend" (also known as a "runtime suspend" or
-"selective suspend"). This document concentrates mostly on how
-dynamic PM is implemented in the USB subsystem, although system PM is
-covered to some extent (see Documentation/power/*.txt for more
-information about system PM).
-
-Note: Dynamic PM support for USB is present only if the kernel was
-built with CONFIG_USB_SUSPEND enabled. System PM support is present
-only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
-enabled.
-
-
- What is Remote Wakeup?
- ----------------------
-
-When a device has been suspended, it generally doesn't resume until
-the computer tells it to. Likewise, if the entire computer has been
-suspended, it generally doesn't resume until the user tells it to, say
-by pressing a power button or opening the cover.
-
-However some devices have the capability of resuming by themselves, or
-asking the kernel to resume them, or even telling the entire computer
-to resume. This capability goes by several names such as "Wake On
-LAN"; we will refer to it generically as "remote wakeup". When a
-device is enabled for remote wakeup and it is suspended, it may resume
-itself (or send a request to be resumed) in response to some external
-event. Examples include a suspended keyboard resuming when a key is
-pressed, or a suspended USB hub resuming when a device is plugged in.
-
-
- When is a USB device idle?
- --------------------------
-
-A device is idle whenever the kernel thinks it's not busy doing
-anything important and thus is a candidate for being suspended. The
-exact definition depends on the device's driver; drivers are allowed
-to declare that a device isn't idle even when there's no actual
-communication taking place. (For example, a hub isn't considered idle
-unless all the devices plugged into that hub are already suspended.)
-In addition, a device isn't considered idle so long as a program keeps
-its usbfs file open, whether or not any I/O is going on.
-
-If a USB device has no driver, its usbfs file isn't open, and it isn't
-being accessed through sysfs, then it definitely is idle.
-
-
- Forms of dynamic PM
- -------------------
-
-Dynamic suspends can occur in two ways: manual and automatic.
-"Manual" means that the user has told the kernel to suspend a device,
-whereas "automatic" means that the kernel has decided all by itself to
-suspend a device. Automatic suspend is called "autosuspend" for
-short. In general, a device won't be autosuspended unless it has been
-idle for some minimum period of time, the so-called idle-delay time.
-
-Of course, nothing the kernel does on its own initiative should
-prevent the computer or its devices from working properly. If a
-device has been autosuspended and a program tries to use it, the
-kernel will automatically resume the device (autoresume). For the
-same reason, an autosuspended device will usually have remote wakeup
-enabled, if the device supports remote wakeup.
-
-It is worth mentioning that many USB drivers don't support
-autosuspend. In fact, at the time of this writing (Linux 2.6.23) the
-only drivers which do support it are the hub driver, kaweth, asix,
-usblp, usblcd, and usb-skeleton (which doesn't count). If a
-non-supporting driver is bound to a device, the device won't be
-autosuspended. In effect, the kernel pretends the device is never
-idle.
-
-We can categorize power management events in two broad classes:
-external and internal. External events are those triggered by some
-agent outside the USB stack: system suspend/resume (triggered by
-userspace), manual dynamic suspend/resume (also triggered by
-userspace), and remote wakeup (triggered by the device). Internal
-events are those triggered within the USB stack: autosuspend and
-autoresume.
-
-
- The user interface for dynamic PM
- ---------------------------------
-
-The user interface for controlling dynamic PM is located in the power/
-subdirectory of each USB device's sysfs directory, that is, in
-/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
-relevant attribute files are: wakeup, level, and autosuspend.
-
- power/wakeup
-
- This file is empty if the device does not support
- remote wakeup. Otherwise the file contains either the
- word "enabled" or the word "disabled", and you can
- write those words to the file. The setting determines
- whether or not remote wakeup will be enabled when the
- device is next suspended. (If the setting is changed
- while the device is suspended, the change won't take
- effect until the following suspend.)
-
- power/level
-
- This file contains one of three words: "on", "auto",
- or "suspend". You can write those words to the file
- to change the device's setting.
-
- "on" means that the device should be resumed and
- autosuspend is not allowed. (Of course, system
- suspends are still allowed.)
-
- "auto" is the normal state in which the kernel is
- allowed to autosuspend and autoresume the device.
-
- "suspend" means that the device should remain
- suspended, and autoresume is not allowed. (But remote
- wakeup may still be allowed, since it is controlled
- separately by the power/wakeup attribute.)
-
- power/autosuspend
-
- This file contains an integer value, which is the
- number of seconds the device should remain idle before
- the kernel will autosuspend it (the idle-delay time).
- The default is 2. 0 means to autosuspend as soon as
- the device becomes idle, and -1 means never to
- autosuspend. You can write a number to the file to
- change the autosuspend idle-delay time.
-
-Writing "-1" to power/autosuspend and writing "on" to power/level do
-essentially the same thing -- they both prevent the device from being
-autosuspended. Yes, this is a redundancy in the API.
-
-(In 2.6.21 writing "0" to power/autosuspend would prevent the device
-from being autosuspended; the behavior was changed in 2.6.22. The
-power/autosuspend attribute did not exist prior to 2.6.21, and the
-power/level attribute did not exist prior to 2.6.22.)
-
-
- Changing the default idle-delay time
- ------------------------------------
-
-The default autosuspend idle-delay time is controlled by a module
-parameter in usbcore. You can specify the value when usbcore is
-loaded. For example, to set it to 5 seconds instead of 2 you would
-do:
-
- modprobe usbcore autosuspend=5
-
-Equivalently, you could add to /etc/modprobe.conf a line saying:
-
- options usbcore autosuspend=5
-
-Some distributions load the usbcore module very early during the boot
-process, by means of a program or script running from an initramfs
-image. To alter the parameter value you would have to rebuild that
-image.
-
-If usbcore is compiled into the kernel rather than built as a loadable
-module, you can add
-
- usbcore.autosuspend=5
-
-to the kernel's boot command line.
-
-Finally, the parameter value can be changed while the system is
-running. If you do:
-
- echo 5 >/sys/module/usbcore/parameters/autosuspend
-
-then each new USB device will have its autosuspend idle-delay
-initialized to 5. (The idle-delay values for already existing devices
-will not be affected.)
-
-Setting the initial default idle-delay to -1 will prevent any
-autosuspend of any USB device. This is a simple alternative to
-disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
-added benefit of allowing you to enable autosuspend for selected
-devices.
-
-
- Warnings
- --------
-
-The USB specification states that all USB devices must support power
-management. Nevertheless, the sad fact is that many devices do not
-support it very well. You can suspend them all right, but when you
-try to resume them they disconnect themselves from the USB bus or
-they stop working entirely. This seems to be especially prevalent
-among printers and scanners, but plenty of other types of device have
-the same deficiency.
-
-For this reason, by default the kernel disables autosuspend (the
-power/level attribute is initialized to "on") for all devices other
-than hubs. Hubs, at least, appear to be reasonably well-behaved in
-this regard.
-
-(In 2.6.21 and 2.6.22 this wasn't the case. Autosuspend was enabled
-by default for almost all USB devices. A number of people experienced
-problems as a result.)
-
-This means that non-hub devices won't be autosuspended unless the user
-or a program explicitly enables it. As of this writing there aren't
-any widespread programs which will do this; we hope that in the near
-future device managers such as HAL will take on this added
-responsibility. In the meantime you can always carry out the
-necessary operations by hand or add them to a udev script. You can
-also change the idle-delay time; 2 seconds is not the best choice for
-every device.
-
-Sometimes it turns out that even when a device does work okay with
-autosuspend there are still problems. For example, there are
-experimental patches adding autosuspend support to the usbhid driver,
-which manages keyboards and mice, among other things. Tests with a
-number of keyboards showed that typing on a suspended keyboard, while
-causing the keyboard to do a remote wakeup all right, would
-nonetheless frequently result in lost keystrokes. Tests with mice
-showed that some of them would issue a remote-wakeup request in
-response to button presses but not to motion, and some in response to
-neither.
-
-The kernel will not prevent you from enabling autosuspend on devices
-that can't handle it. It is even possible in theory to damage a
-device by suspending it at the wrong time -- for example, suspending a
-USB hard disk might cause it to spin down without parking the heads.
-(Highly unlikely, but possible.) Take care.
-
-
- The driver interface for Power Management
- -----------------------------------------
-
-The requirements for a USB driver to support external power management
-are pretty modest; the driver need only define
-
- .suspend
- .resume
- .reset_resume
-
-methods in its usb_driver structure, and the reset_resume method is
-optional. The methods' jobs are quite simple:
-
- The suspend method is called to warn the driver that the
- device is going to be suspended. If the driver returns a
- negative error code, the suspend will be aborted. Normally
- the driver will return 0, in which case it must cancel all
- outstanding URBs (usb_kill_urb()) and not submit any more.
-
- The resume method is called to tell the driver that the
- device has been resumed and the driver can return to normal
- operation. URBs may once more be submitted.
-
- The reset_resume method is called to tell the driver that
- the device has been resumed and it also has been reset.
- The driver should redo any necessary device initialization,
- since the device has probably lost most or all of its state
- (although the interfaces will be in the same altsettings as
- before the suspend).
-
-The reset_resume method is used by the USB Persist facility (see
-Documentation/usb/persist.txt) and it can also be used under certain
-circumstances when CONFIG_USB_PERSIST is not enabled. Currently, if a
-device is reset during a resume and the driver does not have a
-reset_resume method, the driver won't receive any notification about
-the resume. Later kernels will call the driver's disconnect method;
-2.6.23 doesn't do this.
-
-USB drivers are bound to interfaces, so their suspend and resume
-methods get called when the interfaces are suspended or resumed. In
-principle one might want to suspend some interfaces on a device (i.e.,
-force the drivers for those interface to stop all activity) without
-suspending the other interfaces. The USB core doesn't allow this; all
-interfaces are suspended when the device itself is suspended and all
-interfaces are resumed when the device is resumed. It isn't possible
-to suspend or resume some but not all of a device's interfaces. The
-closest you can come is to unbind the interfaces' drivers.
-
-
- The driver interface for autosuspend and autoresume
- ---------------------------------------------------
-
-To support autosuspend and autoresume, a driver should implement all
-three of the methods listed above. In addition, a driver indicates
-that it supports autosuspend by setting the .supports_autosuspend flag
-in its usb_driver structure. It is then responsible for informing the
-USB core whenever one of its interfaces becomes busy or idle. The
-driver does so by calling these three functions:
-
- int usb_autopm_get_interface(struct usb_interface *intf);
- void usb_autopm_put_interface(struct usb_interface *intf);
- int usb_autopm_set_interface(struct usb_interface *intf);
-
-The functions work by maintaining a counter in the usb_interface
-structure. When intf->pm_usage_count is > 0 then the interface is
-deemed to be busy, and the kernel will not autosuspend the interface's
-device. When intf->pm_usage_count is <= 0 then the interface is
-considered to be idle, and the kernel may autosuspend the device.
-
-(There is a similar pm_usage_count field in struct usb_device,
-associated with the device itself rather than any of its interfaces.
-This field is used only by the USB core.)
-
-The driver owns intf->pm_usage_count; it can modify the value however
-and whenever it likes. A nice aspect of the usb_autopm_* routines is
-that the changes they make are protected by the usb_device structure's
-PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
-without holding the mutex.
-
- usb_autopm_get_interface() increments pm_usage_count and
- attempts an autoresume if the new value is > 0 and the
- device is suspended.
-
- usb_autopm_put_interface() decrements pm_usage_count and
- attempts an autosuspend if the new value is <= 0 and the
- device isn't suspended.
-
- usb_autopm_set_interface() leaves pm_usage_count alone.
- It attempts an autoresume if the value is > 0 and the device
- is suspended, and it attempts an autosuspend if the value is
- <= 0 and the device isn't suspended.
-
-There also are a couple of utility routines drivers can use:
-
- usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
- usb_autopm_set_interface(), which will attempt an autoresume.
-
- usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
- usb_autopm_set_interface(), which will attempt an autosuspend.
-
-The conventional usage pattern is that a driver calls
-usb_autopm_get_interface() in its open routine and
-usb_autopm_put_interface() in its close or release routine. But
-other patterns are possible.
-
-The autosuspend attempts mentioned above will often fail for one
-reason or another. For example, the power/level attribute might be
-set to "on", or another interface in the same device might not be
-idle. This is perfectly normal. If the reason for failure was that
-the device hasn't been idle for long enough, a delayed workqueue
-routine is automatically set up to carry out the operation when the
-autosuspend idle-delay has expired.
-
-Autoresume attempts also can fail. This will happen if power/level is
-set to "suspend" or if the device doesn't manage to resume properly.
-Unlike autosuspend, there's no delay for an autoresume.
-
-
- Other parts of the driver interface
- -----------------------------------
-
-Sometimes a driver needs to make sure that remote wakeup is enabled
-during autosuspend. For example, there's not much point
-autosuspending a keyboard if the user can't cause the keyboard to do a
-remote wakeup by typing on it. If the driver sets
-intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
-device if remote wakeup isn't available or has been disabled through
-the power/wakeup attribute. (If the device is already autosuspended,
-though, setting this flag won't cause the kernel to autoresume it.
-Normally a driver would set this flag in its probe method, at which
-time the device is guaranteed not to be autosuspended.)
-
-The usb_autopm_* routines have to run in a sleepable process context;
-they must not be called from an interrupt handler or while holding a
-spinlock. In fact, the entire autosuspend mechanism is not well geared
-toward interrupt-driven operation. However there is one thing a
-driver can do in an interrupt handler:
-
- usb_mark_last_busy(struct usb_device *udev);
-
-This sets udev->last_busy to the current time. udev->last_busy is the
-field used for idle-delay calculations; updating it will cause any
-pending autosuspend to be moved back. The usb_autopm_* routines will
-also set the last_busy field to the current time.
-
-Calling urb_mark_last_busy() from within an URB completion handler is
-subject to races: The kernel may have just finished deciding the
-device has been idle for long enough but not yet gotten around to
-calling the driver's suspend method. The driver would have to be
-responsible for synchronizing its suspend method with its URB
-completion handler and causing the autosuspend to fail with -EBUSY if
-an URB had completed too recently.
-
-External suspend calls should never be allowed to fail in this way,
-only autosuspend calls. The driver can tell them apart by checking
-udev->auto_pm; this flag will be set to 1 for internal PM events
-(autosuspend or autoresume) and 0 for external PM events.
-
-Many of the ingredients in the autosuspend framework are oriented
-towards interfaces: The usb_interface structure contains the
-pm_usage_cnt field, and the usb_autopm_* routines take an interface
-pointer as their argument. But somewhat confusingly, a few of the
-pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
-structure instead. Drivers need to keep this straight; they can call
-interface_to_usbdev() to find the device structure for a given
-interface.
-
-
- Locking requirements
- --------------------
-
-All three suspend/resume methods are always called while holding the
-usb_device's PM mutex. For external events -- but not necessarily for
-autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
-also be held. This implies that external suspend/resume events are
-mutually exclusive with calls to probe, disconnect, pre_reset, and
-post_reset; the USB core guarantees that this is true of internal
-suspend/resume events as well.
-
-If a driver wants to block all suspend/resume calls during some
-critical section, it can simply acquire udev->pm_mutex.
-Alternatively, if the critical section might call some of the
-usb_autopm_* routines, the driver can avoid deadlock by doing:
-
- down(&udev->dev.sem);
- rc = usb_autopm_get_interface(intf);
-
-and at the end of the critical section:
-
- if (!rc)
- usb_autopm_put_interface(intf);
- up(&udev->dev.sem);
-
-Holding the device semaphore will block all external PM calls, and the
-usb_autopm_get_interface() will prevent any internal PM calls, even if
-it fails. (Exercise: Why?)
-
-The rules for locking order are:
-
- Never acquire any device semaphore while holding any PM mutex.
-
- Never acquire udev->pm_mutex while holding the PM mutex for
- a device that isn't a descendant of udev.
-
-In other words, PM mutexes should only be acquired going up the device
-tree, and they should be acquired only after locking all the device
-semaphores you need to hold. These rules don't matter to drivers very
-much; they usually affect just the USB core.
-
-Still, drivers do need to be careful. For example, many drivers use a
-private mutex to synchronize their normal I/O activities with their
-disconnect method. Now if the driver supports autosuspend then it
-must call usb_autopm_put_interface() from somewhere -- maybe from its
-close method. It should make the call while holding the private mutex,
-since a driver shouldn't call any of the usb_autopm_* functions for an
-interface from which it has been unbound.
-
-But the usb_autpm_* routines always acquire the device's PM mutex, and
-consequently the locking order has to be: private mutex first, PM
-mutex second. Since the suspend method is always called with the PM
-mutex held, it mustn't try to acquire the private mutex. It has to
-synchronize with the driver's I/O activities in some other way.
-
-
- Interaction between dynamic PM and system PM
- --------------------------------------------
-
-Dynamic power management and system power management can interact in
-a couple of ways.
-
-Firstly, a device may already be manually suspended or autosuspended
-when a system suspend occurs. Since system suspends are supposed to
-be as transparent as possible, the device should remain suspended
-following the system resume. The 2.6.23 kernel obeys this principle
-for manually suspended devices but not for autosuspended devices; they
-do get resumed when the system wakes up. (Presumably they will be
-autosuspended again after their idle-delay time expires.) In later
-kernels this behavior will be fixed.
-
-(There is an exception. If a device would undergo a reset-resume
-instead of a normal resume, and the device is enabled for remote
-wakeup, then the reset-resume takes place even if the device was
-already suspended when the system suspend began. The justification is
-that a reset-resume is a kind of remote-wakeup event. Or to put it
-another way, a device which needs a reset won't be able to generate
-normal remote-wakeup signals, so it ought to be resumed immediately.)
-
-Secondly, a dynamic power-management event may occur as a system
-suspend is underway. The window for this is short, since system
-suspends don't take long (a few seconds usually), but it can happen.
-For example, a suspended device may send a remote-wakeup signal while
-the system is suspending. The remote wakeup may succeed, which would
-cause the system suspend to abort. If the remote wakeup doesn't
-succeed, it may still remain active and thus cause the system to
-resume as soon as the system suspend is complete. Or the remote
-wakeup may fail and get lost. Which outcome occurs depends on timing
-and on the hardware and firmware design.
-
-More interestingly, a device might undergo a manual resume or
-autoresume during system suspend. With current kernels this shouldn't
-happen, because manual resumes must be initiated by userspace and
-autoresumes happen in response to I/O requests, but all user processes
-and I/O should be quiescent during a system suspend -- thanks to the
-freezer. However there are plans to do away with the freezer, which
-would mean these things would become possible. If and when this comes
-about, the USB core will carefully arrange matters so that either type
-of resume will block until the entire system has resumed.
diff --git a/trunk/Documentation/usb/usb-serial.txt b/trunk/Documentation/usb/usb-serial.txt
index 4e0b62b8566f..5b635ae84944 100644
--- a/trunk/Documentation/usb/usb-serial.txt
+++ b/trunk/Documentation/usb/usb-serial.txt
@@ -428,17 +428,6 @@ Options supported:
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
-Winchiphead CH341 Driver
-
- This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
- also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
- supported by the driver. The protocol was analyzed from the behaviour
- of the Windows driver, no datasheet is available at present.
- The manufacturer's website: http://www.winchiphead.com/.
- For any questions or problems with this driver, please contact
- frank@kingswood-consulting.co.uk.
-
-
Generic Serial driver
If your device is not one of the above listed devices, compatible with
diff --git a/trunk/Documentation/usb/usbmon.txt b/trunk/Documentation/usb/usbmon.txt
index 2917ce4ffdc4..53ae866ae37b 100644
--- a/trunk/Documentation/usb/usbmon.txt
+++ b/trunk/Documentation/usb/usbmon.txt
@@ -34,12 +34,9 @@ if usbmon is built into the kernel.
Verify that bus sockets are present.
# ls /sys/kernel/debug/usbmon
-0s 0t 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
+1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
#
-Now you can choose to either use the sockets numbered '0' (to capture packets on
-all buses), and skip to step #3, or find the bus used by your device with step #2.
-
2. Find which bus connects to the desired device
Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -59,10 +56,6 @@ Bus=03 means it's bus 3.
# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
-to listen on a single bus, otherwise, to listen on all buses, type:
-
-# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
-
This process will be reading until killed. Naturally, the output can be
redirected to a desirable location. This is preferred, because it is going
to be quite long.
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index 60e649ff6fdc..c4eca56ed5bf 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -677,13 +677,6 @@ P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
-ATMEL USBA UDC DRIVER
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
-L: kernel@avr32linux.org
-W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
-S: Supported
-
ATMEL WIRELESS DRIVER
P: Simon Kelley
M: simon@thekelleys.org.uk
diff --git a/trunk/arch/arm/mach-imx/cpufreq.c b/trunk/arch/arm/mach-imx/cpufreq.c
index e548ba74a4d2..467d899fbe75 100644
--- a/trunk/arch/arm/mach-imx/cpufreq.c
+++ b/trunk/arch/arm/mach-imx/cpufreq.c
@@ -269,6 +269,7 @@ static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
return -EINVAL;
policy->cur = policy->min = policy->max = imx_get_speed(0);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 8000;
policy->cpuinfo.max_freq = 200000;
/* Manual states, that PLL stabilizes in two CLK32 periods */
diff --git a/trunk/arch/arm/mach-sa1100/cpu-sa1110.c b/trunk/arch/arm/mach-sa1100/cpu-sa1110.c
index 36b47ff5af11..78f4c1346044 100644
--- a/trunk/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/trunk/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -331,6 +331,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/trunk/arch/arm/plat-omap/cpu-omap.c b/trunk/arch/arm/plat-omap/cpu-omap.c
index c0d63b0c61c9..a0c71dca2373 100644
--- a/trunk/arch/arm/plat-omap/cpu-omap.c
+++ b/trunk/arch/arm/plat-omap/cpu-omap.c
@@ -108,6 +108,7 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = omap_getspeed(0);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/trunk/arch/blackfin/mach-bf533/cpu.c b/trunk/arch/blackfin/mach-bf533/cpu.c
index b7a0e0fbd9af..6fd9cfd0a31b 100644
--- a/trunk/arch/blackfin/mach-bf533/cpu.c
+++ b/trunk/arch/blackfin/mach-bf533/cpu.c
@@ -118,6 +118,8 @@ static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
/*Now ,only support one cpu */
policy->cur = bf533_getfreq(0);
diff --git a/trunk/arch/blackfin/mach-bf537/boards/generic_board.c b/trunk/arch/blackfin/mach-bf537/boards/generic_board.c
index 6668c8e4a3fc..5e9d09eb8579 100644
--- a/trunk/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/trunk/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -40,7 +40,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/trunk/arch/blackfin/mach-bf537/boards/pnav10.c b/trunk/arch/blackfin/mach-bf537/boards/pnav10.c
index f83a2544004d..20507e92a3a4 100644
--- a/trunk/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/trunk/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -40,7 +40,7 @@
#include
#include
#include
-#include
+#include
#include
diff --git a/trunk/arch/blackfin/mach-bf537/boards/stamp.c b/trunk/arch/blackfin/mach-bf537/boards/stamp.c
index f42ba3aa86d7..47d7d4a0e73d 100644
--- a/trunk/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/trunk/arch/blackfin/mach-bf537/boards/stamp.c
@@ -40,7 +40,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/trunk/arch/i386/Kconfig b/trunk/arch/i386/Kconfig
index 6bbbc2755e44..2d85e4b87307 100644
--- a/trunk/arch/i386/Kconfig
+++ b/trunk/arch/i386/Kconfig
@@ -1206,16 +1206,6 @@ config SCx200HR_TIMER
processor goes idle (as is done by the scheduler). The
other workaround is idle=poll boot option.
-config GEODE_MFGPT_TIMER
- bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
- depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
- default y
- help
- This driver provides a clock event source based on the MFGPT
- timer(s) in the CS5535 and CS5536 companion chip for the geode.
- MFGPTs have a better resolution and max interval than the
- generic PIT, and are suitable for use as high-res timers.
-
config K8_NB
def_bool y
depends on AGP_AMD64
diff --git a/trunk/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/trunk/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
index b8498ea62068..8c6ec7070844 100644
--- a/trunk/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/trunk/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -321,6 +321,8 @@ acpi_cpufreq_cpu_init (
data->acpi_data.states[i].transition_latency * 1000;
}
}
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
policy->cur = processor_get_freq(data, policy->cpu);
/* table init */
diff --git a/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c b/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c
index 5123e9d4164b..901236fa0f07 100644
--- a/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -107,6 +107,8 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
}
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
/* if DEBUG is enabled set_pmode() measures the latency
* of a transition */
policy->cpuinfo.transition_latency = 25000;
diff --git a/trunk/arch/powerpc/platforms/pasemi/cpufreq.c b/trunk/arch/powerpc/platforms/pasemi/cpufreq.c
index 1cfb8b0c8fec..3ae083851b01 100644
--- a/trunk/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/trunk/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -195,6 +195,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
}
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
policy->cpuinfo.transition_latency = get_gizmo_latency();
cur_astate = get_cur_astate(policy->cpu);
diff --git a/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c b/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c
index c04abcc28a7a..1fe35dab0e9e 100644
--- a/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -410,6 +410,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -ENODEV;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = cur_freq;
diff --git a/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c b/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c
index 4dfb4bc242b5..00f50298c342 100644
--- a/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -357,6 +357,7 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
/* secondary CPUs are tied to the primary one by the
diff --git a/trunk/arch/s390/appldata/appldata_base.c b/trunk/arch/s390/appldata/appldata_base.c
index ac61cf43a7d9..62391fb1f61f 100644
--- a/trunk/arch/s390/appldata/appldata_base.c
+++ b/trunk/arch/s390/appldata/appldata_base.c
@@ -547,7 +547,8 @@ static void __cpuinit appldata_online_cpu(int cpu)
spin_unlock(&appldata_timer_lock);
}
-static void __cpuinit appldata_offline_cpu(int cpu)
+static void
+appldata_offline_cpu(int cpu)
{
del_virt_timer(&per_cpu(appldata_timer, cpu));
if (atomic_dec_and_test(&appldata_expire_count)) {
@@ -559,9 +560,9 @@ static void __cpuinit appldata_offline_cpu(int cpu)
spin_unlock(&appldata_timer_lock);
}
-static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
- unsigned long action,
- void *hcpu)
+static int __cpuinit
+appldata_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
{
switch (action) {
case CPU_ONLINE:
@@ -607,15 +608,63 @@ static int __init appldata_init(void)
register_hotcpu_notifier(&appldata_nb);
appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
+#ifdef MODULE
+ appldata_dir_table[0].de->owner = THIS_MODULE;
+ appldata_table[0].de->owner = THIS_MODULE;
+ appldata_table[1].de->owner = THIS_MODULE;
+#endif
P_DEBUG("Base interface initialized.\n");
return 0;
}
-__initcall(appldata_init);
+/*
+ * appldata_exit()
+ *
+ * stop timer, unregister /proc entries
+ */
+static void __exit appldata_exit(void)
+{
+ struct list_head *lh;
+ struct appldata_ops *ops;
+ int rc, i;
+ P_DEBUG("Unloading module ...\n");
+ /*
+ * ops list should be empty, but just in case something went wrong...
+ */
+ spin_lock(&appldata_ops_lock);
+ list_for_each(lh, &appldata_ops_list) {
+ ops = list_entry(lh, struct appldata_ops, list);
+ rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
+ (unsigned long) ops->data, ops->size,
+ ops->mod_lvl);
+ if (rc != 0) {
+ P_ERROR("STOP DIAG 0xDC for %s failed, "
+ "return code: %d\n", ops->name, rc);
+ }
+ }
+ spin_unlock(&appldata_ops_lock);
+
+ for_each_online_cpu(i)
+ appldata_offline_cpu(i);
+
+ appldata_timer_active = 0;
+
+ unregister_sysctl_table(appldata_sysctl_header);
+
+ destroy_workqueue(appldata_wq);
+ P_DEBUG("... module unloaded!\n");
+}
/**************************** init / exit ******************************/
+
+module_init(appldata_init);
+module_exit(appldata_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerald Schaefer");
+MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
+
EXPORT_SYMBOL_GPL(appldata_register_ops);
EXPORT_SYMBOL_GPL(appldata_unregister_ops);
EXPORT_SYMBOL_GPL(appldata_diag);
diff --git a/trunk/arch/s390/kernel/audit.c b/trunk/arch/s390/kernel/audit.c
index f4932c22ebe4..d1c76fe10f29 100644
--- a/trunk/arch/s390/kernel/audit.c
+++ b/trunk/arch/s390/kernel/audit.c
@@ -2,7 +2,6 @@
#include
#include
#include
-#include "audit.h"
static unsigned dir_class[] = {
#include
@@ -41,6 +40,7 @@ int audit_classify_arch(int arch)
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_COMPAT
+ extern int s390_classify_syscall(unsigned);
if (abi == AUDIT_ARCH_S390)
return s390_classify_syscall(syscall);
#endif
@@ -61,6 +61,11 @@ int audit_classify_syscall(int abi, unsigned syscall)
static int __init audit_classes_init(void)
{
#ifdef CONFIG_COMPAT
+ extern __u32 s390_dir_class[];
+ extern __u32 s390_write_class[];
+ extern __u32 s390_read_class[];
+ extern __u32 s390_chattr_class[];
+ extern __u32 s390_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
diff --git a/trunk/arch/s390/kernel/audit.h b/trunk/arch/s390/kernel/audit.h
deleted file mode 100644
index 12b56f4b5a73..000000000000
--- a/trunk/arch/s390/kernel/audit.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __ARCH_S390_KERNEL_AUDIT_H
-#define __ARCH_S390_KERNEL_AUDIT_H
-
-#include
-
-#ifdef CONFIG_COMPAT
-extern int s390_classify_syscall(unsigned);
-extern __u32 s390_dir_class[];
-extern __u32 s390_write_class[];
-extern __u32 s390_read_class[];
-extern __u32 s390_chattr_class[];
-extern __u32 s390_signal_class[];
-#endif /* CONFIG_COMPAT */
-
-#endif /* __ARCH_S390_KERNEL_AUDIT_H */
diff --git a/trunk/arch/s390/kernel/compat_audit.c b/trunk/arch/s390/kernel/compat_audit.c
index d6487bf879e5..0569f5126e49 100644
--- a/trunk/arch/s390/kernel/compat_audit.c
+++ b/trunk/arch/s390/kernel/compat_audit.c
@@ -1,6 +1,5 @@
#undef __s390x__
#include
-#include "audit.h"
unsigned s390_dir_class[] = {
#include
diff --git a/trunk/arch/s390/kernel/cpcmd.c b/trunk/arch/s390/kernel/cpcmd.c
index d8c1131e0815..6c89f30c8e31 100644
--- a/trunk/arch/s390/kernel/cpcmd.c
+++ b/trunk/arch/s390/kernel/cpcmd.c
@@ -2,7 +2,7 @@
* arch/s390/kernel/cpcmd.c
*
* S390 version
- * Copyright IBM Corp. 1999,2007
+ * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Christian Borntraeger (cborntra@de.ibm.com),
*/
@@ -21,49 +21,6 @@
static DEFINE_SPINLOCK(cpcmd_lock);
static char cpcmd_buf[241];
-static int diag8_noresponse(int cmdlen)
-{
- register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
- register unsigned long reg3 asm ("3") = cmdlen;
-
- asm volatile(
-#ifndef CONFIG_64BIT
- " diag %1,%0,0x8\n"
-#else /* CONFIG_64BIT */
- " sam31\n"
- " diag %1,%0,0x8\n"
- " sam64\n"
-#endif /* CONFIG_64BIT */
- : "+d" (reg3) : "d" (reg2) : "cc");
- return reg3;
-}
-
-static int diag8_response(int cmdlen, char *response, int *rlen)
-{
- register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
- register unsigned long reg3 asm ("3") = (addr_t) response;
- register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
- register unsigned long reg5 asm ("5") = *rlen;
-
- asm volatile(
-#ifndef CONFIG_64BIT
- " diag %2,%0,0x8\n"
- " brc 8,1f\n"
- " ar %1,%4\n"
-#else /* CONFIG_64BIT */
- " sam31\n"
- " diag %2,%0,0x8\n"
- " sam64\n"
- " brc 8,1f\n"
- " agr %1,%4\n"
-#endif /* CONFIG_64BIT */
- "1:\n"
- : "+d" (reg4), "+d" (reg5)
- : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
- *rlen = reg5;
- return reg4;
-}
-
/*
* __cpcmd has some restrictions over cpcmd
* - the response buffer must reside below 2GB (if any)
@@ -71,27 +28,59 @@ static int diag8_response(int cmdlen, char *response, int *rlen)
*/
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
{
- int cmdlen;
- int rc;
- int response_len;
+ unsigned cmdlen;
+ int return_code, return_len;
cmdlen = strlen(cmd);
BUG_ON(cmdlen > 240);
memcpy(cpcmd_buf, cmd, cmdlen);
ASCEBC(cpcmd_buf, cmdlen);
- if (response) {
+ if (response != NULL && rlen > 0) {
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = (addr_t) response;
+ register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+ register unsigned long reg5 asm ("5") = rlen;
+
memset(response, 0, rlen);
- response_len = rlen;
- rc = diag8_response(cmdlen, response, &rlen);
- EBCASC(response, response_len);
+ asm volatile(
+#ifndef CONFIG_64BIT
+ " diag %2,%0,0x8\n"
+ " brc 8,1f\n"
+ " ar %1,%4\n"
+#else /* CONFIG_64BIT */
+ " sam31\n"
+ " diag %2,%0,0x8\n"
+ " sam64\n"
+ " brc 8,1f\n"
+ " agr %1,%4\n"
+#endif /* CONFIG_64BIT */
+ "1:\n"
+ : "+d" (reg4), "+d" (reg5)
+ : "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
+ return_code = (int) reg4;
+ return_len = (int) reg5;
+ EBCASC(response, rlen);
} else {
- rc = diag8_noresponse(cmdlen);
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = cmdlen;
+ return_len = 0;
+ asm volatile(
+#ifndef CONFIG_64BIT
+ " diag %1,%0,0x8\n"
+#else /* CONFIG_64BIT */
+ " sam31\n"
+ " diag %1,%0,0x8\n"
+ " sam64\n"
+#endif /* CONFIG_64BIT */
+ : "+d" (reg3) : "d" (reg2) : "cc");
+ return_code = (int) reg3;
}
- if (response_code)
- *response_code = rc;
- return rlen;
+ if (response_code != NULL)
+ *response_code = return_code;
+ return return_len;
}
+
EXPORT_SYMBOL(__cpcmd);
int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
@@ -120,4 +109,5 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
}
return len;
}
+
EXPORT_SYMBOL(cpcmd);
diff --git a/trunk/arch/s390/kernel/dis.c b/trunk/arch/s390/kernel/dis.c
index c14a336f6300..50d2235df732 100644
--- a/trunk/arch/s390/kernel/dis.c
+++ b/trunk/arch/s390/kernel/dis.c
@@ -1162,7 +1162,6 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
unsigned int value;
char separator;
char *ptr;
- int i;
ptr = buffer;
insn = find_insn(code);
@@ -1170,8 +1169,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
ptr += sprintf(ptr, "%.5s\t", insn->name);
/* Extract the operands. */
separator = 0;
- for (ops = formats[insn->format] + 1, i = 0;
- *ops != 0 && i < 6; ops++, i++) {
+ for (ops = formats[insn->format] + 1; *ops != 0; ops++) {
operand = operands + *ops;
value = extract_operand(code, operand);
if ((operand->flags & OPERAND_INDEX) && value == 0)
@@ -1243,6 +1241,7 @@ void show_code(struct pt_regs *regs)
}
/* Find a starting point for the disassembly. */
while (start < 32) {
+ hops = 0;
for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
if (!find_insn(code + start + i))
break;
diff --git a/trunk/arch/s390/kernel/ipl.c b/trunk/arch/s390/kernel/ipl.c
index 66b51901c87d..8b8f136d9cc7 100644
--- a/trunk/arch/s390/kernel/ipl.c
+++ b/trunk/arch/s390/kernel/ipl.c
@@ -735,10 +735,10 @@ void do_reipl(void)
case REIPL_METHOD_CCW_VM:
reipl_get_ascii_loadparm(loadparm);
if (strlen(loadparm) == 0)
- sprintf(buf, "IPL %X CLEAR",
+ sprintf(buf, "IPL %X",
reipl_block_ccw->ipl_info.ccw.devno);
else
- sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
+ sprintf(buf, "IPL %X LOADPARM '%s'",
reipl_block_ccw->ipl_info.ccw.devno, loadparm);
__cpcmd(buf, NULL, 0, NULL);
break;
diff --git a/trunk/arch/s390/kernel/vmlinux.lds.S b/trunk/arch/s390/kernel/vmlinux.lds.S
index 849120e3e28a..b4622a3889b0 100644
--- a/trunk/arch/s390/kernel/vmlinux.lds.S
+++ b/trunk/arch/s390/kernel/vmlinux.lds.S
@@ -2,7 +2,6 @@
* Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
-#include
#include
#ifndef CONFIG_64BIT
@@ -19,142 +18,121 @@ jiffies = jiffies_64;
SECTIONS
{
- . = 0x00000000;
- .text : {
- _text = .; /* Text and read-only data */
- *(.text.head)
+ . = 0x00000000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.text.head)
TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- *(.fixup)
- *(.gnu.warning)
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
} = 0x0700
- _etext = .; /* End of text section */
+ _etext = .; /* End of text section */
- RODATA
+ RODATA
#ifdef CONFIG_SHARED_KERNEL
- . = ALIGN(0x100000); /* VM shared segments are 1MB aligned */
+ . = ALIGN(1048576); /* VM shared segments are 1MB aligned */
#endif
- . = ALIGN(PAGE_SIZE);
- _eshared = .; /* End of shareable data */
-
- . = ALIGN(16); /* Exception table */
- __ex_table : {
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
- }
-
- NOTES
- BUG_TABLE
-
- .data : { /* Data */
- DATA_DATA
- CONSTRUCTORS
- }
-
- . = ALIGN(PAGE_SIZE);
- .data_nosave : {
- __nosave_begin = .;
- *(.data.nosave)
- }
- . = ALIGN(PAGE_SIZE);
- __nosave_end = .;
-
- . = ALIGN(PAGE_SIZE);
- .data.page_aligned : {
- *(.data.idt)
- }
-
- . = ALIGN(0x100);
- .data.cacheline_aligned : {
- *(.data.cacheline_aligned)
- }
-
- . = ALIGN(0x100);
- .data.read_mostly : {
- *(.data.read_mostly)
- }
- _edata = .; /* End of data section */
-
- . = ALIGN(2 * PAGE_SIZE); /* init_task */
- .data.init_task : {
- *(.data.init_task)
- }
-
- /* will be freed after init */
- . = ALIGN(PAGE_SIZE); /* Init code and data */
- __init_begin = .;
- .init.text : {
- _sinittext = .;
- *(.init.text)
- _einittext = .;
- }
- /*
- * .exit.text is discarded at runtime, not link time,
- * to deal with references from __bug_table
- */
- .exit.text : {
- *(.exit.text)
- }
-
- .init.data : {
- *(.init.data)
- }
- . = ALIGN(0x100);
- .init.setup : {
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
- }
- .initcall.init : {
- __initcall_start = .;
- INITCALLS
- __initcall_end = .;
- }
-
- .con_initcall.init : {
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
- }
- SECURITY_INIT
+ . = ALIGN(4096);
+ _eshared = .; /* End of shareable data */
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ NOTES
+
+ BUG_TABLE
+
+ .data : { /* Data */
+ DATA_DATA
+ CONSTRUCTORS
+ }
+
+ . = ALIGN(4096);
+ __nosave_begin = .;
+ .data_nosave : { *(.data.nosave) }
+ . = ALIGN(4096);
+ __nosave_end = .;
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(256);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ . = ALIGN(256);
+ .data.read_mostly : { *(.data.read_mostly) }
+ _edata = .; /* End of data section */
+
+ . = ALIGN(8192); /* init_task */
+ .data.init_task : { *(.data.init_task) }
+
+ /* will be freed after init */
+ . = ALIGN(4096); /* Init code and data */
+ __init_begin = .;
+ .init.text : {
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
+ /*
+ * .exit.text is discarded at runtime, not link time,
+ * to deal with references from __bug_table
+ */
+ .exit.text : { *(.exit.text) }
+
+ .init.data : { *(.init.data) }
+ . = ALIGN(256);
+ __setup_start = .;
+ .init.setup : { *(.init.setup) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : {
+ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
+ SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(0x100);
- .init.ramfs : {
- __initramfs_start = .;
- *(.init.ramfs)
- . = ALIGN(2);
- __initramfs_end = .;
- }
+ . = ALIGN(256);
+ __initramfs_start = .;
+ .init.ramfs : { *(.init.initramfs) }
+ . = ALIGN(2);
+ __initramfs_end = .;
#endif
-
- PERCPU(PAGE_SIZE)
- . = ALIGN(PAGE_SIZE);
- __init_end = .; /* freed after init ends here */
-
- /* BSS */
- .bss : {
- __bss_start = .;
- *(.bss)
- . = ALIGN(2);
- __bss_stop = .;
- }
-
- _end = . ;
-
- /* Sections to be discarded */
- /DISCARD/ : {
- *(.exit.data)
- *(.exitcall.exit)
- }
-
- /* Debugging sections. */
- STABS_DEBUG
- DWARF_DEBUG
+ PERCPU(4096)
+ . = ALIGN(4096);
+ __init_end = .;
+ /* freed after init ends here */
+
+ __bss_start = .; /* BSS */
+ .bss : { *(.bss) }
+ . = ALIGN(2);
+ __bss_stop = .;
+
+ _end = . ;
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ *(.exit.data) *(.exitcall.exit)
+ }
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
}
diff --git a/trunk/arch/s390/mm/fault.c b/trunk/arch/s390/mm/fault.c
index 4c1ac341ec80..54055194e9af 100644
--- a/trunk/arch/s390/mm/fault.c
+++ b/trunk/arch/s390/mm/fault.c
@@ -468,7 +468,7 @@ typedef struct {
__u64 refselmk;
__u64 refcmpmk;
__u64 reserved;
-} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
+} __attribute__ ((packed)) pfault_refbk_t;
int pfault_init(void)
{
diff --git a/trunk/arch/sh/kernel/cpufreq.c b/trunk/arch/sh/kernel/cpufreq.c
index 71d1c427b907..e61890217c50 100644
--- a/trunk/arch/sh/kernel/cpufreq.c
+++ b/trunk/arch/sh/kernel/cpufreq.c
@@ -93,6 +93,7 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cur = sh_cpufreq_get(policy->cpu);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
diff --git a/trunk/arch/sparc64/kernel/us2e_cpufreq.c b/trunk/arch/sparc64/kernel/us2e_cpufreq.c
index 791c15138f3a..1f83fe6a82d6 100644
--- a/trunk/arch/sparc64/kernel/us2e_cpufreq.c
+++ b/trunk/arch/sparc64/kernel/us2e_cpufreq.c
@@ -326,6 +326,7 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
table[2].index = 5;
table[3].frequency = CPUFREQ_TABLE_END;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
diff --git a/trunk/arch/x86/kernel/Makefile_32 b/trunk/arch/x86/kernel/Makefile_32
index 7ff02063b858..c624193740fd 100644
--- a/trunk/arch/x86/kernel/Makefile_32
+++ b/trunk/arch/x86/kernel/Makefile_32
@@ -7,7 +7,7 @@ extra-y := head_32.o init_task_32.o vmlinux.lds
obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
- quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
@@ -37,9 +37,9 @@ obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
obj-$(CONFIG_VM86) += vm86_32.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_HPET_TIMER) += hpet.o
+obj-$(CONFIG_HPET_TIMER) += hpet_32.o
obj-$(CONFIG_K8_NB) += k8.o
-obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o
+obj-$(CONFIG_MGEODE_LX) += geode_32.o
obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o
obj-$(CONFIG_PARAVIRT) += paravirt_32.o
diff --git a/trunk/arch/x86/kernel/Makefile_64 b/trunk/arch/x86/kernel/Makefile_64
index 43da66213a47..3ab017a0a3b9 100644
--- a/trunk/arch/x86/kernel/Makefile_64
+++ b/trunk/arch/x86/kernel/Makefile_64
@@ -8,8 +8,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \
x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
- pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
- perfctr-watchdog.o i8253.o
+ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \
+ perfctr-watchdog.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o
diff --git a/trunk/arch/x86/kernel/apic_64.c b/trunk/arch/x86/kernel/apic_64.c
index 395928de28ea..925758dbca0c 100644
--- a/trunk/arch/x86/kernel/apic_64.c
+++ b/trunk/arch/x86/kernel/apic_64.c
@@ -25,7 +25,6 @@
#include
#include
#include
-#include
#include
#include
@@ -40,9 +39,12 @@
#include
#include
+int apic_mapped;
int apic_verbosity;
-int disable_apic_timer __cpuinitdata;
-static int apic_calibrate_pmtmr __initdata;
+int apic_runs_main_timer;
+int apic_calibrate_pmtmr __initdata;
+
+int disable_apic_timer __initdata;
/* Local APIC timer works in C2? */
int local_apic_timer_c2_ok;
@@ -54,78 +56,14 @@ static struct resource lapic_resource = {
.flags = IORESOURCE_MEM | IORESOURCE_BUSY,
};
-static unsigned int calibration_result;
-
-static int lapic_next_event(unsigned long delta,
- struct clock_event_device *evt);
-static void lapic_timer_setup(enum clock_event_mode mode,
- struct clock_event_device *evt);
-
-static void lapic_timer_broadcast(cpumask_t mask);
-
-static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);
-
-static struct clock_event_device lapic_clockevent = {
- .name = "lapic",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
- | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
- .shift = 32,
- .set_mode = lapic_timer_setup,
- .set_next_event = lapic_next_event,
- .broadcast = lapic_timer_broadcast,
- .rating = 100,
- .irq = -1,
-};
-static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
-
-static int lapic_next_event(unsigned long delta,
- struct clock_event_device *evt)
-{
- apic_write(APIC_TMICT, delta);
- return 0;
-}
-
-static void lapic_timer_setup(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- unsigned long flags;
- unsigned int v;
-
- /* Lapic used as dummy for broadcast ? */
- if (evt->features & CLOCK_EVT_FEAT_DUMMY)
- return;
-
- local_irq_save(flags);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- case CLOCK_EVT_MODE_ONESHOT:
- __setup_APIC_LVTT(calibration_result,
- mode != CLOCK_EVT_MODE_PERIODIC, 1);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- v = apic_read(APIC_LVTT);
- v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
- apic_write(APIC_LVTT, v);
- break;
- case CLOCK_EVT_MODE_RESUME:
- /* Nothing to do here */
- break;
- }
-
- local_irq_restore(flags);
-}
-
/*
- * Local APIC timer broadcast function
+ * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
+ * IPIs in place of local APIC timers
*/
-static void lapic_timer_broadcast(cpumask_t mask)
-{
-#ifdef CONFIG_SMP
- send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
-#endif
-}
+static cpumask_t timer_interrupt_broadcast_ipi_mask;
+
+/* Using APIC to generate smp_local_timer_interrupt? */
+int using_apic_timer __read_mostly = 0;
static void apic_pm_activate(void);
@@ -246,10 +184,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
apic_write(APIC_SPIV, value);
if (!virt_wire_setup) {
- /*
- * For LVT0 make it edge triggered, active high,
- * external and enabled
- */
+ /* For LVT0 make it edge triggered, active high, external and enabled */
value = apic_read(APIC_LVT0);
value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -485,12 +420,10 @@ void __cpuinit setup_local_APIC (void)
value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
if (!smp_processor_id() && !value) {
value = APIC_DM_EXTINT;
- apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",
- smp_processor_id());
+ apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
} else {
value = APIC_DM_EXTINT | APIC_LVT_MASKED;
- apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
- smp_processor_id());
+ apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
}
apic_write(APIC_LVT0, value);
@@ -773,8 +706,8 @@ void __init init_apic_mappings(void)
apic_phys = mp_lapic_addr;
set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
- apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
- APIC_BASE, apic_phys);
+ apic_mapped = 1;
+ apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
/* Put local APIC into the resource map. */
lapic_resource.start = apic_phys;
@@ -797,14 +730,12 @@ void __init init_apic_mappings(void)
if (smp_found_config) {
ioapic_phys = mp_ioapics[i].mpc_apicaddr;
} else {
- ioapic_phys = (unsigned long)
- alloc_bootmem_pages(PAGE_SIZE);
+ ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
ioapic_phys = __pa(ioapic_phys);
}
set_fixmap_nocache(idx, ioapic_phys);
- apic_printk(APIC_VERBOSE,
- "mapped IOAPIC to %016lx (%016lx)\n",
- __fix_to_virt(idx), ioapic_phys);
+ apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
+ __fix_to_virt(idx), ioapic_phys);
idx++;
if (ioapic_res != NULL) {
@@ -827,14 +758,16 @@ void __init init_apic_mappings(void)
* P5 APIC double write bug.
*/
-static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
+#define APIC_DIVISOR 16
+
+static void __setup_APIC_LVTT(unsigned int clocks)
{
unsigned int lvtt_value, tmp_value;
+ int cpu = smp_processor_id();
- lvtt_value = LOCAL_TIMER_VECTOR;
- if (!oneshot)
- lvtt_value |= APIC_LVT_TIMER_PERIODIC;
- if (!irqen)
+ lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
+
+ if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
lvtt_value |= APIC_LVT_MASKED;
apic_write(APIC_LVTT, lvtt_value);
@@ -847,18 +780,44 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
| APIC_TDR_DIV_16);
- if (!oneshot)
- apic_write(APIC_TMICT, clocks);
+ apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
}
-static void setup_APIC_timer(void)
+static void setup_APIC_timer(unsigned int clocks)
{
- struct clock_event_device *levt = &__get_cpu_var(lapic_events);
+ unsigned long flags;
- memcpy(levt, &lapic_clockevent, sizeof(*levt));
- levt->cpumask = cpumask_of_cpu(smp_processor_id());
+ local_irq_save(flags);
- clockevents_register_device(levt);
+ /* wait for irq slice */
+ if (hpet_address && hpet_use_timer) {
+ u32 trigger = hpet_readl(HPET_T0_CMP);
+ while (hpet_readl(HPET_T0_CMP) == trigger)
+ /* do nothing */ ;
+ } else {
+ int c1, c2;
+ outb_p(0x00, 0x43);
+ c2 = inb_p(0x40);
+ c2 |= inb_p(0x40) << 8;
+ do {
+ c1 = c2;
+ outb_p(0x00, 0x43);
+ c2 = inb_p(0x40);
+ c2 |= inb_p(0x40) << 8;
+ } while (c2 - c1 < 300);
+ }
+ __setup_APIC_LVTT(clocks);
+ /* Turn off PIT interrupt if we use APIC timer as main timer.
+ Only works with the PM timer right now
+ TBD fix it for HPET too. */
+ if ((pmtmr_ioport != 0) &&
+ smp_processor_id() == boot_cpu_id &&
+ apic_runs_main_timer == 1 &&
+ !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
+ stop_timer_interrupt();
+ apic_runs_main_timer++;
+ }
+ local_irq_restore(flags);
}
/*
@@ -876,22 +835,17 @@ static void setup_APIC_timer(void)
#define TICK_COUNT 100000000
-static void __init calibrate_APIC_clock(void)
+static int __init calibrate_APIC_clock(void)
{
unsigned apic, apic_start;
unsigned long tsc, tsc_start;
int result;
-
- local_irq_disable();
-
/*
* Put whatever arbitrary (but long enough) timeout
* value into the APIC clock, we just want to get the
* counter running for calibration.
- *
- * No interrupt enable !
*/
- __setup_APIC_LVTT(250000000, 0, 0);
+ __setup_APIC_LVTT(4000000000);
apic_start = apic_read(APIC_TMCCT);
#ifdef CONFIG_X86_PM_TIMER
@@ -913,62 +867,123 @@ static void __init calibrate_APIC_clock(void)
result = (apic_start - apic) * 1000L * tsc_khz /
(tsc - tsc_start);
}
+ printk("result %d\n", result);
- local_irq_enable();
-
- printk(KERN_DEBUG "APIC timer calibration result %d\n", result);
printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
result / 1000 / 1000, result / 1000 % 1000);
- /* Calculate the scaled math multiplication factor */
- lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
- lapic_clockevent.max_delta_ns =
- clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
- lapic_clockevent.min_delta_ns =
- clockevent_delta2ns(0xF, &lapic_clockevent);
-
- calibration_result = result / HZ;
+ return result * APIC_DIVISOR / HZ;
}
+static unsigned int calibration_result;
+
void __init setup_boot_APIC_clock (void)
{
- /*
- * The local apic timer can be disabled via the kernel commandline.
- * Register the lapic timer as a dummy clock event source on SMP
- * systems, so the broadcast mechanism is used. On UP systems simply
- * ignore it.
- */
if (disable_apic_timer) {
printk(KERN_INFO "Disabling APIC timer\n");
- /* No broadcast on UP ! */
- if (num_possible_cpus() > 1)
- setup_APIC_timer();
return;
}
printk(KERN_INFO "Using local APIC timer interrupts.\n");
- calibrate_APIC_clock();
+ using_apic_timer = 1;
+
+ local_irq_disable();
+ calibration_result = calibrate_APIC_clock();
/*
- * If nmi_watchdog is set to IO_APIC, we need the
- * PIT/HPET going. Otherwise register lapic as a dummy
- * device.
+ * Now set up the timer for real.
*/
- if (nmi_watchdog != NMI_IO_APIC)
- lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
- else
- printk(KERN_WARNING "APIC timer registered as dummy,"
- " due to nmi_watchdog=1!\n");
+ setup_APIC_timer(calibration_result);
- setup_APIC_timer();
+ local_irq_enable();
}
void __cpuinit setup_secondary_APIC_clock(void)
{
- setup_APIC_timer();
+ local_irq_disable(); /* FIXME: Do we need this? --RR */
+ setup_APIC_timer(calibration_result);
+ local_irq_enable();
}
+void disable_APIC_timer(void)
+{
+ if (using_apic_timer) {
+ unsigned long v;
+
+ v = apic_read(APIC_LVTT);
+ /*
+ * When an illegal vector value (0-15) is written to an LVT
+ * entry and delivery mode is Fixed, the APIC may signal an
+ * illegal vector error, with out regard to whether the mask
+ * bit is set or whether an interrupt is actually seen on input.
+ *
+ * Boot sequence might call this function when the LVTT has
+ * '0' vector value. So make sure vector field is set to
+ * valid value.
+ */
+ v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+ apic_write(APIC_LVTT, v);
+ }
+}
+
+void enable_APIC_timer(void)
+{
+ int cpu = smp_processor_id();
+
+ if (using_apic_timer &&
+ !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
+ unsigned long v;
+
+ v = apic_read(APIC_LVTT);
+ apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
+ }
+}
+
+void switch_APIC_timer_to_ipi(void *cpumask)
+{
+ cpumask_t mask = *(cpumask_t *)cpumask;
+ int cpu = smp_processor_id();
+
+ if (cpu_isset(cpu, mask) &&
+ !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
+ disable_APIC_timer();
+ cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
+ }
+}
+EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
+
+void smp_send_timer_broadcast_ipi(void)
+{
+ int cpu = smp_processor_id();
+ cpumask_t mask;
+
+ cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
+
+ if (cpu_isset(cpu, mask)) {
+ cpu_clear(cpu, mask);
+ add_pda(apic_timer_irqs, 1);
+ smp_local_timer_interrupt();
+ }
+
+ if (!cpus_empty(mask)) {
+ send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+ }
+}
+
+void switch_ipi_to_APIC_timer(void *cpumask)
+{
+ cpumask_t mask = *(cpumask_t *)cpumask;
+ int cpu = smp_processor_id();
+
+ if (cpu_isset(cpu, mask) &&
+ cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
+ cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask);
+ enable_APIC_timer();
+ }
+}
+EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
+
int setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
@@ -982,6 +997,8 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
apic_write(reg, v);
}
+#undef APIC_DIVISOR
+
/*
* Local timer interrupt handler. It does both profiling and
* process statistics/rescheduling.
@@ -994,34 +1011,22 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
void smp_local_timer_interrupt(void)
{
- int cpu = smp_processor_id();
- struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
-
+ profile_tick(CPU_PROFILING);
+#ifdef CONFIG_SMP
+ update_process_times(user_mode(get_irq_regs()));
+#endif
+ if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
+ main_timer_handler();
/*
- * Normally we should not be here till LAPIC has been initialized but
- * in some cases like kdump, its possible that there is a pending LAPIC
- * timer interrupt from previous kernel's context and is delivered in
- * new kernel the moment interrupts are enabled.
+ * We take the 'long' return path, and there every subsystem
+ * grabs the appropriate locks (kernel lock/ irq lock).
*
- * Interrupts are enabled early and LAPIC is setup much later, hence
- * its possible that when we get here evt->event_handler is NULL.
- * Check for event_handler being NULL and discard the interrupt as
- * spurious.
- */
- if (!evt->event_handler) {
- printk(KERN_WARNING
- "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
- /* Switch it off */
- lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
- return;
- }
-
- /*
- * the NMI deadlock-detector uses this.
+ * We might want to decouple profiling from the 'long path',
+ * and do the profiling totally in assembly.
+ *
+ * Currently this isn't too much of an issue (performance wise),
+ * we can take more than 100K local irqs per second on a 100 MHz P5.
*/
- add_pda(apic_timer_irqs, 1);
-
- evt->event_handler(evt);
}
/*
@@ -1036,6 +1041,11 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
+ /*
+ * the NMI deadlock-detector uses this.
+ */
+ add_pda(apic_timer_irqs, 1);
+
/*
* NOTE! We'd better ACK the irq immediately,
* because timer handling can be slow.
@@ -1215,13 +1225,29 @@ static __init int setup_noapictimer(char *str)
disable_apic_timer = 1;
return 1;
}
-__setup("noapictimer", setup_noapictimer);
+
+static __init int setup_apicmaintimer(char *str)
+{
+ apic_runs_main_timer = 1;
+ nohpet = 1;
+ return 1;
+}
+__setup("apicmaintimer", setup_apicmaintimer);
+
+static __init int setup_noapicmaintimer(char *str)
+{
+ apic_runs_main_timer = -1;
+ return 1;
+}
+__setup("noapicmaintimer", setup_noapicmaintimer);
static __init int setup_apicpmtimer(char *s)
{
apic_calibrate_pmtmr = 1;
notsc_setup(NULL);
- return 0;
+ return setup_apicmaintimer(NULL);
}
__setup("apicpmtimer", setup_apicpmtimer);
+__setup("noapictimer", setup_noapictimer);
+
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index ffd01e5dcb52..b6434a7ef8b2 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -646,6 +646,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency =
perf->states[i].transition_latency * 1000;
}
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/trunk/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
index 32f0bda3fc95..66acd5039918 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
@@ -363,6 +363,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
policy->cur = nforce2_get(policy->cpu);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
return 0;
}
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/e_powersaver.c b/trunk/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
index c11baaf9f2b4..f43d98e11cc7 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
@@ -253,6 +253,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
f_table[k].frequency = CPUFREQ_TABLE_END;
}
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
policy->cur = fsb * current_multiplier;
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/trunk/arch/x86/kernel/cpu/cpufreq/elanfreq.c
index 1e7ae7dafcf6..f317276afa7a 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/elanfreq.c
@@ -219,6 +219,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
}
/* cpuinfo and default policy values */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = elanfreq_get_cpu_frequency(0);
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/trunk/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
index ed2bda127c44..461dabc4e495 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
@@ -420,6 +420,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
policy->min = maxfreq / POLICY_MIN_DIV;
policy->max = maxfreq;
policy->cur = curfreq;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = maxfreq / max_duration;
policy->cpuinfo.max_freq = maxfreq;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/longhaul.c b/trunk/arch/x86/kernel/cpu/cpufreq/longhaul.c
index 5045f5d583c8..f0cce3c2dc3a 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@ -710,10 +710,6 @@ static int enable_arbiter_disable(void)
reg = 0x78;
dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
NULL);
- /* Find PM133/VT8605 host bridge */
- if (dev == NULL)
- dev = pci_get_device(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_8605_0, NULL);
/* Find CLE266 host bridge */
if (dev == NULL) {
reg = 0x76;
@@ -922,6 +918,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
longhaul_setup_voltagescaling();
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 200000; /* nsec */
policy->cur = calc_speed(longhaul_get_cpu_mult());
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/trunk/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index 8eb414b906d2..4c76b511e194 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@ -229,6 +229,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
/* cpuinfo and default policy values */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* assumed */
policy->cur = stock_freq;
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
index 6d0285339317..f89524051e4a 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
@@ -160,6 +160,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
}
/* cpuinfo and default policy values */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = busfreq * max_multiplier;
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index 7decd6a50ffa..ca3e1d341889 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@ -637,6 +637,8 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
minimum_speed/1000, maximum_speed/1000);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
policy->cur = powernow_get(0);
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index b273b69cfddf..34ed53a06730 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -76,10 +76,7 @@ static u32 find_khz_freq_from_fid(u32 fid)
/* Return a frequency in MHz, given an input fid and did */
static u32 find_freq_from_fiddid(u32 fid, u32 did)
{
- if (current_cpu_data.x86 == 0x10)
- return 100 * (fid + 0x10) >> did;
- else
- return 100 * (fid + 0x8) >> did;
+ return 100 * (fid + 0x10) >> did;
}
static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
@@ -1211,6 +1208,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
/* run on any CPU again */
set_cpus_allowed(current, oldmask);
+ pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
if (cpu_family == CPU_HW_PSTATE)
pol->cpus = cpumask_of_cpu(pol->cpu);
else
@@ -1327,16 +1325,21 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
static int __cpuinit powernowk8_init(void)
{
unsigned int i, supported_cpus = 0;
+ unsigned int booted_cores = 1;
for_each_online_cpu(i) {
if (check_supported_cpu(i))
supported_cpus++;
}
+#ifdef CONFIG_SMP
+ booted_cores = cpu_data[0].booted_cores;
+#endif
+
if (supported_cpus == num_online_cpus()) {
printk(KERN_INFO PFX "Found %d %s "
"processors (%d cpu cores) (" VERSION ")\n",
- num_online_nodes(),
+ supported_cpus/booted_cores,
boot_cpu_data.x86_model_id, supported_cpus);
return cpufreq_register_driver(&cpufreq_amd64_driver);
}
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/trunk/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
index d9f3e90a7ae0..b8fb4b521c62 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
@@ -111,6 +111,7 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
return -ENODEV;
/* cpuinfo and default policy values */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = sc520_freq_get_cpu_frequency(0);
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
index 811d47438546..6c5dc2c85aeb 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -393,6 +393,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
freq = get_cur_freq(policy->cpu);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
policy->cur = freq;
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
index 36685e8f7be1..a5b2346faf1f 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
@@ -348,6 +348,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
(speed / 1000));
/* cpuinfo and default policy values */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cur = speed;
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
index f2b5a621d27b..e1c509aa3054 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
@@ -290,6 +290,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
(speed / 1000));
/* cpuinfo and default policy values */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = speed;
diff --git a/trunk/arch/x86/kernel/geode_32.c b/trunk/arch/x86/kernel/geode_32.c
index f12d8c5d9809..41e8aec4c61d 100644
--- a/trunk/arch/x86/kernel/geode_32.c
+++ b/trunk/arch/x86/kernel/geode_32.c
@@ -145,14 +145,10 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
static int __init geode_southbridge_init(void)
{
- int timers;
-
if (!is_geode())
return -ENODEV;
init_lbars();
- timers = geode_mfgpt_detect();
- printk(KERN_INFO "geode: %d MFGPT timers available.\n", timers);
return 0;
}
diff --git a/trunk/arch/x86/kernel/hpet.c b/trunk/arch/x86/kernel/hpet_32.c
similarity index 81%
rename from trunk/arch/x86/kernel/hpet.c
rename to trunk/arch/x86/kernel/hpet_32.c
index f8367074da0d..533d4932bc79 100644
--- a/trunk/arch/x86/kernel/hpet.c
+++ b/trunk/arch/x86/kernel/hpet_32.c
@@ -1,6 +1,5 @@
#include
#include
-#include
#include
#include
#include
@@ -8,11 +7,11 @@
#include
#include
-#include
#include
-#include
#include
+extern struct clock_event_device *global_clock_event;
+
#define HPET_MASK CLOCKSOURCE_MASK(32)
#define HPET_SHIFT 22
@@ -23,9 +22,9 @@
* HPET address is set in acpi/boot.c, when an ACPI entry exists
*/
unsigned long hpet_address;
-static void __iomem *hpet_virt_address;
+static void __iomem * hpet_virt_address;
-unsigned long hpet_readl(unsigned long a)
+static inline unsigned long hpet_readl(unsigned long a)
{
return readl(hpet_virt_address + a);
}
@@ -35,36 +34,6 @@ static inline void hpet_writel(unsigned long d, unsigned long a)
writel(d, hpet_virt_address + a);
}
-#ifdef CONFIG_X86_64
-
-#include
-
-static inline void hpet_set_mapping(void)
-{
- set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
- __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
- hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
-}
-
-static inline void hpet_clear_mapping(void)
-{
- hpet_virt_address = NULL;
-}
-
-#else
-
-static inline void hpet_set_mapping(void)
-{
- hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
-}
-
-static inline void hpet_clear_mapping(void)
-{
- iounmap(hpet_virt_address);
- hpet_virt_address = NULL;
-}
-#endif
-
/*
* HPET command line enable / disable
*/
@@ -80,13 +49,6 @@ static int __init hpet_setup(char* str)
}
__setup("hpet=", hpet_setup);
-static int __init disable_hpet(char *str)
-{
- boot_hpet_disable = 1;
- return 1;
-}
-__setup("nohpet", disable_hpet);
-
static inline int is_hpet_capable(void)
{
return (!boot_hpet_disable && hpet_address);
@@ -121,7 +83,7 @@ static void hpet_reserve_platform_timers(unsigned long id)
memset(&hd, 0, sizeof (hd));
hd.hd_phys_address = hpet_address;
- hd.hd_address = hpet;
+ hd.hd_address = hpet_virt_address;
hd.hd_nirqs = nrtimers;
hd.hd_flags = HPET_DATA_PLATFORM;
hpet_reserve_timer(&hd, 0);
@@ -149,9 +111,9 @@ static void hpet_reserve_platform_timers(unsigned long id) { }
*/
static unsigned long hpet_period;
-static void hpet_legacy_set_mode(enum clock_event_mode mode,
+static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt);
-static int hpet_legacy_next_event(unsigned long delta,
+static int hpet_next_event(unsigned long delta,
struct clock_event_device *evt);
/*
@@ -160,11 +122,10 @@ static int hpet_legacy_next_event(unsigned long delta,
static struct clock_event_device hpet_clockevent = {
.name = "hpet",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = hpet_legacy_set_mode,
- .set_next_event = hpet_legacy_next_event,
+ .set_mode = hpet_set_mode,
+ .set_next_event = hpet_next_event,
.shift = 32,
.irq = 0,
- .rating = 50,
};
static void hpet_start_counter(void)
@@ -179,18 +140,7 @@ static void hpet_start_counter(void)
hpet_writel(cfg, HPET_CFG);
}
-static void hpet_resume_device(void)
-{
- force_hpet_resume();
-}
-
-static void hpet_restart_counter(void)
-{
- hpet_resume_device();
- hpet_start_counter();
-}
-
-static void hpet_enable_legacy_int(void)
+static void hpet_enable_int(void)
{
unsigned long cfg = hpet_readl(HPET_CFG);
@@ -199,39 +149,7 @@ static void hpet_enable_legacy_int(void)
hpet_legacy_int_enabled = 1;
}
-static void hpet_legacy_clockevent_register(void)
-{
- uint64_t hpet_freq;
-
- /* Start HPET legacy interrupts */
- hpet_enable_legacy_int();
-
- /*
- * The period is a femto seconds value. We need to calculate the
- * scaled math multiplication factor for nanosecond to hpet tick
- * conversion.
- */
- hpet_freq = 1000000000000000ULL;
- do_div(hpet_freq, hpet_period);
- hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
- NSEC_PER_SEC, 32);
- /* Calculate the min / max delta */
- hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
- &hpet_clockevent);
- hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
- &hpet_clockevent);
-
- /*
- * Start hpet with the boot cpu mask and make it
- * global after the IO_APIC has been initialized.
- */
- hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
- clockevents_register_device(&hpet_clockevent);
- global_clock_event = &hpet_clockevent;
- printk(KERN_DEBUG "hpet clockevent registered\n");
-}
-
-static void hpet_legacy_set_mode(enum clock_event_mode mode,
+static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
unsigned long cfg, cmp, now;
@@ -272,12 +190,12 @@ static void hpet_legacy_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_RESUME:
- hpet_enable_legacy_int();
+ hpet_enable_int();
break;
}
}
-static int hpet_legacy_next_event(unsigned long delta,
+static int hpet_next_event(unsigned long delta,
struct clock_event_device *evt)
{
unsigned long cnt;
@@ -297,13 +215,6 @@ static cycle_t read_hpet(void)
return (cycle_t)hpet_readl(HPET_COUNTER);
}
-#ifdef CONFIG_X86_64
-static cycle_t __vsyscall_fn vread_hpet(void)
-{
- return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
-}
-#endif
-
static struct clocksource clocksource_hpet = {
.name = "hpet",
.rating = 250,
@@ -311,17 +222,61 @@ static struct clocksource clocksource_hpet = {
.mask = HPET_MASK,
.shift = HPET_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .resume = hpet_restart_counter,
-#ifdef CONFIG_X86_64
- .vread = vread_hpet,
-#endif
+ .resume = hpet_start_counter,
};
-static int hpet_clocksource_register(void)
+/*
+ * Try to setup the HPET timer
+ */
+int __init hpet_enable(void)
{
+ unsigned long id;
+ uint64_t hpet_freq;
u64 tmp, start, now;
cycle_t t1;
+ if (!is_hpet_capable())
+ return 0;
+
+ hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+
+ /*
+ * Read the period and check for a sane value:
+ */
+ hpet_period = hpet_readl(HPET_PERIOD);
+ if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
+ goto out_nohpet;
+
+ /*
+ * The period is a femto seconds value. We need to calculate the
+ * scaled math multiplication factor for nanosecond to hpet tick
+ * conversion.
+ */
+ hpet_freq = 1000000000000000ULL;
+ do_div(hpet_freq, hpet_period);
+ hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+ NSEC_PER_SEC, 32);
+ /* Calculate the min / max delta */
+ hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+ &hpet_clockevent);
+ hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+ &hpet_clockevent);
+
+ /*
+ * Read the HPET ID register to retrieve the IRQ routing
+ * information and the number of channels
+ */
+ id = hpet_readl(HPET_ID);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+ /*
+ * The legacy routing mode needs at least two channels, tick timer
+ * and the rtc emulation channel.
+ */
+ if (!(id & HPET_ID_NUMBER))
+ goto out_nohpet;
+#endif
+
/* Start the counter */
hpet_start_counter();
@@ -343,7 +298,7 @@ static int hpet_clocksource_register(void)
if (t1 == read_hpet()) {
printk(KERN_WARNING
"HPET counter not counting. HPET disabled\n");
- return -ENODEV;
+ goto out_nohpet;
}
/* Initialize and register HPET clocksource
@@ -364,84 +319,27 @@ static int hpet_clocksource_register(void)
clocksource_register(&clocksource_hpet);
- return 0;
-}
-
-/*
- * Try to setup the HPET timer
- */
-int __init hpet_enable(void)
-{
- unsigned long id;
-
- if (!is_hpet_capable())
- return 0;
-
- hpet_set_mapping();
-
- /*
- * Read the period and check for a sane value:
- */
- hpet_period = hpet_readl(HPET_PERIOD);
- if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
- goto out_nohpet;
-
- /*
- * Read the HPET ID register to retrieve the IRQ routing
- * information and the number of channels
- */
- id = hpet_readl(HPET_ID);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
- /*
- * The legacy routing mode needs at least two channels, tick timer
- * and the rtc emulation channel.
- */
- if (!(id & HPET_ID_NUMBER))
- goto out_nohpet;
-#endif
-
- if (hpet_clocksource_register())
- goto out_nohpet;
-
if (id & HPET_ID_LEGSUP) {
- hpet_legacy_clockevent_register();
+ hpet_enable_int();
+ hpet_reserve_platform_timers(id);
+ /*
+ * Start hpet with the boot cpu mask and make it
+ * global after the IO_APIC has been initialized.
+ */
+ hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+ clockevents_register_device(&hpet_clockevent);
+ global_clock_event = &hpet_clockevent;
return 1;
}
return 0;
out_nohpet:
- hpet_clear_mapping();
+ iounmap(hpet_virt_address);
+ hpet_virt_address = NULL;
boot_hpet_disable = 1;
return 0;
}
-/*
- * Needs to be late, as the reserve_timer code calls kalloc !
- *
- * Not a problem on i386 as hpet_enable is called from late_time_init,
- * but on x86_64 it is necessary !
- */
-static __init int hpet_late_init(void)
-{
- if (boot_hpet_disable)
- return -ENODEV;
-
- if (!hpet_address) {
- if (!force_hpet_address)
- return -ENODEV;
-
- hpet_address = force_hpet_address;
- hpet_enable();
- if (!hpet_virt_address)
- return -ENODEV;
- }
-
- hpet_reserve_platform_timers(hpet_readl(HPET_ID));
-
- return 0;
-}
-fs_initcall(hpet_late_init);
#ifdef CONFIG_HPET_EMULATE_RTC
diff --git a/trunk/arch/x86/kernel/hpet_64.c b/trunk/arch/x86/kernel/hpet_64.c
new file mode 100644
index 000000000000..e2d1b912e154
--- /dev/null
+++ b/trunk/arch/x86/kernel/hpet_64.c
@@ -0,0 +1,493 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define HPET_MASK 0xFFFFFFFF
+#define HPET_SHIFT 22
+
+/* FSEC = 10^-15 NSEC = 10^-9 */
+#define FSEC_PER_NSEC 1000000
+
+int nohpet __initdata;
+
+unsigned long hpet_address;
+unsigned long hpet_period; /* fsecs / HPET clock */
+unsigned long hpet_tick; /* HPET clocks / interrupt */
+
+int hpet_use_timer; /* Use counter of hpet for time keeping,
+ * otherwise PIT
+ */
+
+#ifdef CONFIG_HPET
+static __init int late_hpet_init(void)
+{
+ struct hpet_data hd;
+ unsigned int ntimer;
+
+ if (!hpet_address)
+ return 0;
+
+ memset(&hd, 0, sizeof(hd));
+
+ ntimer = hpet_readl(HPET_ID);
+ ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+ ntimer++;
+
+ /*
+ * Register with driver.
+ * Timer0 and Timer1 is used by platform.
+ */
+ hd.hd_phys_address = hpet_address;
+ hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
+ hd.hd_nirqs = ntimer;
+ hd.hd_flags = HPET_DATA_PLATFORM;
+ hpet_reserve_timer(&hd, 0);
+#ifdef CONFIG_HPET_EMULATE_RTC
+ hpet_reserve_timer(&hd, 1);
+#endif
+ hd.hd_irq[0] = HPET_LEGACY_8254;
+ hd.hd_irq[1] = HPET_LEGACY_RTC;
+ if (ntimer > 2) {
+ struct hpet *hpet;
+ struct hpet_timer *timer;
+ int i;
+
+ hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);
+ timer = &hpet->hpet_timers[2];
+ for (i = 2; i < ntimer; timer++, i++)
+ hd.hd_irq[i] = (timer->hpet_config &
+ Tn_INT_ROUTE_CNF_MASK) >>
+ Tn_INT_ROUTE_CNF_SHIFT;
+
+ }
+
+ hpet_alloc(&hd);
+ return 0;
+}
+fs_initcall(late_hpet_init);
+#endif
+
+int hpet_timer_stop_set_go(unsigned long tick)
+{
+ unsigned int cfg;
+
+/*
+ * Stop the timers and reset the main counter.
+ */
+
+ cfg = hpet_readl(HPET_CFG);
+ cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
+ hpet_writel(cfg, HPET_CFG);
+ hpet_writel(0, HPET_COUNTER);
+ hpet_writel(0, HPET_COUNTER + 4);
+
+/*
+ * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
+ * and period also hpet_tick.
+ */
+ if (hpet_use_timer) {
+ hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
+ HPET_TN_32BIT, HPET_T0_CFG);
+ hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
+ hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
+ cfg |= HPET_CFG_LEGACY;
+ }
+/*
+ * Go!
+ */
+
+ cfg |= HPET_CFG_ENABLE;
+ hpet_writel(cfg, HPET_CFG);
+
+ return 0;
+}
+
+static cycle_t read_hpet(void)
+{
+ return (cycle_t)hpet_readl(HPET_COUNTER);
+}
+
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+ return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+
+struct clocksource clocksource_hpet = {
+ .name = "hpet",
+ .rating = 250,
+ .read = read_hpet,
+ .mask = (cycle_t)HPET_MASK,
+ .mult = 0, /* set below */
+ .shift = HPET_SHIFT,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .vread = vread_hpet,
+};
+
+int __init hpet_arch_init(void)
+{
+ unsigned int id;
+ u64 tmp;
+
+ if (!hpet_address)
+ return -1;
+ set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
+ __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
+
+/*
+ * Read the period, compute tick and quotient.
+ */
+
+ id = hpet_readl(HPET_ID);
+
+ if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
+ return -1;
+
+ hpet_period = hpet_readl(HPET_PERIOD);
+ if (hpet_period < 100000 || hpet_period > 100000000)
+ return -1;
+
+ hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
+
+ hpet_use_timer = (id & HPET_ID_LEGSUP);
+
+ /*
+ * hpet period is in femto seconds per cycle
+ * so we need to convert this to ns/cyc units
+ * aproximated by mult/2^shift
+ *
+ * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
+ * fsec/cyc * 1ns/1000000fsec * 2^shift = mult
+ * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
+ * (fsec/cyc << shift)/1000000 = mult
+ * (hpet_period << shift)/FSEC_PER_NSEC = mult
+ */
+ tmp = (u64)hpet_period << HPET_SHIFT;
+ do_div(tmp, FSEC_PER_NSEC);
+ clocksource_hpet.mult = (u32)tmp;
+ clocksource_register(&clocksource_hpet);
+
+ return hpet_timer_stop_set_go(hpet_tick);
+}
+
+int hpet_reenable(void)
+{
+ return hpet_timer_stop_set_go(hpet_tick);
+}
+
+/*
+ * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
+ * it to the HPET timer of known frequency.
+ */
+
+#define TICK_COUNT 100000000
+#define SMI_THRESHOLD 50000
+#define MAX_TRIES 5
+
+/*
+ * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
+ * occurs between the reads of the hpet & TSC.
+ */
+static void __init read_hpet_tsc(int *hpet, int *tsc)
+{
+ int tsc1, tsc2, hpet1, i;
+
+ for (i = 0; i < MAX_TRIES; i++) {
+ tsc1 = get_cycles_sync();
+ hpet1 = hpet_readl(HPET_COUNTER);
+ tsc2 = get_cycles_sync();
+ if ((tsc2 - tsc1) < SMI_THRESHOLD)
+ break;
+ }
+ *hpet = hpet1;
+ *tsc = tsc2;
+}
+
+unsigned int __init hpet_calibrate_tsc(void)
+{
+ int tsc_start, hpet_start;
+ int tsc_now, hpet_now;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ read_hpet_tsc(&hpet_start, &tsc_start);
+
+ do {
+ local_irq_disable();
+ read_hpet_tsc(&hpet_now, &tsc_now);
+ local_irq_restore(flags);
+ } while ((tsc_now - tsc_start) < TICK_COUNT &&
+ (hpet_now - hpet_start) < TICK_COUNT);
+
+ return (tsc_now - tsc_start) * 1000000000L
+ / ((hpet_now - hpet_start) * hpet_period / 1000);
+}
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
+ * is enabled, we support RTC interrupt functionality in software.
+ * RTC has 3 kinds of interrupts:
+ * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
+ * is updated
+ * 2) Alarm Interrupt - generate an interrupt at a specific time of day
+ * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
+ * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
+ * (1) and (2) above are implemented using polling at a frequency of
+ * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
+ * overhead. (DEFAULT_RTC_INT_FREQ)
+ * For (3), we use interrupts at 64Hz or user specified periodic
+ * frequency, whichever is higher.
+ */
+#include
+
+#define DEFAULT_RTC_INT_FREQ 64
+#define RTC_NUM_INTS 1
+
+static unsigned long UIE_on;
+static unsigned long prev_update_sec;
+
+static unsigned long AIE_on;
+static struct rtc_time alarm_time;
+
+static unsigned long PIE_on;
+static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
+static unsigned long PIE_count;
+
+static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
+static unsigned int hpet_t1_cmp; /* cached comparator register */
+
+int is_hpet_enabled(void)
+{
+ return hpet_address != 0;
+}
+
+/*
+ * Timer 1 for RTC, we do not use periodic interrupt feature,
+ * even if HPET supports periodic interrupts on Timer 1.
+ * The reason being, to set up a periodic interrupt in HPET, we need to
+ * stop the main counter. And if we do that everytime someone diables/enables
+ * RTC, we will have adverse effect on main kernel timer running on Timer 0.
+ * So, for the time being, simulate the periodic interrupt in software.
+ *
+ * hpet_rtc_timer_init() is called for the first time and during subsequent
+ * interuppts reinit happens through hpet_rtc_timer_reinit().
+ */
+int hpet_rtc_timer_init(void)
+{
+ unsigned int cfg, cnt;
+ unsigned long flags;
+
+ if (!is_hpet_enabled())
+ return 0;
+ /*
+ * Set the counter 1 and enable the interrupts.
+ */
+ if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
+ hpet_rtc_int_freq = PIE_freq;
+ else
+ hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+ local_irq_save(flags);
+
+ cnt = hpet_readl(HPET_COUNTER);
+ cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
+ hpet_writel(cnt, HPET_T1_CMP);
+ hpet_t1_cmp = cnt;
+
+ cfg = hpet_readl(HPET_T1_CFG);
+ cfg &= ~HPET_TN_PERIODIC;
+ cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+ hpet_writel(cfg, HPET_T1_CFG);
+
+ local_irq_restore(flags);
+
+ return 1;
+}
+
+static void hpet_rtc_timer_reinit(void)
+{
+ unsigned int cfg, cnt, ticks_per_int, lost_ints;
+
+ if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
+ cfg = hpet_readl(HPET_T1_CFG);
+ cfg &= ~HPET_TN_ENABLE;
+ hpet_writel(cfg, HPET_T1_CFG);
+ return;
+ }
+
+ if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
+ hpet_rtc_int_freq = PIE_freq;
+ else
+ hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+ /* It is more accurate to use the comparator value than current count.*/
+ ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
+ hpet_t1_cmp += ticks_per_int;
+ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
+
+ /*
+ * If the interrupt handler was delayed too long, the write above tries
+ * to schedule the next interrupt in the past and the hardware would
+ * not interrupt until the counter had wrapped around.
+ * So we have to check that the comparator wasn't set to a past time.
+ */
+ cnt = hpet_readl(HPET_COUNTER);
+ if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
+ lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
+ /* Make sure that, even with the time needed to execute
+ * this code, the next scheduled interrupt has been moved
+ * back to the future: */
+ lost_ints++;
+
+ hpet_t1_cmp += lost_ints * ticks_per_int;
+ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
+
+ if (PIE_on)
+ PIE_count += lost_ints;
+
+ if (printk_ratelimit())
+ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
+ hpet_rtc_int_freq);
+ }
+}
+
+/*
+ * The functions below are called from rtc driver.
+ * Return 0 if HPET is not being used.
+ * Otherwise do the necessary changes and return 1.
+ */
+int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
+{
+ if (!is_hpet_enabled())
+ return 0;
+
+ if (bit_mask & RTC_UIE)
+ UIE_on = 0;
+ if (bit_mask & RTC_PIE)
+ PIE_on = 0;
+ if (bit_mask & RTC_AIE)
+ AIE_on = 0;
+
+ return 1;
+}
+
+int hpet_set_rtc_irq_bit(unsigned long bit_mask)
+{
+ int timer_init_reqd = 0;
+
+ if (!is_hpet_enabled())
+ return 0;
+
+ if (!(PIE_on | AIE_on | UIE_on))
+ timer_init_reqd = 1;
+
+ if (bit_mask & RTC_UIE) {
+ UIE_on = 1;
+ }
+ if (bit_mask & RTC_PIE) {
+ PIE_on = 1;
+ PIE_count = 0;
+ }
+ if (bit_mask & RTC_AIE) {
+ AIE_on = 1;
+ }
+
+ if (timer_init_reqd)
+ hpet_rtc_timer_init();
+
+ return 1;
+}
+
+int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
+{
+ if (!is_hpet_enabled())
+ return 0;
+
+ alarm_time.tm_hour = hrs;
+ alarm_time.tm_min = min;
+ alarm_time.tm_sec = sec;
+
+ return 1;
+}
+
+int hpet_set_periodic_freq(unsigned long freq)
+{
+ if (!is_hpet_enabled())
+ return 0;
+
+ PIE_freq = freq;
+ PIE_count = 0;
+
+ return 1;
+}
+
+int hpet_rtc_dropped_irq(void)
+{
+ if (!is_hpet_enabled())
+ return 0;
+
+ return 1;
+}
+
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
+{
+ struct rtc_time curr_time;
+ unsigned long rtc_int_flag = 0;
+ int call_rtc_interrupt = 0;
+
+ hpet_rtc_timer_reinit();
+
+ if (UIE_on | AIE_on) {
+ rtc_get_rtc_time(&curr_time);
+ }
+ if (UIE_on) {
+ if (curr_time.tm_sec != prev_update_sec) {
+ /* Set update int info, call real rtc int routine */
+ call_rtc_interrupt = 1;
+ rtc_int_flag = RTC_UF;
+ prev_update_sec = curr_time.tm_sec;
+ }
+ }
+ if (PIE_on) {
+ PIE_count++;
+ if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
+ /* Set periodic int info, call real rtc int routine */
+ call_rtc_interrupt = 1;
+ rtc_int_flag |= RTC_PF;
+ PIE_count = 0;
+ }
+ }
+ if (AIE_on) {
+ if ((curr_time.tm_sec == alarm_time.tm_sec) &&
+ (curr_time.tm_min == alarm_time.tm_min) &&
+ (curr_time.tm_hour == alarm_time.tm_hour)) {
+ /* Set alarm int info, call real rtc int routine */
+ call_rtc_interrupt = 1;
+ rtc_int_flag |= RTC_AF;
+ }
+ }
+ if (call_rtc_interrupt) {
+ rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
+ rtc_interrupt(rtc_int_flag, dev_id);
+ }
+ return IRQ_HANDLED;
+}
+#endif
+
+static int __init nohpet_setup(char *s)
+{
+ nohpet = 1;
+ return 1;
+}
+
+__setup("nohpet", nohpet_setup);
diff --git a/trunk/arch/x86/kernel/i8253.c b/trunk/arch/x86/kernel/i8253_32.c
similarity index 99%
rename from trunk/arch/x86/kernel/i8253.c
rename to trunk/arch/x86/kernel/i8253_32.c
index ac15e4cbd9c1..6d839f2f1b1a 100644
--- a/trunk/arch/x86/kernel/i8253.c
+++ b/trunk/arch/x86/kernel/i8253_32.c
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
@@ -119,7 +120,6 @@ void __init setup_pit_timer(void)
global_clock_event = &pit_clockevent;
}
-#ifndef CONFIG_X86_64
/*
* Since the PIT overflows every tick, its not very useful
* to just read by itself. So use jiffies to emulate a free
@@ -204,5 +204,3 @@ static int __init init_pit_clocksource(void)
return clocksource_register(&clocksource_pit);
}
arch_initcall(init_pit_clocksource);
-
-#endif
diff --git a/trunk/arch/x86/kernel/i8259_32.c b/trunk/arch/x86/kernel/i8259_32.c
index 679bb33acbf1..0499cbe9871a 100644
--- a/trunk/arch/x86/kernel/i8259_32.c
+++ b/trunk/arch/x86/kernel/i8259_32.c
@@ -10,6 +10,7 @@
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/x86/kernel/i8259_64.c b/trunk/arch/x86/kernel/i8259_64.c
index eb72976cc13c..948cae646099 100644
--- a/trunk/arch/x86/kernel/i8259_64.c
+++ b/trunk/arch/x86/kernel/i8259_64.c
@@ -444,6 +444,46 @@ void __init init_ISA_irqs (void)
}
}
+static void setup_timer_hardware(void)
+{
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ udelay(10);
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ udelay(10);
+ outb(LATCH >> 8 , 0x40); /* MSB */
+}
+
+static int timer_resume(struct sys_device *dev)
+{
+ setup_timer_hardware();
+ return 0;
+}
+
+void i8254_timer_resume(void)
+{
+ setup_timer_hardware();
+}
+
+static struct sysdev_class timer_sysclass = {
+ set_kset_name("timer_pit"),
+ .resume = timer_resume,
+};
+
+static struct sys_device device_timer = {
+ .id = 0,
+ .cls = &timer_sysclass,
+};
+
+static int __init init_timer_sysfs(void)
+{
+ int error = sysdev_class_register(&timer_sysclass);
+ if (!error)
+ error = sysdev_register(&device_timer);
+ return error;
+}
+
+device_initcall(init_timer_sysfs);
+
void __init init_IRQ(void)
{
int i;
@@ -493,6 +533,12 @@ void __init init_IRQ(void)
set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+ /*
+ * Set the clock to HZ Hz, we already have a valid
+ * vector now:
+ */
+ setup_timer_hardware();
+
if (!acpi_ioapic)
setup_irq(2, &irq2);
}
diff --git a/trunk/arch/x86/kernel/mfgpt_32.c b/trunk/arch/x86/kernel/mfgpt_32.c
deleted file mode 100644
index 0ab680f2d9db..000000000000
--- a/trunk/arch/x86/kernel/mfgpt_32.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
- *
- * Copyright (C) 2006, Advanced Micro Devices, Inc.
- * Copyright (C) 2007, Andres Salomon
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- *
- * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
- */
-
-/*
- * We are using the 32Khz input clock - its the only one that has the
- * ranges we find desirable. The following table lists the suitable
- * divisors and the associated hz, minimum interval
- * and the maximum interval:
- *
- * Divisor Hz Min Delta (S) Max Delta (S)
- * 1 32000 .0005 2.048
- * 2 16000 .001 4.096
- * 4 8000 .002 8.192
- * 8 4000 .004 16.384
- * 16 2000 .008 32.768
- * 32 1000 .016 65.536
- * 64 500 .032 131.072
- * 128 250 .064 262.144
- * 256 125 .128 524.288
- */
-
-#include
-#include
-#include
-#include
-
-#define F_AVAIL 0x01
-
-static struct mfgpt_timer_t {
- int flags;
- struct module *owner;
-} mfgpt_timers[MFGPT_MAX_TIMERS];
-
-/* Selected from the table above */
-
-#define MFGPT_DIVISOR 16
-#define MFGPT_SCALE 4 /* divisor = 2^(scale) */
-#define MFGPT_HZ (32000 / MFGPT_DIVISOR)
-#define MFGPT_PERIODIC (MFGPT_HZ / HZ)
-
-#ifdef CONFIG_GEODE_MFGPT_TIMER
-static int __init mfgpt_timer_setup(void);
-#else
-#define mfgpt_timer_setup() (0)
-#endif
-
-/* Allow for disabling of MFGPTs */
-static int disable;
-static int __init mfgpt_disable(char *s)
-{
- disable = 1;
- return 1;
-}
-__setup("nomfgpt", mfgpt_disable);
-
-/*
- * Check whether any MFGPTs are available for the kernel to use. In most
- * cases, firmware that uses AMD's VSA code will claim all timers during
- * bootup; we certainly don't want to take them if they're already in use.
- * In other cases (such as with VSAless OpenFirmware), the system firmware
- * leaves timers available for us to use.
- */
-int __init geode_mfgpt_detect(void)
-{
- int count = 0, i;
- u16 val;
-
- if (disable) {
- printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n");
- return 0;
- }
-
- for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
- val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
- if (!(val & MFGPT_SETUP_SETUP)) {
- mfgpt_timers[i].flags = F_AVAIL;
- count++;
- }
- }
-
- /* set up clock event device, if desired */
- i = mfgpt_timer_setup();
-
- return count;
-}
-
-int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
-{
- u32 msr, mask, value, dummy;
- int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
-
- if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
- return -EIO;
-
- /*
- * The register maps for these are described in sections 6.17.1.x of
- * the AMD Geode CS5536 Companion Device Data Book.
- */
- switch (event) {
- case MFGPT_EVENT_RESET:
- /*
- * XXX: According to the docs, we cannot reset timers above
- * 6; that is, resets for 7 and 8 will be ignored. Is this
- * a problem? -dilinger
- */
- msr = MFGPT_NR_MSR;
- mask = 1 << (timer + 24);
- break;
-
- case MFGPT_EVENT_NMI:
- msr = MFGPT_NR_MSR;
- mask = 1 << (timer + shift);
- break;
-
- case MFGPT_EVENT_IRQ:
- msr = MFGPT_IRQ_MSR;
- mask = 1 << (timer + shift);
- break;
-
- default:
- return -EIO;
- }
-
- rdmsr(msr, value, dummy);
-
- if (enable)
- value |= mask;
- else
- value &= ~mask;
-
- wrmsr(msr, value, dummy);
- return 0;
-}
-
-int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable)
-{
- u32 val, dummy;
- int offset;
-
- if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
- return -EIO;
-
- if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
- return -EIO;
-
- rdmsr(MSR_PIC_ZSEL_LOW, val, dummy);
-
- offset = (timer % 4) * 4;
-
- val &= ~((0xF << offset) | (0xF << (offset + 16)));
-
- if (enable) {
- val |= (irq & 0x0F) << (offset);
- val |= (irq & 0x0F) << (offset + 16);
- }
-
- wrmsr(MSR_PIC_ZSEL_LOW, val, dummy);
- return 0;
-}
-
-static int mfgpt_get(int timer, struct module *owner)
-{
- mfgpt_timers[timer].flags &= ~F_AVAIL;
- mfgpt_timers[timer].owner = owner;
- printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer);
- return timer;
-}
-
-int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
-{
- int i;
-
- if (!geode_get_dev_base(GEODE_DEV_MFGPT))
- return -ENODEV;
- if (timer >= MFGPT_MAX_TIMERS)
- return -EIO;
-
- if (timer < 0) {
- /* Try to find an available timer */
- for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
- if (mfgpt_timers[i].flags & F_AVAIL)
- return mfgpt_get(i, owner);
-
- if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
- break;
- }
- } else {
- /* If they requested a specific timer, try to honor that */
- if (mfgpt_timers[timer].flags & F_AVAIL)
- return mfgpt_get(timer, owner);
- }
-
- /* No timers available - too bad */
- return -1;
-}
-
-
-#ifdef CONFIG_GEODE_MFGPT_TIMER
-
-/*
- * The MFPGT timers on the CS5536 provide us with suitable timers to use
- * as clock event sources - not as good as a HPET or APIC, but certainly
- * better then the PIT. This isn't a general purpose MFGPT driver, but
- * a simplified one designed specifically to act as a clock event source.
- * For full details about the MFGPT, please consult the CS5536 data sheet.
- */
-
-#include
-#include
-
-static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN;
-static u16 mfgpt_event_clock;
-
-static int irq = 7;
-static int __init mfgpt_setup(char *str)
-{
- get_option(&str, &irq);
- return 1;
-}
-__setup("mfgpt_irq=", mfgpt_setup);
-
-static inline void mfgpt_disable_timer(u16 clock)
-{
- u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP);
- geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN);
-}
-
-static int mfgpt_next_event(unsigned long, struct clock_event_device *);
-static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *);
-
-static struct clock_event_device mfgpt_clockevent = {
- .name = "mfgpt-timer",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = mfgpt_set_mode,
- .set_next_event = mfgpt_next_event,
- .rating = 250,
- .cpumask = CPU_MASK_ALL,
- .shift = 32
-};
-
-static inline void mfgpt_start_timer(u16 clock, u16 delta)
-{
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta);
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
-
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
- MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
-}
-
-static void mfgpt_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- mfgpt_disable_timer(mfgpt_event_clock);
-
- if (mode == CLOCK_EVT_MODE_PERIODIC)
- mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC);
-
- mfgpt_tick_mode = mode;
-}
-
-static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
-{
- mfgpt_start_timer(mfgpt_event_clock, delta);
- return 0;
-}
-
-/* Assume (foolishly?), that this interrupt was due to our tick */
-
-static irqreturn_t mfgpt_tick(int irq, void *dev_id)
-{
- if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
- return IRQ_HANDLED;
-
- /* Turn off the clock */
- mfgpt_disable_timer(mfgpt_event_clock);
-
- /* Clear the counter */
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
-
- /* Restart the clock in periodic mode */
-
- if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) {
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
- MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
- }
-
- mfgpt_clockevent.event_handler(&mfgpt_clockevent);
- return IRQ_HANDLED;
-}
-
-static struct irqaction mfgptirq = {
- .handler = mfgpt_tick,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING,
- .mask = CPU_MASK_NONE,
- .name = "mfgpt-timer"
-};
-
-static int __init mfgpt_timer_setup(void)
-{
- int timer, ret;
- u16 val;
-
- timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING,
- THIS_MODULE);
- if (timer < 0) {
- printk(KERN_ERR
- "mfgpt-timer: Could not allocate a MFPGT timer\n");
- return -ENODEV;
- }
-
- mfgpt_event_clock = timer;
- /* Set the clock scale and enable the event mode for CMP2 */
- val = MFGPT_SCALE | (3 << 8);
-
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
-
- /* Set up the IRQ on the MFGPT side */
- if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
- printk(KERN_ERR "mfgpt-timer: Could not set up IRQ %d\n", irq);
- return -EIO;
- }
-
- /* And register it with the kernel */
- ret = setup_irq(irq, &mfgptirq);
-
- if (ret) {
- printk(KERN_ERR
- "mfgpt-timer: Unable to set up the interrupt.\n");
- goto err;
- }
-
- /* Set up the clock event */
- mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
- mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
- &mfgpt_clockevent);
- mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
- &mfgpt_clockevent);
-
- printk(KERN_INFO
- "mfgpt-timer: registering the MFGT timer as a clock event.\n");
- clockevents_register_device(&mfgpt_clockevent);
-
- return 0;
-
-err:
- geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
- printk(KERN_ERR
- "mfgpt-timer: Unable to set up the MFGPT clock source\n");
- return -EIO;
-}
-
-#endif
diff --git a/trunk/arch/x86/kernel/nmi_32.c b/trunk/arch/x86/kernel/nmi_32.c
index 95d3fc203cf7..c7227e2180f8 100644
--- a/trunk/arch/x86/kernel/nmi_32.c
+++ b/trunk/arch/x86/kernel/nmi_32.c
@@ -353,8 +353,7 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
* Take the local apic timer and PIT/HPET into account. We don't
* know which one is active, when we have highres/dyntick on
*/
- sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
- per_cpu(irq_stat, cpu).irq0_irqs;
+ sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
/* if the none of the timers isn't firing, this cpu isn't doing much */
if (!touched && last_irq_sums[cpu] == sum) {
diff --git a/trunk/arch/x86/kernel/nmi_64.c b/trunk/arch/x86/kernel/nmi_64.c
index e60ac0da5283..0ec6d2ddb931 100644
--- a/trunk/arch/x86/kernel/nmi_64.c
+++ b/trunk/arch/x86/kernel/nmi_64.c
@@ -329,7 +329,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
touched = 1;
}
- sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
+ sum = read_pda(apic_timer_irqs);
if (__get_cpu_var(nmi_touch)) {
__get_cpu_var(nmi_touch) = 0;
touched = 1;
diff --git a/trunk/arch/x86/kernel/process_64.c b/trunk/arch/x86/kernel/process_64.c
index 6f9dbbe65eef..98956555450b 100644
--- a/trunk/arch/x86/kernel/process_64.c
+++ b/trunk/arch/x86/kernel/process_64.c
@@ -38,7 +38,6 @@
#include
#include
#include
-#include
#include
#include
@@ -209,8 +208,6 @@ void cpu_idle (void)
if (__get_cpu_var(cpu_idle_state))
__get_cpu_var(cpu_idle_state) = 0;
- tick_nohz_stop_sched_tick();
-
rmb();
idle = pm_idle;
if (!idle)
@@ -231,7 +228,6 @@ void cpu_idle (void)
__exit_idle();
}
- tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/trunk/arch/x86/kernel/quirks.c b/trunk/arch/x86/kernel/quirks.c
index d769e204f942..6722469c2633 100644
--- a/trunk/arch/x86/kernel/quirks.c
+++ b/trunk/arch/x86/kernel/quirks.c
@@ -4,8 +4,6 @@
#include
#include
-#include
-
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
@@ -49,206 +47,3 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quir
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
#endif
-
-#if defined(CONFIG_HPET_TIMER)
-unsigned long force_hpet_address;
-
-static enum {
- NONE_FORCE_HPET_RESUME,
- OLD_ICH_FORCE_HPET_RESUME,
- ICH_FORCE_HPET_RESUME
-} force_hpet_resume_type;
-
-static void __iomem *rcba_base;
-
-static void ich_force_hpet_resume(void)
-{
- u32 val;
-
- if (!force_hpet_address)
- return;
-
- if (rcba_base == NULL)
- BUG();
-
- /* read the Function Disable register, dword mode only */
- val = readl(rcba_base + 0x3404);
- if (!(val & 0x80)) {
- /* HPET disabled in HPTC. Trying to enable */
- writel(val | 0x80, rcba_base + 0x3404);
- }
-
- val = readl(rcba_base + 0x3404);
- if (!(val & 0x80))
- BUG();
- else
- printk(KERN_DEBUG "Force enabled HPET at resume\n");
-
- return;
-}
-
-static void ich_force_enable_hpet(struct pci_dev *dev)
-{
- u32 val;
- u32 uninitialized_var(rcba);
- int err = 0;
-
- if (hpet_address || force_hpet_address)
- return;
-
- pci_read_config_dword(dev, 0xF0, &rcba);
- rcba &= 0xFFFFC000;
- if (rcba == 0) {
- printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
- return;
- }
-
- /* use bits 31:14, 16 kB aligned */
- rcba_base = ioremap_nocache(rcba, 0x4000);
- if (rcba_base == NULL) {
- printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
- return;
- }
-
- /* read the Function Disable register, dword mode only */
- val = readl(rcba_base + 0x3404);
-
- if (val & 0x80) {
- /* HPET is enabled in HPTC. Just not reported by BIOS */
- val = val & 0x3;
- force_hpet_address = 0xFED00000 | (val << 12);
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
- iounmap(rcba_base);
- return;
- }
-
- /* HPET disabled in HPTC. Trying to enable */
- writel(val | 0x80, rcba_base + 0x3404);
-
- val = readl(rcba_base + 0x3404);
- if (!(val & 0x80)) {
- err = 1;
- } else {
- val = val & 0x3;
- force_hpet_address = 0xFED00000 | (val << 12);
- }
-
- if (err) {
- force_hpet_address = 0;
- iounmap(rcba_base);
- printk(KERN_DEBUG "Failed to force enable HPET\n");
- } else {
- force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
- }
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
- ich_force_enable_hpet);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
- ich_force_enable_hpet);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,
- ich_force_enable_hpet);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,
- ich_force_enable_hpet);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
- ich_force_enable_hpet);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
- ich_force_enable_hpet);
-
-
-static struct pci_dev *cached_dev;
-
-static void old_ich_force_hpet_resume(void)
-{
- u32 val;
- u32 uninitialized_var(gen_cntl);
-
- if (!force_hpet_address || !cached_dev)
- return;
-
- pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
- gen_cntl &= (~(0x7 << 15));
- gen_cntl |= (0x4 << 15);
-
- pci_write_config_dword(cached_dev, 0xD0, gen_cntl);
- pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
- val = gen_cntl >> 15;
- val &= 0x7;
- if (val == 0x4)
- printk(KERN_DEBUG "Force enabled HPET at resume\n");
- else
- BUG();
-}
-
-static void old_ich_force_enable_hpet(struct pci_dev *dev)
-{
- u32 val;
- u32 uninitialized_var(gen_cntl);
-
- if (hpet_address || force_hpet_address)
- return;
-
- pci_read_config_dword(dev, 0xD0, &gen_cntl);
- /*
- * Bit 17 is HPET enable bit.
- * Bit 16:15 control the HPET base address.
- */
- val = gen_cntl >> 15;
- val &= 0x7;
- if (val & 0x4) {
- val &= 0x3;
- force_hpet_address = 0xFED00000 | (val << 12);
- printk(KERN_DEBUG "HPET at base address 0x%lx\n",
- force_hpet_address);
- return;
- }
-
- /*
- * HPET is disabled. Trying enabling at FED00000 and check
- * whether it sticks
- */
- gen_cntl &= (~(0x7 << 15));
- gen_cntl |= (0x4 << 15);
- pci_write_config_dword(dev, 0xD0, gen_cntl);
-
- pci_read_config_dword(dev, 0xD0, &gen_cntl);
-
- val = gen_cntl >> 15;
- val &= 0x7;
- if (val & 0x4) {
- /* HPET is enabled in HPTC. Just not reported by BIOS */
- val &= 0x3;
- force_hpet_address = 0xFED00000 | (val << 12);
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
- cached_dev = dev;
- force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
- return;
- }
-
- printk(KERN_DEBUG "Failed to force enable HPET\n");
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
- old_ich_force_enable_hpet);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12,
- old_ich_force_enable_hpet);
-
-void force_hpet_resume(void)
-{
- switch (force_hpet_resume_type) {
- case ICH_FORCE_HPET_RESUME:
- return ich_force_hpet_resume();
-
- case OLD_ICH_FORCE_HPET_RESUME:
- return old_ich_force_hpet_resume();
-
- default:
- break;
- }
-}
-
-#endif
diff --git a/trunk/arch/x86/kernel/setup_64.c b/trunk/arch/x86/kernel/setup_64.c
index 32054bf5ba40..af838f6b0b7f 100644
--- a/trunk/arch/x86/kernel/setup_64.c
+++ b/trunk/arch/x86/kernel/setup_64.c
@@ -546,37 +546,6 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
#endif
}
-#define ENABLE_C1E_MASK 0x18000000
-#define CPUID_PROCESSOR_SIGNATURE 1
-#define CPUID_XFAM 0x0ff00000
-#define CPUID_XFAM_K8 0x00000000
-#define CPUID_XFAM_10H 0x00100000
-#define CPUID_XFAM_11H 0x00200000
-#define CPUID_XMOD 0x000f0000
-#define CPUID_XMOD_REV_F 0x00040000
-
-/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
-static __cpuinit int amd_apic_timer_broken(void)
-{
- u32 lo, hi;
- u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
- switch (eax & CPUID_XFAM) {
- case CPUID_XFAM_K8:
- if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
- break;
- case CPUID_XFAM_10H:
- case CPUID_XFAM_11H:
- rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
- if (lo & ENABLE_C1E_MASK)
- return 1;
- break;
- default:
- /* err on the side of caution */
- return 1;
- }
- return 0;
-}
-
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
unsigned level;
@@ -648,9 +617,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
/* Family 10 doesn't support C states in MWAIT so don't use it */
if (c->x86 == 0x10 && !force_mwait)
clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
-
- if (amd_apic_timer_broken())
- disable_apic_timer = 1;
}
static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
diff --git a/trunk/arch/x86/kernel/smpboot_64.c b/trunk/arch/x86/kernel/smpboot_64.c
index 57ccf7cb6b91..32f50783edc8 100644
--- a/trunk/arch/x86/kernel/smpboot_64.c
+++ b/trunk/arch/x86/kernel/smpboot_64.c
@@ -223,6 +223,8 @@ void __cpuinit smp_callin(void)
local_irq_disable();
Dprintk("Stack at about %p\n",&cpuid);
+ disable_APIC_timer();
+
/*
* Save our processor parameters
*/
@@ -346,6 +348,8 @@ void __cpuinit start_secondary(void)
enable_8259A_irq(0);
}
+ enable_APIC_timer();
+
/*
* The sibling maps must be set before turing the online map on for
* this cpu
diff --git a/trunk/arch/x86/kernel/time_32.c b/trunk/arch/x86/kernel/time_32.c
index 56dadfc2f41c..19a6c678d02e 100644
--- a/trunk/arch/x86/kernel/time_32.c
+++ b/trunk/arch/x86/kernel/time_32.c
@@ -157,9 +157,6 @@ EXPORT_SYMBOL(profile_pc);
*/
irqreturn_t timer_interrupt(int irq, void *dev_id)
{
- /* Keep nmi watchdog up to date */
- per_cpu(irq_stat, smp_processor_id()).irq0_irqs++;
-
#ifdef CONFIG_X86_IO_APIC
if (timer_ack) {
/*
diff --git a/trunk/arch/x86/kernel/time_64.c b/trunk/arch/x86/kernel/time_64.c
index e0134d6c88da..6d48a4e826d9 100644
--- a/trunk/arch/x86/kernel/time_64.c
+++ b/trunk/arch/x86/kernel/time_64.c
@@ -28,12 +28,11 @@
#include
#include
#include
-#include
-
#ifdef CONFIG_ACPI
#include /* for PM timer frequency */
#include
#endif
+#include
#include
#include
#include
@@ -48,8 +47,12 @@
#include
#include
+static char *timename = NULL;
+
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
+DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
@@ -150,12 +153,45 @@ int update_persistent_clock(struct timespec now)
return set_rtc_mmss(now.tv_sec);
}
-static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
+void main_timer_handler(void)
{
- add_pda(irq0_irqs, 1);
+/*
+ * Here we are in the timer irq handler. We have irqs locally disabled (so we
+ * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
+ * on the other CPU, so we need a lock. We also need to lock the vsyscall
+ * variables, because both do_timer() and us change them -arca+vojtech
+ */
+
+ write_seqlock(&xtime_lock);
- global_clock_event->event_handler(global_clock_event);
+/*
+ * Do the timer stuff.
+ */
+
+ do_timer(1);
+#ifndef CONFIG_SMP
+ update_process_times(user_mode(get_irq_regs()));
+#endif
+/*
+ * In the SMP case we use the local APIC timer interrupt to do the profiling,
+ * except when we simulate SMP mode on a uniprocessor system, in that case we
+ * have to call the local interrupt handler.
+ */
+
+ if (!using_apic_timer)
+ smp_local_timer_interrupt();
+
+ write_sequnlock(&xtime_lock);
+}
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ if (apic_runs_main_timer > 1)
+ return IRQ_HANDLED;
+ main_timer_handler();
+ if (using_apic_timer)
+ smp_send_timer_broadcast_ipi();
return IRQ_HANDLED;
}
@@ -256,21 +292,97 @@ static unsigned int __init tsc_calibrate_cpu_khz(void)
return pmc_now * tsc_khz / (tsc_now - tsc_start);
}
+/*
+ * pit_calibrate_tsc() uses the speaker output (channel 2) of
+ * the PIT. This is better than using the timer interrupt output,
+ * because we can read the value of the speaker with just one inb(),
+ * where we need three i/o operations for the interrupt channel.
+ * We count how many ticks the TSC does in 50 ms.
+ */
+
+static unsigned int __init pit_calibrate_tsc(void)
+{
+ unsigned long start, end;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i8253_lock, flags);
+
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ outb(0xb0, 0x43);
+ outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
+ outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+ start = get_cycles_sync();
+ while ((inb(0x61) & 0x20) == 0);
+ end = get_cycles_sync();
+
+ spin_unlock_irqrestore(&i8253_lock, flags);
+
+ return (end - start) / 50;
+}
+
+#define PIT_MODE 0x43
+#define PIT_CH0 0x40
+
+static void __pit_init(int val, u8 mode)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&i8253_lock, flags);
+ outb_p(mode, PIT_MODE);
+ outb_p(val & 0xff, PIT_CH0); /* LSB */
+ outb_p(val >> 8, PIT_CH0); /* MSB */
+ spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+void __init pit_init(void)
+{
+ __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
+}
+
+void pit_stop_interrupt(void)
+{
+ __pit_init(0, 0x30); /* mode 0 */
+}
+
+void stop_timer_interrupt(void)
+{
+ char *name;
+ if (hpet_address) {
+ name = "HPET";
+ hpet_timer_stop_set_go(0);
+ } else {
+ name = "PIT";
+ pit_stop_interrupt();
+ }
+ printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
+}
+
static struct irqaction irq0 = {
- .handler = timer_event_interrupt,
- .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
.name = "timer"
};
void __init time_init(void)
{
- if (!hpet_enable())
- setup_pit_timer();
+ if (nohpet)
+ hpet_address = 0;
- setup_irq(0, &irq0);
+ if (hpet_arch_init())
+ hpet_address = 0;
- tsc_calibrate();
+ if (hpet_use_timer) {
+ /* set tick_nsec to use the proper rate for HPET */
+ tick_nsec = TICK_NSEC_HPET;
+ tsc_khz = hpet_calibrate_tsc();
+ timename = "HPET";
+ } else {
+ pit_init();
+ tsc_khz = pit_calibrate_tsc();
+ timename = "PIT";
+ }
cpu_khz = tsc_khz;
if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
@@ -286,7 +398,50 @@ void __init time_init(void)
else
vgetcpu_mode = VGETCPU_LSL;
+ set_cyc2ns_scale(tsc_khz);
printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
init_tsc_clocksource();
+
+ setup_irq(0, &irq0);
+}
+
+/*
+ * sysfs support for the timer.
+ */
+
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
+{
+ return 0;
+}
+
+static int timer_resume(struct sys_device *dev)
+{
+ if (hpet_address)
+ hpet_reenable();
+ else
+ i8254_timer_resume();
+ return 0;
}
+
+static struct sysdev_class timer_sysclass = {
+ .resume = timer_resume,
+ .suspend = timer_suspend,
+ set_kset_name("timer"),
+};
+
+/* XXX this sysfs stuff should probably go elsewhere later -john */
+static struct sys_device device_timer = {
+ .id = 0,
+ .cls = &timer_sysclass,
+};
+
+static int time_init_device(void)
+{
+ int error = sysdev_class_register(&timer_sysclass);
+ if (!error)
+ error = sysdev_register(&device_timer);
+ return error;
+}
+
+device_initcall(time_init_device);
diff --git a/trunk/arch/x86/kernel/tsc_64.c b/trunk/arch/x86/kernel/tsc_64.c
index 9f22e542c374..2a59bde663f2 100644
--- a/trunk/arch/x86/kernel/tsc_64.c
+++ b/trunk/arch/x86/kernel/tsc_64.c
@@ -6,9 +6,7 @@
#include
#include
#include
-#include
-#include
#include
static int notsc __initdata = 0;
@@ -20,7 +18,7 @@ EXPORT_SYMBOL(tsc_khz);
static unsigned int cyc2ns_scale __read_mostly;
-static inline void set_cyc2ns_scale(unsigned long khz)
+void set_cyc2ns_scale(unsigned long khz)
{
cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz;
}
@@ -120,95 +118,6 @@ core_initcall(cpufreq_tsc);
#endif
-#define MAX_RETRIES 5
-#define SMI_TRESHOLD 50000
-
-/*
- * Read TSC and the reference counters. Take care of SMI disturbance
- */
-static unsigned long __init tsc_read_refs(unsigned long *pm,
- unsigned long *hpet)
-{
- unsigned long t1, t2;
- int i;
-
- for (i = 0; i < MAX_RETRIES; i++) {
- t1 = get_cycles_sync();
- if (hpet)
- *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
- else
- *pm = acpi_pm_read_early();
- t2 = get_cycles_sync();
- if ((t2 - t1) < SMI_TRESHOLD)
- return t2;
- }
- return ULONG_MAX;
-}
-
-/**
- * tsc_calibrate - calibrate the tsc on boot
- */
-void __init tsc_calibrate(void)
-{
- unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2;
- int hpet = is_hpet_enabled();
-
- local_irq_save(flags);
-
- tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
-
- outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
- outb(0xb0, 0x43);
- outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
- outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
- tr1 = get_cycles_sync();
- while ((inb(0x61) & 0x20) == 0);
- tr2 = get_cycles_sync();
-
- tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
-
- local_irq_restore(flags);
-
- /*
- * Preset the result with the raw and inaccurate PIT
- * calibration value
- */
- tsc_khz = (tr2 - tr1) / 50;
-
- /* hpet or pmtimer available ? */
- if (!hpet && !pm1 && !pm2) {
- printk(KERN_INFO "TSC calibrated against PIT\n");
- return;
- }
-
- /* Check, whether the sampling was disturbed by an SMI */
- if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) {
- printk(KERN_WARNING "TSC calibration disturbed by SMI, "
- "using PIT calibration result\n");
- return;
- }
-
- tsc2 = (tsc2 - tsc1) * 1000000L;
-
- if (hpet) {
- printk(KERN_INFO "TSC calibrated against HPET\n");
- if (hpet2 < hpet1)
- hpet2 += 0x100000000;
- hpet2 -= hpet1;
- tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000;
- } else {
- printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
- if (pm2 < pm1)
- pm2 += ACPI_PM_OVRRUN;
- pm2 -= pm1;
- tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC;
- }
-
- tsc_khz = tsc2 / tsc1;
- set_cyc2ns_scale(tsc_khz);
-}
-
/*
* Make an educated guess if the TSC is trustworthy and synchronized
* over all CPUs.
diff --git a/trunk/arch/x86_64/Kconfig b/trunk/arch/x86_64/Kconfig
index eb80f5aca54e..b1b98e614f7c 100644
--- a/trunk/arch/x86_64/Kconfig
+++ b/trunk/arch/x86_64/Kconfig
@@ -36,18 +36,6 @@ config GENERIC_CMOS_UPDATE
bool
default y
-config CLOCKSOURCE_WATCHDOG
- bool
- default y
-
-config GENERIC_CLOCKEVENTS
- bool
- default y
-
-config GENERIC_CLOCKEVENTS_BROADCAST
- bool
- default y
-
config ZONE_DMA32
bool
default y
@@ -142,8 +130,6 @@ source "init/Kconfig"
menu "Processor type and features"
-source "kernel/time/Kconfig"
-
choice
prompt "Subarchitecture Type"
default X86_PC
diff --git a/trunk/block/Kconfig b/trunk/block/Kconfig
index e10895647f72..2484e0e9d89c 100644
--- a/trunk/block/Kconfig
+++ b/trunk/block/Kconfig
@@ -62,10 +62,6 @@ config BLK_DEV_BSG
protocols (e.g. Task Management Functions and SMP in Serial
Attached SCSI).
-config BLOCK_COMPAT
- bool
- default y
-
endif # BLOCK
source block/Kconfig.iosched
diff --git a/trunk/block/Makefile b/trunk/block/Makefile
index 826108190f00..3cfe7cebaa6a 100644
--- a/trunk/block/Makefile
+++ b/trunk/block/Makefile
@@ -11,4 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
-obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
+obj-$(CONFIG_COMPAT) += compat_ioctl.o
diff --git a/trunk/drivers/acpi/processor_idle.c b/trunk/drivers/acpi/processor_idle.c
index 1f6fb38de017..1e8287b4f40c 100644
--- a/trunk/drivers/acpi/processor_idle.c
+++ b/trunk/drivers/acpi/processor_idle.c
@@ -276,12 +276,21 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
{
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
unsigned long reason;
reason = pr->power.timer_broadcast_on_state < INT_MAX ?
CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
clockevents_notify(reason, &pr->id);
+#else
+ cpumask_t mask = cpumask_of_cpu(pr->id);
+
+ if (pr->power.timer_broadcast_on_state < INT_MAX)
+ on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
+ else
+ on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
+#endif
}
/* Power(C) State timer broadcast control */
@@ -289,6 +298,8 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
struct acpi_processor_cx *cx,
int broadcast)
{
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
int state = cx - pr->power.states;
if (state >= pr->power.timer_broadcast_on_state) {
@@ -298,6 +309,7 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
clockevents_notify(reason, &pr->id);
}
+#endif
}
#else
diff --git a/trunk/drivers/base/platform.c b/trunk/drivers/base/platform.c
index 869ff8c00146..9bfc434d1327 100644
--- a/trunk/drivers/base/platform.c
+++ b/trunk/drivers/base/platform.c
@@ -160,11 +160,6 @@ static void platform_device_release(struct device *dev)
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
- *
- * This device will be marked as not supporting hotpluggable drivers; no
- * device add/remove uevents will be generated. In the unusual case that
- * the device isn't being dynamically allocated as a legacy "probe the
- * hardware" driver, infrastructure code should reverse this marking.
*/
struct platform_device *platform_device_alloc(const char *name, unsigned int id)
{
@@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id)
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
-
- /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
- * legacy probe-the-hardware drivers, which don't properly split
- * out device enumeration logic from drivers.
- */
- pa->pdev.dev.uevent_suppress = 1;
}
return pa ? &pa->pdev : NULL;
@@ -530,7 +519,7 @@ static ssize_t
modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
- int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+ int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
@@ -546,7 +535,7 @@ static int platform_uevent(struct device *dev, char **envp, int num_envp,
struct platform_device *pdev = to_platform_device(dev);
envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+ snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name);
return 0;
}
diff --git a/trunk/drivers/block/Kconfig b/trunk/drivers/block/Kconfig
index ca4d7f0d09b7..4245b7f80a49 100644
--- a/trunk/drivers/block/Kconfig
+++ b/trunk/drivers/block/Kconfig
@@ -361,7 +361,8 @@ config BLK_DEV_RAM_SIZE
default "4096"
help
The default value is 4096 kilobytes. Only change this if you know
- what are you doing.
+ what are you doing. If you are using IBM S/390, then set this to
+ 8192.
config BLK_DEV_RAM_BLOCKSIZE
int "Default RAM disk block size (bytes)"
diff --git a/trunk/drivers/cpufreq/Kconfig b/trunk/drivers/cpufreq/Kconfig
index 721f86f4f008..993fa7b89253 100644
--- a/trunk/drivers/cpufreq/Kconfig
+++ b/trunk/drivers/cpufreq/Kconfig
@@ -56,6 +56,10 @@ config CPU_FREQ_STAT_DETAILS
If in doubt, say N.
+# Note that it is not currently possible to set the other governors (such as ondemand)
+# as the default, since if they fail to initialise, cpufreq will be
+# left in an undefined state.
+
choice
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -81,29 +85,6 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
program shall be able to set the CPU dynamically without having
to enable the userspace governor manually.
-config CPU_FREQ_DEFAULT_GOV_ONDEMAND
- bool "ondemand"
- select CPU_FREQ_GOV_ONDEMAND
- select CPU_FREQ_GOV_PERFORMANCE
- help
- Use the CPUFreq governor 'ondemand' as default. This allows
- you to get a full dynamic frequency capable system by simply
- loading your cpufreq low-level hardware driver.
- Be aware that not all cpufreq drivers support the ondemand
- governor. If unsure have a look at the help section of the
- driver. Fallback governor will be the performance governor.
-
-config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
- bool "conservative"
- select CPU_FREQ_GOV_CONSERVATIVE
- select CPU_FREQ_GOV_PERFORMANCE
- help
- Use the CPUFreq governor 'conservative' as default. This allows
- you to get a full dynamic frequency capable system by simply
- loading your cpufreq low-level hardware driver.
- Be aware that not all cpufreq drivers support the conservative
- governor. If unsure have a look at the help section of the
- driver. Fallback governor will be the performance governor.
endchoice
config CPU_FREQ_GOV_PERFORMANCE
diff --git a/trunk/drivers/cpufreq/cpufreq.c b/trunk/drivers/cpufreq/cpufreq.c
index f7b9d6fce123..2f6a73c01b71 100644
--- a/trunk/drivers/cpufreq/cpufreq.c
+++ b/trunk/drivers/cpufreq/cpufreq.c
@@ -763,8 +763,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
- /* Set governor before ->init, so that driver could check it */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
@@ -1111,7 +1109,12 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
unsigned int ret_freq = 0;
if (policy) {
+ if (unlikely(lock_policy_rwsem_read(cpu)))
+ return ret_freq;
+
ret_freq = policy->cur;
+
+ unlock_policy_rwsem_read(cpu);
cpufreq_cpu_put(policy);
}
@@ -1480,31 +1483,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
{
int ret;
- /* Only must be defined when default governor is known to have latency
- restrictions, like e.g. conservative or ondemand.
- That this is the case is already ensured in Kconfig
- */
-#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
- struct cpufreq_governor *gov = &cpufreq_gov_performance;
-#else
- struct cpufreq_governor *gov = NULL;
-#endif
-
- if (policy->governor->max_transition_latency &&
- policy->cpuinfo.transition_latency >
- policy->governor->max_transition_latency) {
- if (!gov)
- return -EINVAL;
- else {
- printk(KERN_WARNING "%s governor failed, too long"
- " transition latency of HW, fallback"
- " to %s governor\n",
- policy->governor->name,
- gov->name);
- policy->governor = gov;
- }
- }
-
if (!try_module_get(policy->governor->owner))
return -EINVAL;
@@ -1725,7 +1703,7 @@ int cpufreq_update_policy(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_update_policy);
-static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
+static int cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
diff --git a/trunk/drivers/cpufreq/cpufreq_conservative.c b/trunk/drivers/cpufreq/cpufreq_conservative.c
index 4bd33ce8a6f3..26f440ccc3fb 100644
--- a/trunk/drivers/cpufreq/cpufreq_conservative.c
+++ b/trunk/drivers/cpufreq/cpufreq_conservative.c
@@ -58,7 +58,7 @@ static unsigned int def_sampling_rate;
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -466,6 +466,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
(!policy->cur))
return -EINVAL;
+ if (policy->cpuinfo.transition_latency >
+ (TRANSITION_LATENCY_LIMIT * 1000))
+ return -EINVAL;
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -548,17 +551,15 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-struct cpufreq_governor cpufreq_gov_conservative = {
- .name = "conservative",
- .governor = cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
+static struct cpufreq_governor cpufreq_gov_dbs = {
+ .name = "conservative",
+ .governor = cpufreq_governor_dbs,
+ .owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_conservative);
static int __init cpufreq_gov_dbs_init(void)
{
- return cpufreq_register_governor(&cpufreq_gov_conservative);
+ return cpufreq_register_governor(&cpufreq_gov_dbs);
}
static void __exit cpufreq_gov_dbs_exit(void)
@@ -566,7 +567,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
/* Make sure that the scheduled work is indeed not running */
flush_scheduled_work();
- cpufreq_unregister_governor(&cpufreq_gov_conservative);
+ cpufreq_unregister_governor(&cpufreq_gov_dbs);
}
diff --git a/trunk/drivers/cpufreq/cpufreq_ondemand.c b/trunk/drivers/cpufreq/cpufreq_ondemand.c
index 369f44595150..e794527e4925 100644
--- a/trunk/drivers/cpufreq/cpufreq_ondemand.c
+++ b/trunk/drivers/cpufreq/cpufreq_ondemand.c
@@ -47,7 +47,7 @@ static unsigned int def_sampling_rate;
(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -508,6 +508,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if ((!cpu_online(cpu)) || (!policy->cur))
return -EINVAL;
+ if (policy->cpuinfo.transition_latency >
+ (TRANSITION_LATENCY_LIMIT * 1000)) {
+ printk(KERN_WARNING "ondemand governor failed to load "
+ "due to too long transition latency\n");
+ return -EINVAL;
+ }
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -579,13 +585,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-struct cpufreq_governor cpufreq_gov_ondemand = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
+static struct cpufreq_governor cpufreq_gov_dbs = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_ondemand);
static int __init cpufreq_gov_dbs_init(void)
{
@@ -594,12 +598,12 @@ static int __init cpufreq_gov_dbs_init(void)
printk(KERN_ERR "Creation of kondemand failed\n");
return -EFAULT;
}
- return cpufreq_register_governor(&cpufreq_gov_ondemand);
+ return cpufreq_register_governor(&cpufreq_gov_dbs);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- cpufreq_unregister_governor(&cpufreq_gov_ondemand);
+ cpufreq_unregister_governor(&cpufreq_gov_dbs);
destroy_workqueue(kondemand_wq);
}
diff --git a/trunk/drivers/cpufreq/cpufreq_stats.c b/trunk/drivers/cpufreq/cpufreq_stats.c
index 8a45d0f93e26..917b9bab9ccb 100644
--- a/trunk/drivers/cpufreq/cpufreq_stats.c
+++ b/trunk/drivers/cpufreq/cpufreq_stats.c
@@ -164,7 +164,8 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1;
}
-static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
+static void
+cpufreq_stats_free_table (unsigned int cpu)
{
struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -304,9 +305,8 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
return 0;
}
-static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
- unsigned long action,
- void *hcpu)
+static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -323,7 +323,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
+static struct notifier_block cpufreq_stat_cpu_notifier =
{
.notifier_call = cpufreq_stat_cpu_callback,
};
@@ -356,7 +356,8 @@ __init cpufreq_stats_init(void)
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_update_policy(cpu);
+ cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
+ CPU_ONLINE, (void *)(long)cpu);
}
return 0;
}
@@ -371,12 +372,13 @@ __exit cpufreq_stats_exit(void)
CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stats_free_table(cpu);
+ cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
+ CPU_DEAD, (void *)(long)cpu);
}
}
MODULE_AUTHOR ("Zou Nan hai ");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
"through sysfs filesystem");
MODULE_LICENSE ("GPL");
diff --git a/trunk/drivers/input/misc/pcspkr.c b/trunk/drivers/input/misc/pcspkr.c
index 4e2ca6f0ab18..e1a44020ed2b 100644
--- a/trunk/drivers/input/misc/pcspkr.c
+++ b/trunk/drivers/input/misc/pcspkr.c
@@ -17,17 +17,18 @@
#include
#include
#include
+#include
#include
MODULE_AUTHOR("Vojtech Pavlik ");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
#ifdef CONFIG_X86
/* Use the global PIT lock ! */
#include
#else
-#include
static DEFINE_SPINLOCK(i8253_lock);
#endif
diff --git a/trunk/drivers/isdn/hisax/avm_pci.c b/trunk/drivers/isdn/hisax/avm_pci.c
index f8b79783c8b3..b04a178e5021 100644
--- a/trunk/drivers/isdn/hisax/avm_pci.c
+++ b/trunk/drivers/isdn/hisax/avm_pci.c
@@ -20,6 +20,7 @@
#include
#include
+extern const char *CardType[];
static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
#define AVM_FRITZ_PCI 1
@@ -725,15 +726,100 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static int __devinit avm_setup_rest(struct IsdnCardState *cs)
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_avm __devinitdata = NULL;
+#endif
+#ifdef __ISAPNP__
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+#endif
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
{
u_int val, ver;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ strcpy(tmp, avm_pci_rev);
+ printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_FRITZPCI)
+ return (0);
+ if (card->para[1]) {
+ /* old manual method */
+ cs->hw.avm.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = AVM_FRITZ_PNP;
+ goto ready;
+ }
+#ifdef __ISAPNP__
+ if (isapnp_present()) {
+ struct pnp_dev *pnp_avm_d = NULL;
+ if ((pnp_avm_c = pnp_find_card(
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+ if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+ int err;
+
+ pnp_disable_dev(pnp_avm_d);
+ err = pnp_activate_dev(pnp_avm_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ cs->hw.avm.cfg_reg =
+ pnp_port_start(pnp_avm_d, 0);
+ cs->irq = pnp_irq(pnp_avm_d, 0);
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPnP:No IRQ\n");
+ return(0);
+ }
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPnP:No IO address\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PNP;
+ goto ready;
+ }
+ }
+ } else {
+ printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
+ }
+#endif
+#ifdef CONFIG_PCI
+ if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+ if (pci_enable_device(dev_avm))
+ return(0);
+ cs->irq = dev_avm->irq;
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PCI;
+ } else {
+ printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+#else
+ printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
+ return (0);
+#endif /* CONFIG_PCI */
+ready:
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
- "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 31);
return (0);
@@ -774,137 +860,3 @@ static int __devinit avm_setup_rest(struct IsdnCardState *cs)
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
-
-#ifndef __ISAPNP__
-
-static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
-{
- return(1); /* no-op: success */
-}
-
-#else
-
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-
-static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
-{
- struct pnp_dev *pnp_avm_d = NULL;
-
- if (!isapnp_present())
- return(1); /* no-op: success */
-
- if ((pnp_avm_c = pnp_find_card(
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
- if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
- int err;
-
- pnp_disable_dev(pnp_avm_d);
- err = pnp_activate_dev(pnp_avm_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- cs->hw.avm.cfg_reg =
- pnp_port_start(pnp_avm_d, 0);
- cs->irq = pnp_irq(pnp_avm_d, 0);
- if (!cs->irq) {
- printk(KERN_ERR "FritzPnP:No IRQ\n");
- return(0);
- }
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPnP:No IO address\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PNP;
-
- return (2); /* goto 'ready' label */
- }
- }
-
- return (1);
-}
-
-#endif /* __ISAPNP__ */
-
-#ifndef CONFIG_PCI
-
-static int __devinit avm_pci_setup(struct IsdnCardState *cs)
-{
- return(1); /* no-op: success */
-}
-
-#else
-
-static struct pci_dev *dev_avm __devinitdata = NULL;
-
-static int __devinit avm_pci_setup(struct IsdnCardState *cs)
-{
- if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_A1, dev_avm))) {
-
- if (pci_enable_device(dev_avm))
- return(0);
-
- cs->irq = dev_avm->irq;
- if (!cs->irq) {
- printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
- return(0);
- }
-
- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
- return(0);
- }
-
- cs->subtyp = AVM_FRITZ_PCI;
- } else {
- printk(KERN_WARNING "FritzPCI: No PCI card found\n");
- return(0);
- }
-
- cs->irq_flags |= IRQF_SHARED;
-
- return (1);
-}
-
-#endif /* CONFIG_PCI */
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- int rc;
-
- strcpy(tmp, avm_pci_rev);
- printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
-
- if (cs->typ != ISDN_CTYPE_FRITZPCI)
- return (0);
-
- if (card->para[1]) {
- /* old manual method */
- cs->hw.avm.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
-
- rc = avm_pnp_setup(cs);
- if (rc < 1)
- return (0);
- if (rc == 2)
- goto ready;
-
- rc = avm_pci_setup(cs);
- if (rc < 1)
- return (0);
-
-ready:
- return avm_setup_rest(cs);
-}
diff --git a/trunk/drivers/isdn/hisax/bkm_a8.c b/trunk/drivers/isdn/hisax/bkm_a8.c
index 99ef3b43fcd7..6339bb443f62 100644
--- a/trunk/drivers/isdn/hisax/bkm_a8.c
+++ b/trunk/drivers/isdn/hisax/bkm_a8.c
@@ -20,6 +20,8 @@
#include
#include "bkm_ax.h"
+#ifdef CONFIG_PCI
+
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
@@ -277,9 +279,12 @@ static u_char pci_bus __devinitdata = 0;
static u_char pci_device_fn __devinitdata = 0;
static u_char pci_irq __devinitdata = 0;
+#endif /* CONFIG_PCI */
+
int __devinit
setup_sct_quadro(struct IsdnCard *card)
{
+#ifdef CONFIG_PCI
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int found = 0;
@@ -437,4 +442,7 @@ setup_sct_quadro(struct IsdnCard *card)
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
+#else
+ printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
+#endif /* CONFIG_PCI */
}
diff --git a/trunk/drivers/isdn/hisax/diva.c b/trunk/drivers/isdn/hisax/diva.c
index 826745078746..6eebeb441bfd 100644
--- a/trunk/drivers/isdn/hisax/diva.c
+++ b/trunk/drivers/isdn/hisax/diva.c
@@ -25,6 +25,8 @@
#include
#include
+extern const char *CardType[];
+
static const char *Diva_revision = "$Revision: 1.33.2.6 $";
#define byteout(addr,val) outb(val,addr)
@@ -904,15 +906,225 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static int __devinit setup_diva_common(struct IsdnCardState *cs)
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+#endif
+
+
+int __devinit
+setup_diva(struct IsdnCard *card)
{
- int bytecnt;
+ int bytecnt = 8;
u_char val;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
- if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
- bytecnt = 8;
- else
- bytecnt = 32;
+ strcpy(tmp, Diva_revision);
+ printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+ return(0);
+ cs->hw.diva.status = 0;
+ if (card->para[1]) {
+ cs->hw.diva.ctrl_reg = 0;
+ cs->hw.diva.cfg_reg = card->para[1];
+ val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+ cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+ printk(KERN_INFO "Diva: IPAC version %x\n", val);
+ if ((val == 1) || (val==2)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+ }
+ cs->irq = card->para[0];
+ } else {
+#ifdef __ISAPNP__
+ if (isapnp_present()) {
+ struct pnp_dev *pnp_d;
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.diva.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl =
+ card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_HSCX_ADR;
+ }
+ goto ready;
+ } else {
+ printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c=NULL;
+ }
+ if (!ipid->card_vendor) {
+ printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
+ }
+ }
+#endif
+#ifdef CONFIG_PCI
+ cs->subtyp = 0;
+ if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+ if (pci_enable_device(dev_diva))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+ } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+ if (pci_enable_device(dev_diva_u))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva_u->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+ if (pci_enable_device(dev_diva201))
+ return(0);
+ cs->subtyp = DIVA_IPAC_PCI;
+ cs->irq = dev_diva201->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+ } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+ if (pci_enable_device(dev_diva202))
+ return(0);
+ cs->subtyp = DIVA_IPACX_PCI;
+ cs->irq = dev_diva202->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+ } else {
+ printk(KERN_WARNING "Diva: No PCI card found\n");
+ return(0);
+ }
+
+ if (!cs->irq) {
+ printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+
+ if (!cs->hw.diva.cfg_reg) {
+ printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+#else
+ printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
+ return (0);
+#endif /* CONFIG_PCI */
+ if ((cs->subtyp == DIVA_IPAC_PCI) ||
+ (cs->subtyp == DIVA_IPACX_PCI) ) {
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = 0;
+ cs->hw.diva.hscx = 0;
+ cs->hw.diva.isac_adr = 0;
+ cs->hw.diva.hscx_adr = 0;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ bytecnt = 0;
+ } else {
+ cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+ cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+ cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+ cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+ bytecnt = 32;
+ }
+ }
+
+#ifdef __ISAPNP__
+ready:
+#endif
printk(KERN_INFO
"Diva: %s card configured at %#lx IRQ %d\n",
@@ -933,7 +1145,7 @@ static int __devinit setup_diva_common(struct IsdnCardState *cs)
if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %lx-%lx already in use\n",
- "diva",
+ CardType[card->typ],
cs->hw.diva.cfg_reg,
cs->hw.diva.cfg_reg + bytecnt);
iounmap_diva(cs);
@@ -994,290 +1206,3 @@ static int __devinit setup_diva_common(struct IsdnCardState *cs)
}
return (1);
}
-
-#ifdef CONFIG_ISA
-
-static int __devinit setup_diva_isa(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
-
- if (!card->para[1])
- return (-1); /* card not found; continue search */
-
- cs->hw.diva.ctrl_reg = 0;
- cs->hw.diva.cfg_reg = card->para[1];
- val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
- cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- if ((val == 1) || (val==2)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
- }
- cs->irq = card->para[0];
-
- return (1); /* card found */
-}
-
-#else /* if !CONFIG_ISA */
-
-static int __devinit setup_diva_isa(struct IsdnCard *card)
-{
- return (-1); /* card not found; continue search */
-}
-
-#endif /* CONFIG_ISA */
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-
-static int __devinit setup_diva_isapnp(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- struct pnp_dev *pnp_d;
-
- if (!isapnp_present())
- return (-1); /* card not found; continue search */
-
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.diva.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl =
- card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac =
- card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_HSCX_ADR;
- }
- return (1); /* card found */
- } else {
- printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c=NULL;
- }
-
- return (-1); /* card not found; continue search */
-}
-
-#else /* if !ISAPNP */
-
-static int __devinit setup_diva_isapnp(struct IsdnCard *card)
-{
- return (-1); /* card not found; continue search */
-}
-
-#endif /* ISAPNP */
-
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-static int __devinit setup_diva_pci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
-
- cs->subtyp = 0;
- if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
- if (pci_enable_device(dev_diva))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
- if (pci_enable_device(dev_diva_u))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva_u->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
- if (pci_enable_device(dev_diva201))
- return(0);
- cs->subtyp = DIVA_IPAC_PCI;
- cs->irq = dev_diva201->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
- } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
- if (pci_enable_device(dev_diva202))
- return(0);
- cs->subtyp = DIVA_IPACX_PCI;
- cs->irq = dev_diva202->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
- } else {
- return (-1); /* card not found; continue search */
- }
-
- if (!cs->irq) {
- printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
-
- if (!cs->hw.diva.cfg_reg) {
- printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI) ) {
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = 0;
- cs->hw.diva.hscx = 0;
- cs->hw.diva.isac_adr = 0;
- cs->hw.diva.hscx_adr = 0;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
- cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
- cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
- cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
- }
-
- return (1); /* card found */
-}
-
-#else /* if !CONFIG_PCI */
-
-static int __devinit setup_diva_pci(struct IsdnCard *card)
-{
- return (-1); /* card not found; continue search */
-}
-
-#endif /* CONFIG_PCI */
-
-int __devinit
-setup_diva(struct IsdnCard *card)
-{
- int rc, have_card = 0;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Diva_revision);
- printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
- return(0);
- cs->hw.diva.status = 0;
-
- rc = setup_diva_isa(card);
- if (!rc)
- return rc;
- if (rc > 0) {
- have_card = 1;
- goto ready;
- }
-
- rc = setup_diva_isapnp(card);
- if (!rc)
- return rc;
- if (rc > 0) {
- have_card = 1;
- goto ready;
- }
-
- rc = setup_diva_pci(card);
- if (!rc)
- return rc;
- if (rc > 0)
- have_card = 1;
-
-ready:
- if (!have_card) {
- printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
- return(0);
- }
-
- return setup_diva_common(card->cs);
-}
diff --git a/trunk/drivers/isdn/hisax/elsa.c b/trunk/drivers/isdn/hisax/elsa.c
index 0c1351b23840..fab3e4ea0595 100644
--- a/trunk/drivers/isdn/hisax/elsa.c
+++ b/trunk/drivers/isdn/hisax/elsa.c
@@ -30,6 +30,8 @@
#include
#include
+extern const char *CardType[];
+
static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
static const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -830,75 +832,8 @@ probe_elsa(struct IsdnCardState *cs)
return (CARD_portlist[i]);
}
-static int __devinit
-setup_elsa_isa(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
-
- cs->hw.elsa.base = card->para[0];
- printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (cs->hw.elsa.base) {
- if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
- cs->typ))) {
- printk(KERN_WARNING
- "Elsa: no Elsa Microlink at %#lx\n",
- cs->hw.elsa.base);
- return (0);
- }
- } else
- cs->hw.elsa.base = probe_elsa(cs);
-
- if (!cs->hw.elsa.base) {
- printk(KERN_WARNING
- "No Elsa Microlink found\n");
- return (0);
- }
-
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- val = bytein(cs->hw.elsa.cfg);
- if (cs->subtyp == ELSA_PC) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
- } else if (cs->subtyp == ELSA_PCC8) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
- } else {
- const u_char CARD_IrqTab[8] =
- {15, 10, 15, 3, 11, 5, 11, 9};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
- }
- val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
- if (val < 3)
- val |= 8;
- val += 'A' - 3;
- if (val == 'B' || val == 'C')
- val ^= 1;
- if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
- val = 'C';
- printk(KERN_INFO
- "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- val, cs->irq);
- val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
- if (val) {
- printk(KERN_WARNING
- "Elsa: Microlink S0 bus power bad\n");
- cs->hw.elsa.status |= ELSA_BAD_PWR;
- }
-
- return (1);
-}
+static struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static struct pci_dev *dev_qs3000 __devinitdata = NULL;
#ifdef __ISAPNP__
static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -913,194 +848,233 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif /* __ISAPNP__ */
+#endif
-static int __devinit
-setup_elsa_isapnp(struct IsdnCard *card)
+int __devinit
+setup_elsa(struct IsdnCard *card)
{
+ int bytecnt;
+ u_char val;
struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ strcpy(tmp, Elsa_revision);
+ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ cs->hw.elsa.MFlag = 0;
+ cs->subtyp = 0;
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ cs->hw.elsa.base = card->para[0];
+ printk(KERN_INFO "Elsa: Microlink IO probing\n");
+ if (cs->hw.elsa.base) {
+ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+ cs->typ))) {
+ printk(KERN_WARNING
+ "Elsa: no Elsa Microlink at %#lx\n",
+ cs->hw.elsa.base);
+ return (0);
+ }
+ } else
+ cs->hw.elsa.base = probe_elsa(cs);
+ if (cs->hw.elsa.base) {
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ val = bytein(cs->hw.elsa.cfg);
+ if (cs->subtyp == ELSA_PC) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+ } else if (cs->subtyp == ELSA_PCC8) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+ } else {
+ const u_char CARD_IrqTab[8] =
+ {15, 10, 15, 3, 11, 5, 11, 9};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+ }
+ val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+ if (val < 3)
+ val |= 8;
+ val += 'A' - 3;
+ if (val == 'B' || val == 'C')
+ val ^= 1;
+ if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+ val = 'C';
+ printk(KERN_INFO
+ "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ val, cs->irq);
+ val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+ if (val) {
+ printk(KERN_WARNING
+ "Elsa: Microlink S0 bus power bad\n");
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ }
+ } else {
+ printk(KERN_WARNING
+ "No Elsa Microlink found\n");
+ return (0);
+ }
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
+ if (!card->para[1] && isapnp_present()) {
+ struct pnp_dev *pnp_d;
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ if (ipid->function == ISAPNP_FUNCTION(0x133))
+ cs->subtyp = ELSA_QS1000;
+ else
+ cs->subtyp = ELSA_QS3000;
+ break;
+ } else {
+ printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
return(0);
}
- if (ipid->function == ISAPNP_FUNCTION(0x133))
- cs->subtyp = ELSA_QS1000;
- else
- cs->subtyp = ELSA_QS3000;
- break;
- } else {
- printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
- return(0);
}
+ ipid++;
+ pnp_c=NULL;
+ }
+ if (!ipid->card_vendor) {
+ printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+ return(0);
}
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
- return(0);
}
- }
-#endif /* __ISAPNP__ */
-
- if (card->para[1] && card->para[0]) {
+#endif
+ if (card->para[1] && card->para[0]) {
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ if (!cs->subtyp)
+ cs->subtyp = ELSA_QS1000;
+ } else {
+ printk(KERN_ERR "Elsa PnP: no parameter\n");
+ }
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
cs->hw.elsa.base = card->para[1];
cs->irq = card->para[0];
- if (!cs->subtyp)
- cs->subtyp = ELSA_QS1000;
- } else {
- printk(KERN_ERR "Elsa PnP: no parameter\n");
- }
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
-
- return (1);
-}
-
-static void __devinit
-setup_elsa_pcmcia(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
-
- cs->hw.elsa.base = card->para[1];
- cs->irq = card->para[0];
- val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
- if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
- cs->subtyp = ELSA_PCMCIA_IPAC;
- cs->hw.elsa.ale = cs->hw.elsa.base + 0;
- cs->hw.elsa.isac = cs->hw.elsa.base + 2;
- cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = ELSA_PCMCIA;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- }
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->hw.elsa.ctrl = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
-}
-
+ val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+ if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+ cs->subtyp = ELSA_PCMCIA_IPAC;
+ cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+ cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = ELSA_PCMCIA;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ }
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->hw.elsa.ctrl = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
#ifdef CONFIG_PCI
-static struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static struct pci_dev *dev_qs3000 __devinitdata = NULL;
-
-static int __devinit
-setup_elsa_pci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
-
- cs->subtyp = 0;
- if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
- if (pci_enable_device(dev_qs1000))
+ cs->subtyp = 0;
+ if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+ if (pci_enable_device(dev_qs1000))
+ return(0);
+ cs->subtyp = ELSA_QS1000PCI;
+ cs->irq = dev_qs1000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+ } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+ if (pci_enable_device(dev_qs3000))
+ return(0);
+ cs->subtyp = ELSA_QS3000PCI;
+ cs->irq = dev_qs3000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+ } else {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
return(0);
- cs->subtyp = ELSA_QS1000PCI;
- cs->irq = dev_qs1000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
- if (pci_enable_device(dev_qs3000))
+ }
+ if (!cs->irq) {
+ printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
return(0);
- cs->subtyp = ELSA_QS3000PCI;
- cs->irq = dev_qs3000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
- } else {
- printk(KERN_WARNING "Elsa: No PCI card found\n");
- return(0);
- }
- if (!cs->irq) {
- printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
- return(0);
- }
-
- if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
- printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
- return(0);
- }
- if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
- printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
- printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
- printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
- }
- cs->hw.elsa.ale = cs->hw.elsa.base;
- cs->hw.elsa.isac = cs->hw.elsa.base +1;
- cs->hw.elsa.hscx = cs->hw.elsa.base +1;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->hw.elsa.cfg,
- cs->irq);
-
- return (1);
-}
+ }
+ if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+ printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+ printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+ printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+ printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+ }
+ cs->hw.elsa.ale = cs->hw.elsa.base;
+ cs->hw.elsa.isac = cs->hw.elsa.base +1;
+ cs->hw.elsa.hscx = cs->hw.elsa.base +1;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->hw.elsa.cfg,
+ cs->irq);
#else
-
-static void __devinit
-setup_elsa_pci(struct IsdnCard *card)
-{
- return (1);
-}
+ printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
+ return (0);
#endif /* CONFIG_PCI */
-
-static int __devinit
-setup_elsa_common(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
- int bytecnt;
+ } else
+ return (0);
switch (cs->subtyp) {
case ELSA_PC:
@@ -1130,7 +1104,8 @@ setup_elsa_common(struct IsdnCard *card)
here, it would fail. */
if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
printk(KERN_WARNING
- "HiSax: ELSA config port %#lx-%#lx already in use\n",
+ "HiSax: %s config port %#lx-%#lx already in use\n",
+ CardType[card->typ],
cs->hw.elsa.base,
cs->hw.elsa.base + bytecnt);
return (0);
@@ -1138,7 +1113,8 @@ setup_elsa_common(struct IsdnCard *card)
if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
printk(KERN_WARNING
- "HiSax: ELSA pci port %x-%x already in use\n",
+ "HiSax: %s pci port %x-%x already in use\n",
+ CardType[card->typ],
cs->hw.elsa.cfg,
cs->hw.elsa.cfg + 0x80);
release_region(cs->hw.elsa.base, bytecnt);
@@ -1210,41 +1186,3 @@ setup_elsa_common(struct IsdnCard *card)
}
return (1);
}
-
-int __devinit
-setup_elsa(struct IsdnCard *card)
-{
- int rc;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Elsa_revision);
- printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
- cs->hw.elsa.ctrl_reg = 0;
- cs->hw.elsa.status = 0;
- cs->hw.elsa.MFlag = 0;
- cs->subtyp = 0;
-
- if (cs->typ == ISDN_CTYPE_ELSA) {
- rc = setup_elsa_isa(card);
- if (!rc)
- return (0);
-
- } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
- rc = setup_elsa_isapnp(card);
- if (!rc)
- return (0);
-
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
- setup_elsa_pcmcia(card);
-
- else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
- rc = setup_elsa_pci(card);
- if (!rc)
- return (0);
-
- } else
- return (0);
-
- return setup_elsa_common(card);
-}
diff --git a/trunk/drivers/isdn/hisax/sedlbauer.c b/trunk/drivers/isdn/hisax/sedlbauer.c
index 03dfc32166a0..ad06f3cc60fb 100644
--- a/trunk/drivers/isdn/hisax/sedlbauer.c
+++ b/trunk/drivers/isdn/hisax/sedlbauer.c
@@ -518,6 +518,8 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
#ifdef __ISAPNP__
static struct isapnp_device_id sedl_ids[] __devinitdata = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -531,158 +533,15 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-
-static int __devinit
-setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
-{
- struct IsdnCardState *cs = card->cs;
- struct pnp_dev *pnp_d;
-
- if (!isapnp_present())
- return -1;
-
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.sedl.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0x2)) {
- cs->subtyp = SEDL_SPEED_FAX;
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- *bytecnt = 16;
- } else {
- cs->subtyp = SEDL_SPEED_CARD_WIN;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- }
-
- return (1);
- } else {
- printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
-
- printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
- return -1;
-}
-#else
-
-static int __devinit
-setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
-{
- return -1;
-}
-#endif /* __ISAPNP__ */
-
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
-static int __devinit
-setup_sedlbauer_pci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u16 sub_vendor_id, sub_id;
-
- if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
- if (pci_enable_device(dev_sedl))
- return(0);
- cs->irq = dev_sedl->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
- } else {
- printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.sedl.bus = SEDL_BUS_PCI;
- sub_vendor_id = dev_sedl->subsystem_vendor;
- sub_id = dev_sedl->subsystem_device;
- printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
- sub_vendor_id, sub_id);
- printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
- cs->hw.sedl.cfg_reg);
- if (sub_id != PCI_SUB_ID_SEDLBAUER) {
- printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
- return(0);
- }
- if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PCI;
- } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = HST_SAPHIR3;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = SEDL_SPEED_PCI;
- } else {
- printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
- sub_vendor_id);
- return(0);
- }
-
- cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
- byteout(cs->hw.sedl.cfg_reg, 0xff);
- byteout(cs->hw.sedl.cfg_reg, 0x00);
- byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
- mdelay(2);
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- mdelay(10);
-
- return (1);
-}
-
-#else
-
-static int __devinit
-setup_sedlbauer_pci(struct IsdnCard *card)
-{
- return (1);
-}
-
-#endif /* CONFIG_PCI */
+#endif
int __devinit
setup_sedlbauer(struct IsdnCard *card)
{
- int bytecnt = 8, ver, val, rc;
+ int bytecnt, ver, val;
struct IsdnCardState *cs = card->cs;
char tmp[64];
+ u16 sub_vendor_id, sub_id;
strcpy(tmp, Sedlbauer_revision);
printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -710,21 +569,124 @@ setup_sedlbauer(struct IsdnCard *card)
bytecnt = 16;
}
} else {
- rc = setup_sedlbauer_isapnp(card, &bytecnt);
- if (!rc)
- return (0);
- if (rc > 0)
- goto ready;
-
- /* Probe for Sedlbauer speed pci */
- rc = setup_sedlbauer_pci(card);
- if (!rc)
- return (0);
-
+#ifdef __ISAPNP__
+ if (isapnp_present()) {
+ struct pnp_dev *pnp_d;
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+ cs->subtyp = SEDL_SPEED_FAX;
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ bytecnt = 16;
+ } else {
+ cs->subtyp = SEDL_SPEED_CARD_WIN;
+ cs->hw.sedl.chip = SEDL_CHIP_TEST;
+ }
+ goto ready;
+ } else {
+ printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c = NULL;
+ }
+ if (!ipid->card_vendor) {
+ printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+ }
+ }
+#endif
+/* Probe for Sedlbauer speed pci */
+#ifdef CONFIG_PCI
+ if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+ if (pci_enable_device(dev_sedl))
+ return(0);
+ cs->irq = dev_sedl->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+ } else {
+ printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+ cs->hw.sedl.bus = SEDL_BUS_PCI;
+ sub_vendor_id = dev_sedl->subsystem_vendor;
+ sub_id = dev_sedl->subsystem_device;
+ printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+ sub_vendor_id, sub_id);
+ printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+ cs->hw.sedl.cfg_reg);
+ if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+ printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+ return(0);
+ }
+ if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PCI;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = HST_SAPHIR3;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = SEDL_SPEED_PCI;
+ } else {
+ printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+ sub_vendor_id);
+ return(0);
+ }
bytecnt = 256;
+ cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+ byteout(cs->hw.sedl.cfg_reg, 0xff);
+ byteout(cs->hw.sedl.cfg_reg, 0x00);
+ byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+ mdelay(2);
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+ mdelay(10);
+#else
+ printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
+ return (0);
+#endif /* CONFIG_PCI */
}
+#ifdef __ISAPNP__
ready:
+#endif
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
diff --git a/trunk/drivers/isdn/hisax/telespci.c b/trunk/drivers/isdn/hisax/telespci.c
index 4393003ae162..d09f6d033f15 100644
--- a/trunk/drivers/isdn/hisax/telespci.c
+++ b/trunk/drivers/isdn/hisax/telespci.c
@@ -295,12 +295,11 @@ setup_telespci(struct IsdnCard *card)
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
-
strcpy(tmp, telespci_revision);
printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELESPCI)
return (0);
-
+#ifdef CONFIG_PCI
if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
if (pci_enable_device(dev_tel))
return(0);
@@ -318,6 +317,11 @@ setup_telespci(struct IsdnCard *card)
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
}
+#else
+ printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
+ return (0);
+#endif /* CONFIG_PCI */
/* Initialize Zoran PCI controller */
writel(0x00000000, cs->hw.teles0.membase + 0x28);
diff --git a/trunk/drivers/isdn/hisax/w6692.c b/trunk/drivers/isdn/hisax/w6692.c
index 39129b94f8be..3aeceaf9769e 100644
--- a/trunk/drivers/isdn/hisax/w6692.c
+++ b/trunk/drivers/isdn/hisax/w6692.c
@@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card)
printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_W6692)
return (0);
-
+#ifdef CONFIG_PCI
while (id_list[id_idx].vendor_id) {
dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
id_list[id_idx].device_id,
@@ -1061,6 +1061,11 @@ setup_w6692(struct IsdnCard *card)
cs->hw.w6692.iobase + 255);
return (0);
}
+#else
+ printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "HiSax: W6692 unable to config\n");
+ return (0);
+#endif /* CONFIG_PCI */
printk(KERN_INFO
"HiSax: %s config irq:%d I/O:%x\n",
diff --git a/trunk/drivers/isdn/hysdn/hysdn_init.c b/trunk/drivers/isdn/hysdn/hysdn_init.c
index b7cc5c2f08c6..9e01748a176e 100644
--- a/trunk/drivers/isdn/hysdn/hysdn_init.c
+++ b/trunk/drivers/isdn/hysdn/hysdn_init.c
@@ -20,15 +20,10 @@
#include "hysdn_defs.h"
static struct pci_device_id hysdn_pci_tbl[] = {
- { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
- { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
- { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
- { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
-
+ {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
+ {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
+ {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
+ {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -39,7 +34,128 @@ MODULE_LICENSE("GPL");
static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
static int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
-static hysdn_card *card_last = NULL; /* pointer to first card */
+
+/**********************************************/
+/* table assigning PCI-sub ids to board types */
+/* the last entry contains all 0 */
+/**********************************************/
+static struct {
+ unsigned short subid; /* PCI sub id */
+ unsigned char cardtyp; /* card type assigned */
+} pci_subid_map[] = {
+
+ {
+ PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
+ },
+ {
+ PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
+ },
+ {
+ PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
+ },
+ {
+ PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
+ },
+ {
+ 0, 0
+ } /* terminating entry */
+};
+
+
+/*********************************************************************/
+/* search_cards searches for available cards in the pci config data. */
+/* If a card is found, the card structure is allocated and the cards */
+/* ressources are reserved. cardmax is incremented. */
+/*********************************************************************/
+static void
+search_cards(void)
+{
+ struct pci_dev *akt_pcidev = NULL;
+ hysdn_card *card, *card_last;
+ int i;
+
+ card_root = NULL;
+ card_last = NULL;
+ while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ akt_pcidev)) != NULL) {
+ if (pci_enable_device(akt_pcidev))
+ continue;
+
+ if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+ return;
+ }
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+ card->subsysid = akt_pcidev->subsystem_device;
+ card->irq = akt_pcidev->irq;
+ card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+ card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+ card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+ card->bchans = 2; /* and 2 b-channels */
+ for (i = 0; pci_subid_map[i].subid; i++)
+ if (pci_subid_map[i].subid == card->subsysid) {
+ card->brdtype = pci_subid_map[i].cardtyp;
+ break;
+ }
+ if (card->brdtype != BD_NONE) {
+ if (ergo_inithardware(card)) {
+ printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+ kfree(card);
+ continue;
+ }
+ } else {
+ printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
+ kfree(card); /* release mem */
+ continue;
+ }
+ cardmax++;
+ card->next = NULL; /*end of chain */
+ if (card_last)
+ card_last->next = card; /* pointer to next card */
+ else
+ card_root = card;
+ card_last = card; /* new chain end */
+ } /* device found */
+} /* search_cards */
+
+/************************************************************************************/
+/* free_resources frees the acquired PCI resources and returns the allocated memory */
+/************************************************************************************/
+static void
+free_resources(void)
+{
+ hysdn_card *card;
+
+ while (card_root) {
+ card = card_root;
+ if (card->releasehardware)
+ card->releasehardware(card); /* free all hardware resources */
+ card_root = card_root->next; /* remove card from chain */
+ kfree(card); /* return mem */
+
+ } /* while card_root */
+} /* free_resources */
+
+/**************************************************************************/
+/* stop_cards disables (hardware resets) all cards and disables interrupt */
+/**************************************************************************/
+static void
+stop_cards(void)
+{
+ hysdn_card *card;
+
+ card = card_root; /* first in chain */
+ while (card) {
+ if (card->stopcard)
+ card->stopcard(card);
+ card = card->next; /* remove card from chain */
+ } /* while card */
+} /* stop_cards */
/****************************************************************************/
@@ -75,138 +191,31 @@ hysdn_getrev(const char *revision)
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
-
-static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
- const struct pci_device_id *ent)
-{
- hysdn_card *card;
- int rc;
-
- rc = pci_enable_device(akt_pcidev);
- if (rc)
- return rc;
-
- if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
- printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
- rc = -ENOMEM;
- goto err_out;
- }
- card->myid = cardmax; /* set own id */
- card->bus = akt_pcidev->bus->number;
- card->devfn = akt_pcidev->devfn; /* slot + function */
- card->subsysid = akt_pcidev->subsystem_device;
- card->irq = akt_pcidev->irq;
- card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
- card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
- card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
- card->brdtype = BD_NONE; /* unknown */
- card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
- card->faxchans = 0; /* default no fax channels */
- card->bchans = 2; /* and 2 b-channels */
- card->brdtype = ent->driver_data;
-
- if (ergo_inithardware(card)) {
- printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
- rc = -EBUSY;
- goto err_out_card;
- }
-
- cardmax++;
- card->next = NULL; /*end of chain */
- if (card_last)
- card_last->next = card; /* pointer to next card */
- else
- card_root = card;
- card_last = card; /* new chain end */
-
- pci_set_drvdata(akt_pcidev, card);
- return 0;
-
-err_out_card:
- kfree(card);
-err_out:
- pci_disable_device(akt_pcidev);
- return rc;
-}
-
-static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
-{
- hysdn_card *card = pci_get_drvdata(akt_pcidev);
-
- pci_set_drvdata(akt_pcidev, NULL);
-
- if (card->stopcard)
- card->stopcard(card);
-
-#ifdef CONFIG_HYSDN_CAPI
- hycapi_capi_release(card);
-#endif
-
- if (card->releasehardware)
- card->releasehardware(card); /* free all hardware resources */
-
- if (card == card_root) {
- card_root = card_root->next;
- if (!card_root)
- card_last = NULL;
- } else {
- hysdn_card *tmp = card_root;
- while (tmp) {
- if (tmp->next == card)
- tmp->next = card->next;
- card_last = tmp;
- tmp = tmp->next;
- }
- }
-
- kfree(card);
- pci_disable_device(akt_pcidev);
-}
-
-static struct pci_driver hysdn_pci_driver = {
- .name = "hysdn",
- .id_table = hysdn_pci_tbl,
- .probe = hysdn_pci_init_one,
- .remove = __devexit_p(hysdn_pci_remove_one),
-};
-
-static int hysdn_have_procfs;
-
static int __init
hysdn_init(void)
{
char tmp[50];
- int rc;
strcpy(tmp, hysdn_init_revision);
printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
strcpy(tmp, hysdn_net_revision);
printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
-
- rc = pci_register_driver(&hysdn_pci_driver);
- if (rc)
- return rc;
-
+ search_cards();
printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
- if (!hysdn_procconf_init())
- hysdn_have_procfs = 1;
-
+ if (hysdn_procconf_init()) {
+ free_resources(); /* proc file_sys not created */
+ return (-1);
+ }
#ifdef CONFIG_HYSDN_CAPI
if(cardmax > 0) {
if(hycapi_init()) {
printk(KERN_ERR "HYCAPI: init failed\n");
-
- if (hysdn_have_procfs)
- hysdn_procconf_release();
-
- pci_unregister_driver(&hysdn_pci_driver);
- return -ESPIPE;
+ return(-1);
}
}
#endif /* CONFIG_HYSDN_CAPI */
-
- return 0; /* no error */
+ return (0); /* no error */
} /* init_module */
@@ -221,15 +230,20 @@ hysdn_init(void)
static void __exit
hysdn_exit(void)
{
- if (hysdn_have_procfs)
- hysdn_procconf_release();
-
- pci_unregister_driver(&hysdn_pci_driver);
-
#ifdef CONFIG_HYSDN_CAPI
+ hysdn_card *card;
+#endif /* CONFIG_HYSDN_CAPI */
+ stop_cards();
+#ifdef CONFIG_HYSDN_CAPI
+ card = card_root; /* first in chain */
+ while (card) {
+ hycapi_capi_release(card);
+ card = card->next; /* remove card from chain */
+ } /* while card */
hycapi_cleanup();
#endif /* CONFIG_HYSDN_CAPI */
-
+ hysdn_procconf_release();
+ free_resources();
printk(KERN_NOTICE "HYSDN: module unloaded\n");
} /* cleanup_module */
diff --git a/trunk/drivers/mmc/core/host.c b/trunk/drivers/mmc/core/host.c
index c65d203a846d..64fbc9759a30 100644
--- a/trunk/drivers/mmc/core/host.c
+++ b/trunk/drivers/mmc/core/host.c
@@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev);
- led_trigger_unregister_simple(host->led);
+ led_trigger_unregister(host->led);
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
diff --git a/trunk/drivers/net/bnx2.c b/trunk/drivers/net/bnx2.c
index 78ed633ceb82..d68accea380b 100644
--- a/trunk/drivers/net/bnx2.c
+++ b/trunk/drivers/net/bnx2.c
@@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
REG_RD(bp, BNX2_HC_COMMAND);
}
- if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+ if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
bnx2_tx_int(bp);
- if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+ if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
work_done += bnx2_rx_int(bp, budget - work_done);
return work_done;
@@ -2665,7 +2665,6 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
{
struct bnx2 *bp = container_of(napi, struct bnx2, napi);
int work_done = 0;
- struct status_block *sblk = bp->status_blk;
while (1) {
work_done = bnx2_poll_work(bp, work_done, budget);
@@ -2673,19 +2672,16 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
if (unlikely(work_done >= budget))
break;
- /* bp->last_status_idx is used below to tell the hw how
- * much work has been processed, so we must read it before
- * checking for more work.
- */
- bp->last_status_idx = sblk->status_idx;
- rmb();
if (likely(!bnx2_has_work(bp))) {
+ bp->last_status_idx = bp->status_blk->status_idx;
+ rmb();
+
netif_rx_complete(bp->dev, napi);
if (likely(bp->flags & USING_MSI_FLAG)) {
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
bp->last_status_idx);
- break;
+ return 0;
}
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
diff --git a/trunk/drivers/net/tg3.c b/trunk/drivers/net/tg3.c
index 30b1cca8144c..e795c33b982d 100644
--- a/trunk/drivers/net/tg3.c
+++ b/trunk/drivers/net/tg3.c
@@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
tg3_tx(tp);
if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
- return work_done;
+ return 0;
}
/* run RX thread, within the bounds set by NAPI.
@@ -3593,7 +3593,6 @@ static int tg3_poll(struct napi_struct *napi, int budget)
{
struct tg3 *tp = container_of(napi, struct tg3, napi);
int work_done = 0;
- struct tg3_hw_status *sblk = tp->hw_status;
while (1) {
work_done = tg3_poll_work(tp, work_done, budget);
@@ -3604,17 +3603,15 @@ static int tg3_poll(struct napi_struct *napi, int budget)
if (unlikely(work_done >= budget))
break;
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
- /* tp->last_tag is used in tg3_restart_ints() below
- * to tell the hw how much work has been processed,
- * so we must read it before checking for more work.
- */
- tp->last_tag = sblk->status_tag;
- rmb();
- } else
- sblk->status &= ~SD_STATUS_UPDATED;
-
if (likely(!tg3_has_work(tp))) {
+ struct tg3_hw_status *sblk = tp->hw_status;
+
+ if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+ tp->last_tag = sblk->status_tag;
+ rmb();
+ } else
+ sblk->status &= ~SD_STATUS_UPDATED;
+
netif_rx_complete(tp->dev, napi);
tg3_restart_ints(tp);
break;
@@ -3624,10 +3621,9 @@ static int tg3_poll(struct napi_struct *napi, int budget)
return work_done;
tx_recovery:
- /* work_done is guaranteed to be less than budget. */
netif_rx_complete(tp->dev, napi);
schedule_work(&tp->reset_task);
- return work_done;
+ return 0;
}
static void tg3_irq_quiesce(struct tg3 *tp)
diff --git a/trunk/drivers/pcmcia/pxa2xx_mainstone.c b/trunk/drivers/pcmcia/pxa2xx_mainstone.c
index 383107ba4bd3..f6722ba0dd1e 100644
--- a/trunk/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/trunk/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void)
if (!mst_pcmcia_device)
return -ENOMEM;
- mst_pcmcia_device->dev.uevent_suppress = 0;
mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
ret = platform_device_add(mst_pcmcia_device);
@@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init);
module_exit(mst_pcmcia_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/trunk/drivers/pcmcia/pxa2xx_sharpsl.c b/trunk/drivers/pcmcia/pxa2xx_sharpsl.c
index a2daa3f531b2..d5c33bd78d68 100644
--- a/trunk/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/trunk/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void)
if (!sharpsl_pcmcia_device)
return -ENOMEM;
- sharpsl_pcmcia_device->dev.uevent_suppress = 0;
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
@@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit);
MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/trunk/drivers/s390/block/dasd_int.h b/trunk/drivers/s390/block/dasd_int.h
index d427daeef511..aeda52682446 100644
--- a/trunk/drivers/s390/block/dasd_int.h
+++ b/trunk/drivers/s390/block/dasd_int.h
@@ -53,7 +53,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -457,7 +456,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem)
static inline int
dasd_check_blocksize(int bsize)
{
- if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
+ if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
return -EMEDIUMTYPE;
return 0;
}
diff --git a/trunk/drivers/s390/block/xpram.c b/trunk/drivers/s390/block/xpram.c
index f231bc21b1ca..0fbacc8b1063 100644
--- a/trunk/drivers/s390/block/xpram.c
+++ b/trunk/drivers/s390/block/xpram.c
@@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio)
}
}
set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
+ bio_end_io(bio, 0);
return 0;
fail:
bio_io_error(bio);
diff --git a/trunk/drivers/s390/char/con3215.c b/trunk/drivers/s390/char/con3215.c
index 0e1f35c9ed9d..6000bdee4082 100644
--- a/trunk/drivers/s390/char/con3215.c
+++ b/trunk/drivers/s390/char/con3215.c
@@ -667,9 +667,6 @@ raw3215_probe (struct ccw_device *cdev)
struct raw3215_info *raw;
int line;
- /* Console is special. */
- if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
- return 0;
raw = kmalloc(sizeof(struct raw3215_info) +
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
if (raw == NULL)
diff --git a/trunk/drivers/s390/char/con3270.c b/trunk/drivers/s390/char/con3270.c
index 0b040557db02..fd3479119eb4 100644
--- a/trunk/drivers/s390/char/con3270.c
+++ b/trunk/drivers/s390/char/con3270.c
@@ -22,7 +22,6 @@
#include
#include "raw3270.h"
-#include "tty3270.h"
#include "ctrlchar.h"
#define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -508,6 +507,8 @@ con3270_write(struct console *co, const char *str, unsigned int count)
spin_unlock_irqrestore(&cp->view.lock,flags);
}
+extern struct tty_driver *tty3270_driver;
+
static struct tty_driver *
con3270_device(struct console *c, int *index)
{
diff --git a/trunk/drivers/s390/char/sclp.c b/trunk/drivers/s390/char/sclp.c
index 25629b92dec3..fa62e6944057 100644
--- a/trunk/drivers/s390/char/sclp.c
+++ b/trunk/drivers/s390/char/sclp.c
@@ -93,7 +93,6 @@ static volatile enum sclp_mask_state_t {
#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
-static void __sclp_make_read_req(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
@@ -116,6 +115,7 @@ sclp_service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
+static inline void __sclp_make_read_req(void);
static void
__sclp_queue_read_req(void)
@@ -318,7 +318,8 @@ sclp_read_cb(struct sclp_req *req, void *data)
}
/* Prepare read event data request. Called while sclp_lock is locked. */
-static void __sclp_make_read_req(void)
+static inline void
+__sclp_make_read_req(void)
{
struct sccb_header *sccb;
diff --git a/trunk/drivers/s390/char/tape_3590.c b/trunk/drivers/s390/char/tape_3590.c
index da25f8e24152..9f244c591eeb 100644
--- a/trunk/drivers/s390/char/tape_3590.c
+++ b/trunk/drivers/s390/char/tape_3590.c
@@ -708,22 +708,16 @@ static void tape_3590_med_state_set(struct tape_device *device,
c_info = &TAPE_3590_CRYPT_INFO(device);
- DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
- switch (sense->macst) {
- case 0x04:
- case 0x05:
- case 0x06:
+ if (sense->masst == MSENSE_UNASSOCIATED) {
tape_med_state_set(device, MS_UNLOADED);
TAPE_3590_CRYPT_INFO(device).medium_status = 0;
return;
- case 0x08:
- case 0x09:
- tape_med_state_set(device, MS_LOADED);
- break;
- default:
- tape_med_state_set(device, MS_UNKNOWN);
+ }
+ if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
+ PRINT_ERR("Unknown medium state: %x\n", sense->masst);
return;
}
+ tape_med_state_set(device, MS_LOADED);
c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
if (sense->flags & MSENSE_CRYPT_MASK) {
PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -841,17 +835,15 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
/* Probably result of halt ssch */
return TAPE_IO_PENDING;
else if (irb->scsw.dstat == 0x85)
- /* Device Ready */
- DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
- else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+ /* Device Ready -> check medium state */
+ tape_3590_schedule_work(device, TO_MSEN);
+ else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
tape_3590_schedule_work(device, TO_READ_ATTMSG);
- } else {
+ else {
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
tape_dump_sense(device, NULL, irb);
}
- /* check medium state */
- tape_3590_schedule_work(device, TO_MSEN);
return TAPE_IO_SUCCESS;
}
diff --git a/trunk/drivers/s390/char/tty3270.c b/trunk/drivers/s390/char/tty3270.c
index 70b1980a08b6..bc33068b9ce2 100644
--- a/trunk/drivers/s390/char/tty3270.c
+++ b/trunk/drivers/s390/char/tty3270.c
@@ -25,8 +25,8 @@
#include
#include
+
#include "raw3270.h"
-#include "tty3270.h"
#include "keyboard.h"
#define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,11 +1338,8 @@ tty3270_getpar(struct tty3270 *tp, int ix)
static void
tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
{
- int max_cx = max(0, cx);
- int max_cy = max(0, cy);
-
- tp->cx = min_t(int, tp->view.cols - 1, max_cx);
- cy = min_t(int, tp->view.rows - 3, max_cy);
+ tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
+ cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
if (cy != tp->cy) {
tty3270_convert_line(tp, tp->cy);
tp->cy = cy;
diff --git a/trunk/drivers/s390/char/tty3270.h b/trunk/drivers/s390/char/tty3270.h
deleted file mode 100644
index 799da57f0390..000000000000
--- a/trunk/drivers/s390/char/tty3270.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * drivers/s390/char/tty3270.h
- *
- * Copyright IBM Corp. 2007
- *
- */
-
-#ifndef __DRIVERS_S390_CHAR_TTY3270_H
-#define __DRIVERS_S390_CHAR_TTY3270_H
-
-#include
-#include
-
-extern struct tty_driver *tty3270_driver;
-
-#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/trunk/drivers/s390/char/vmwatchdog.c b/trunk/drivers/s390/char/vmwatchdog.c
index 6f40facb1c4d..680b9b58b80e 100644
--- a/trunk/drivers/s390/char/vmwatchdog.c
+++ b/trunk/drivers/s390/char/vmwatchdog.c
@@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout,
"0: la %0,0\n"
"1:\n"
EX_TABLE(0b,1b)
- : "+d" (err) : "d"(__func), "d"(__timeout),
- "d"(__cmdp), "d"(__cmdl) : "1", "cc");
+ : "=d" (err) : "d"(__func), "d"(__timeout),
+ "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
return err;
}
diff --git a/trunk/drivers/s390/char/zcore.c b/trunk/drivers/s390/char/zcore.c
index 7073daf77981..3712ede16723 100644
--- a/trunk/drivers/s390/char/zcore.c
+++ b/trunk/drivers/s390/char/zcore.c
@@ -141,16 +141,15 @@ static int memcpy_real(void *dest, unsigned long src, size_t count)
if (count == 0)
return 0;
- flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
+ flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
asm volatile (
"0: mvcle %1,%2,0x0\n"
"1: jo 0b\n"
" lhi %0,0x0\n"
"2:\n"
EX_TABLE(1b,2b)
- : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
- "+d" (_len2), "=m" (*((long*)dest))
- : "m" (*((long*)src))
+ : "+d" (rc)
+ : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
: "cc", "memory");
__raw_local_irq_ssm(flags);
diff --git a/trunk/drivers/s390/cio/ccwgroup.c b/trunk/drivers/s390/cio/ccwgroup.c
index 9c3b9ea1e66f..b0a18f5176aa 100644
--- a/trunk/drivers/s390/cio/ccwgroup.c
+++ b/trunk/drivers/s390/cio/ccwgroup.c
@@ -152,24 +152,16 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
-/**
- * ccwgroup_create() - create and register a ccw group device
- * @root: parent device for the new device
- * @creator_id: identifier of creating driver
- * @cdrv: ccw driver of slave devices
- * @argc: number of slave devices
- * @argv: bus ids of slave devices
- *
- * Create and register a new ccw group device as a child of @root. Slave
- * devices are obtained from the list of bus ids given in @argv[] and must all
- * belong to @cdrv.
- * Returns:
- * %0 on success and an error code on failure.
- * Context:
- * non-atomic
+/*
+ * try to add a new ccwgroup device for one driver
+ * argc and argv[] are a list of bus_id's of devices
+ * belonging to the driver.
*/
-int ccwgroup_create(struct device *root, unsigned int creator_id,
- struct ccw_driver *cdrv, int argc, char *argv[])
+int
+ccwgroup_create(struct device *root,
+ unsigned int creator_id,
+ struct ccw_driver *cdrv,
+ int argc, char *argv[])
{
struct ccwgroup_device *gdev;
int i;
@@ -398,13 +390,8 @@ static struct bus_type ccwgroup_bus_type = {
.remove = ccwgroup_remove,
};
-/**
- * ccwgroup_driver_register() - register a ccw group driver
- * @cdriver: driver to be registered
- *
- * This function is mainly a wrapper around driver_register().
- */
-int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
+int
+ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
{
/* register our new driver with the core */
cdriver->driver.bus = &ccwgroup_bus_type;
@@ -419,13 +406,8 @@ __ccwgroup_match_all(struct device *dev, void *data)
return 1;
}
-/**
- * ccwgroup_driver_unregister() - deregister a ccw group driver
- * @cdriver: driver to be deregistered
- *
- * This function is mainly a wrapper around driver_unregister().
- */
-void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
+void
+ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
{
struct device *dev;
@@ -445,16 +427,8 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
driver_unregister(&cdriver->driver);
}
-/**
- * ccwgroup_probe_ccwdev() - probe function for slave devices
- * @cdev: ccw device to be probed
- *
- * This is a dummy probe function for ccw devices that are slave devices in
- * a ccw group device.
- * Returns:
- * always %0
- */
-int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+int
+ccwgroup_probe_ccwdev(struct ccw_device *cdev)
{
return 0;
}
@@ -478,15 +452,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
return NULL;
}
-/**
- * ccwgroup_remove_ccwdev() - remove function for slave devices
- * @cdev: ccw device to be removed
- *
- * This is a remove function for ccw devices that are slave devices in a ccw
- * group device. It sets the ccw device offline and also deregisters the
- * embedding ccw group device.
- */
-void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+void
+ccwgroup_remove_ccwdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/trunk/drivers/s390/cio/chp.c b/trunk/drivers/s390/cio/chp.c
index 42c1f4659adb..920dd71e6434 100644
--- a/trunk/drivers/s390/cio/chp.c
+++ b/trunk/drivers/s390/cio/chp.c
@@ -14,7 +14,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue;
/* Return channel_path struct for given chpid. */
static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
{
- return channel_subsystems[chpid.cssid]->chps[chpid.id];
+ return css[chpid.cssid]->chps[chpid.id];
}
/* Set vary state for given chpid. */
@@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
opm = 0;
chp_id_init(&chpid);
- for (i = 0; i < 8; i++) {
+ for (i=0; i < 8; i++) {
opm <<= 1;
chpid.id = sch->schib.pmcw.chpid[i];
if (chp_get_status(chpid) != 0)
@@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
chpid.id);
- CIO_TRACE_EVENT(2, dbf_text);
+ CIO_TRACE_EVENT( 2, dbf_text);
status = chp_get_status(chpid);
if (!on && !status) {
@@ -140,11 +140,9 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct channel_path *chp;
- struct device *device;
unsigned int size;
- device = container_of(kobj, struct device, kobj);
- chp = to_channelpath(device);
+ chp = to_channelpath(container_of(kobj, struct device, kobj));
if (!chp->cmg_chars)
return 0;
@@ -195,11 +193,9 @@ static ssize_t chp_measurement_read(struct kobject *kobj,
{
struct channel_path *chp;
struct channel_subsystem *css;
- struct device *device;
unsigned int size;
- device = container_of(kobj, struct device, kobj);
- chp = to_channelpath(device);
+ chp = to_channelpath(container_of(kobj, struct device, kobj));
css = to_css(chp->dev.parent);
size = sizeof(struct cmg_entry);
@@ -357,7 +353,7 @@ static ssize_t chp_shared_show(struct device *dev,
static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
-static struct attribute *chp_attrs[] = {
+static struct attribute * chp_attrs[] = {
&dev_attr_status.attr,
&dev_attr_configure.attr,
&dev_attr_type.attr,
@@ -399,7 +395,7 @@ int chp_new(struct chp_id chpid)
/* fill in status, etc. */
chp->chpid = chpid;
chp->state = 1;
- chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
+ chp->dev.parent = &css[chpid.cssid]->device;
chp->dev.release = chp_release;
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
chpid.id);
@@ -434,18 +430,18 @@ int chp_new(struct chp_id chpid)
device_unregister(&chp->dev);
goto out_free;
}
- mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
- if (channel_subsystems[chpid.cssid]->cm_enabled) {
+ mutex_lock(&css[chpid.cssid]->mutex);
+ if (css[chpid.cssid]->cm_enabled) {
ret = chp_add_cmg_attr(chp);
if (ret) {
sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
device_unregister(&chp->dev);
- mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
+ mutex_unlock(&css[chpid.cssid]->mutex);
goto out_free;
}
}
- channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
- mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
+ css[chpid.cssid]->chps[chpid.id] = chp;
+ mutex_unlock(&css[chpid.cssid]->mutex);
return ret;
out_free:
kfree(chp);
diff --git a/trunk/drivers/s390/cio/cio.c b/trunk/drivers/s390/cio/cio.c
index 46905345159e..f2708d65be5a 100644
--- a/trunk/drivers/s390/cio/cio.c
+++ b/trunk/drivers/s390/cio/cio.c
@@ -619,11 +619,6 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1; /* multipath mode */
- /* clean up possible residual cmf stuff */
- sch->schib.pmcw.mme = 0;
- sch->schib.pmcw.mbfc = 0;
- sch->schib.pmcw.mbi = 0;
- sch->schib.mba = 0;
return 0;
out:
if (!cio_is_console(schid))
diff --git a/trunk/drivers/s390/cio/cmf.c b/trunk/drivers/s390/cio/cmf.c
index b960f66843e4..34a796913b06 100644
--- a/trunk/drivers/s390/cio/cmf.c
+++ b/trunk/drivers/s390/cio/cmf.c
@@ -45,8 +45,7 @@
#include "ioasm.h"
#include "chsc.h"
-/*
- * parameter to enable cmf during boot, possible uses are:
+/* parameter to enable cmf during boot, possible uses are:
* "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
* used on any subchannel
* "s390cmf=" -- enable cmf and allocate enough memory to measure
@@ -74,20 +73,18 @@ enum cmb_index {
* enum cmb_format - types of supported measurement block formats
*
* @CMF_BASIC: traditional channel measurement blocks supported
- * by all machines that we run on
+ * by all machines that we run on
* @CMF_EXTENDED: improved format that was introduced with the z990
- * machine
- * @CMF_AUTODETECT: default: use extended format when running on a machine
- * supporting extended format, otherwise fall back to
- * basic format
- */
+ * machine
+ * @CMF_AUTODETECT: default: use extended format when running on a z990
+ * or later machine, otherwise fall back to basic format
+ **/
enum cmb_format {
CMF_BASIC,
CMF_EXTENDED,
CMF_AUTODETECT = -1,
};
-
-/*
+/**
* format - actual format for all measurement blocks
*
* The format module parameter can be set to a value of 0 (zero)
@@ -108,21 +105,20 @@ module_param(format, bool, 0444);
* either with the help of a special pool or with kmalloc
* @free: free memory allocated with @alloc
* @set: enable or disable measurement
- * @read: read a measurement entry at an index
* @readall: read a measurement block in a common format
* @reset: clear the data in the associated measurement block and
* reset its time stamp
* @align: align an allocated block so that the hardware can use it
*/
struct cmb_operations {
- int (*alloc) (struct ccw_device *);
- void (*free) (struct ccw_device *);
- int (*set) (struct ccw_device *, u32);
- u64 (*read) (struct ccw_device *, int);
- int (*readall)(struct ccw_device *, struct cmbdata *);
- void (*reset) (struct ccw_device *);
- void *(*align) (void *);
-/* private: */
+ int (*alloc) (struct ccw_device*);
+ void(*free) (struct ccw_device*);
+ int (*set) (struct ccw_device*, u32);
+ u64 (*read) (struct ccw_device*, int);
+ int (*readall)(struct ccw_device*, struct cmbdata *);
+ void (*reset) (struct ccw_device*);
+ void * (*align) (void *);
+
struct attribute_group *attr_group;
};
static struct cmb_operations *cmbops;
@@ -134,11 +130,9 @@ struct cmb_data {
unsigned long long last_update; /* when last_block was updated */
};
-/*
- * Our user interface is designed in terms of nanoseconds,
+/* our user interface is designed in terms of nanoseconds,
* while the hardware measures total times in its own
- * unit.
- */
+ * unit.*/
static inline u64 time_to_nsec(u32 value)
{
return ((u64)value) * 128000ull;
@@ -165,13 +159,12 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
return ret;
}
-/*
- * Activate or deactivate the channel monitor. When area is NULL,
+/* activate or deactivate the channel monitor. When area is NULL,
* the monitor is deactivated. The channel monitor needs to
* be active in order to measure subchannels, which also need
- * to be enabled.
- */
-static inline void cmf_activate(void *area, unsigned int onoff)
+ * to be enabled. */
+static inline void
+cmf_activate(void *area, unsigned int onoff)
{
register void * __gpr2 asm("2");
register long __gpr1 asm("1");
@@ -182,8 +175,8 @@ static inline void cmf_activate(void *area, unsigned int onoff)
asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
}
-static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
- unsigned long address)
+static int
+set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
{
int ret;
int retry;
@@ -473,7 +466,6 @@ static void cmf_generic_reset(struct ccw_device *cdev)
*
* @mem: pointer to CMBs (only in basic measurement mode)
* @list: contains a linked list of all subchannels
- * @num_channels: number of channels to be measured
* @lock: protect concurrent access to @mem and @list
*/
struct cmb_area {
@@ -489,36 +481,28 @@ static struct cmb_area cmb_area = {
.num_channels = 1024,
};
+
/* ****** old style CMB handling ********/
-/*
+/** int maxchannels
+ *
* Basic channel measurement blocks are allocated in one contiguous
* block of memory, which can not be moved as long as any channel
* is active. Therefore, a maximum number of subchannels needs to
* be defined somewhere. This is a module parameter, defaulting to
* a resonable value of 1024, or 32 kb of memory.
* Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096.
+ * maximum is 4096
*/
module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
/**
* struct cmb - basic channel measurement block
- * @ssch_rsch_count: number of ssch and rsch
- * @sample_count: number of samples
- * @device_connect_time: time of device connect
- * @function_pending_time: time of function pending
- * @device_disconnect_time: time of device disconnect
- * @control_unit_queuing_time: time of control unit queuing
- * @device_active_only_time: time of device active only
- * @reserved: unused in basic measurement mode
- *
- * The measurement block as used by the hardware. The fields are described
- * further in z/Architecture Principles of Operation, chapter 17.
*
- * The cmb area made up from these blocks must be a contiguous array and may
- * not be reallocated or freed.
+ * cmb as used by the hardware the fields are described in z/Architecture
+ * Principles of Operation, chapter 17.
+ * The area to be a contiguous array and may not be reallocated or freed.
* Only one cmb area can be present in the system.
*/
struct cmb {
@@ -532,9 +516,8 @@ struct cmb {
u32 reserved[2];
};
-/*
- * Insert a single device into the cmb_area list.
- * Called with cmb_area.lock held from alloc_cmb.
+/* insert a single device into the cmb_area list
+ * called with cmb_area.lock held from alloc_cmb
*/
static int alloc_cmb_single(struct ccw_device *cdev,
struct cmb_data *cmb_data)
@@ -549,11 +532,9 @@ static int alloc_cmb_single(struct ccw_device *cdev,
goto out;
}
- /*
- * Find first unused cmb in cmb_area.mem.
- * This is a little tricky: cmb_area.list
- * remains sorted by ->cmb->hw_data pointers.
- */
+ /* find first unused cmb in cmb_area.mem.
+ * this is a little tricky: cmb_area.list
+ * remains sorted by ->cmb->hw_data pointers */
cmb = cmb_area.mem;
list_for_each_entry(node, &cmb_area.list, cmb_list) {
struct cmb_data *data;
@@ -577,7 +558,8 @@ static int alloc_cmb_single(struct ccw_device *cdev,
return ret;
}
-static int alloc_cmb(struct ccw_device *cdev)
+static int
+alloc_cmb (struct ccw_device *cdev)
{
int ret;
struct cmb *mem;
@@ -688,7 +670,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme)
return set_schib_wait(cdev, mme, 0, offset);
}
-static u64 read_cmb(struct ccw_device *cdev, int index)
+static u64 read_cmb (struct ccw_device *cdev, int index)
{
struct cmb *cmb;
u32 val;
@@ -738,7 +720,7 @@ static u64 read_cmb(struct ccw_device *cdev, int index)
return ret;
}
-static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
{
struct cmb *cmb;
struct cmb_data *cmb_data;
@@ -811,25 +793,14 @@ static struct cmb_operations cmbops_basic = {
.align = align_cmb,
.attr_group = &cmf_attr_group,
};
-
+
/* ******** extended cmb handling ********/
/**
* struct cmbe - extended channel measurement block
- * @ssch_rsch_count: number of ssch and rsch
- * @sample_count: number of samples
- * @device_connect_time: time of device connect
- * @function_pending_time: time of function pending
- * @device_disconnect_time: time of device disconnect
- * @control_unit_queuing_time: time of control unit queuing
- * @device_active_only_time: time of device active only
- * @device_busy_time: time of device busy
- * @initial_command_response_time: initial command response time
- * @reserved: unused
*
- * The measurement block as used by the hardware. May be in any 64 bit physical
- * location.
- * The fields are described further in z/Architecture Principles of Operation,
+ * cmb as used by the hardware, may be in any 64 bit physical location,
+ * the fields are described in z/Architecture Principles of Operation,
* third edition, chapter 17.
*/
struct cmbe {
@@ -845,12 +816,10 @@ struct cmbe {
u32 reserved[7];
};
-/*
- * kmalloc only guarantees 8 byte alignment, but we need cmbe
+/* kmalloc only guarantees 8 byte alignment, but we need cmbe
* pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes.
- */
-static inline struct cmbe *cmbe_align(struct cmbe *c)
+ * enough space for two cmbes */
+static inline struct cmbe* cmbe_align(struct cmbe *c)
{
unsigned long addr;
addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -858,7 +827,7 @@ static inline struct cmbe *cmbe_align(struct cmbe *c)
return (struct cmbe*)addr;
}
-static int alloc_cmbe(struct ccw_device *cdev)
+static int alloc_cmbe (struct ccw_device *cdev)
{
struct cmbe *cmbe;
struct cmb_data *cmb_data;
@@ -904,7 +873,7 @@ static int alloc_cmbe(struct ccw_device *cdev)
return ret;
}
-static void free_cmbe(struct ccw_device *cdev)
+static void free_cmbe (struct ccw_device *cdev)
{
struct cmb_data *cmb_data;
@@ -943,7 +912,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
}
-static u64 read_cmbe(struct ccw_device *cdev, int index)
+static u64 read_cmbe (struct ccw_device *cdev, int index)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -1001,7 +970,7 @@ static u64 read_cmbe(struct ccw_device *cdev, int index)
return ret;
}
-static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -1078,16 +1047,17 @@ static struct cmb_operations cmbops_extended = {
.align = align_cmbe,
.attr_group = &cmf_attr_group_ext,
};
+
-static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t
+cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
{
return sprintf(buf, "%lld\n",
(unsigned long long) cmf_read(to_ccwdev(dev), idx));
}
-static ssize_t cmb_show_avg_sample_interval(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t
+cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ccw_device *cdev;
long interval;
@@ -1109,9 +1079,8 @@ static ssize_t cmb_show_avg_sample_interval(struct device *dev,
return sprintf(buf, "%ld\n", interval);
}
-static ssize_t cmb_show_avg_utilization(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t
+cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cmbdata data;
u64 utilization;
@@ -1143,16 +1112,14 @@ static ssize_t cmb_show_avg_utilization(struct device *dev,
}
#define cmf_attr(name) \
-static ssize_t show_##name(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ return cmb_show_attr((dev), buf, cmb_##name); } \
-static DEVICE_ATTR(name, 0444, show_##name, NULL);
+static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
+{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
+static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
#define cmf_attr_avg(name) \
-static ssize_t show_avg_##name(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ return cmb_show_attr((dev), buf, cmb_##name); } \
-static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
+static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
+{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
+static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
cmf_attr(ssch_rsch_count);
cmf_attr(sample_count);
@@ -1164,8 +1131,7 @@ cmf_attr_avg(device_active_only_time);
cmf_attr_avg(device_busy_time);
cmf_attr_avg(initial_command_response_time);
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
- NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
static struct attribute *cmf_attributes[] = {
@@ -1206,16 +1172,12 @@ static struct attribute_group cmf_attr_group_ext = {
.attrs = cmf_attributes_ext,
};
-static ssize_t cmb_enable_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
}
-static ssize_t cmb_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t c)
+static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
{
struct ccw_device *cdev;
int ret;
@@ -1240,16 +1202,9 @@ static ssize_t cmb_enable_store(struct device *dev,
DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
-/**
- * enable_cmf() - switch on the channel measurement for a specific device
- * @cdev: The ccw device to be enabled
- *
- * Returns %0 for success or a negative error value.
- *
- * Context:
- * non-atomic
- */
-int enable_cmf(struct ccw_device *cdev)
+/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
+int
+enable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1270,16 +1225,8 @@ int enable_cmf(struct ccw_device *cdev)
return ret;
}
-/**
- * disable_cmf() - switch off the channel measurement for a specific device
- * @cdev: The ccw device to be disabled
- *
- * Returns %0 for success or a negative error value.
- *
- * Context:
- * non-atomic
- */
-int disable_cmf(struct ccw_device *cdev)
+int
+disable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1291,32 +1238,14 @@ int disable_cmf(struct ccw_device *cdev)
return ret;
}
-/**
- * cmf_read() - read one value from the current channel measurement block
- * @cdev: the channel to be read
- * @index: the index of the value to be read
- *
- * Returns the value read or %0 if the value cannot be read.
- *
- * Context:
- * any
- */
-u64 cmf_read(struct ccw_device *cdev, int index)
+u64
+cmf_read(struct ccw_device *cdev, int index)
{
return cmbops->read(cdev, index);
}
-/**
- * cmf_readall() - read the current channel measurement block
- * @cdev: the channel to be read
- * @data: a pointer to a data block that will be filled
- *
- * Returns %0 on success, a negative error value otherwise.
- *
- * Context:
- * any
- */
-int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+int
+cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
{
return cmbops->readall(cdev, data);
}
@@ -1328,16 +1257,15 @@ int cmf_reenable(struct ccw_device *cdev)
return cmbops->set(cdev, 2);
}
-static int __init init_cmf(void)
+static int __init
+init_cmf(void)
{
char *format_string;
char *detect_string = "parameter";
- /*
- * If the user did not give a parameter, see if we are running on a
- * machine supporting extended measurement blocks, otherwise fall back
- * to basic mode.
- */
+ /* We cannot really autoprobe this. If the user did not give a parameter,
+ see if we are running on z990 or up, otherwise fall back to basic mode. */
+
if (format == CMF_AUTODETECT) {
if (!css_characteristics_avail ||
!css_general_characteristics.ext_mb) {
@@ -1356,7 +1284,7 @@ static int __init init_cmf(void)
cmbops = &cmbops_basic;
break;
case CMF_EXTENDED:
- format_string = "extended";
+ format_string = "extended";
cmbops = &cmbops_extended;
break;
default:
diff --git a/trunk/drivers/s390/cio/css.c b/trunk/drivers/s390/cio/css.c
index 5d83dd471461..5635e656c1a3 100644
--- a/trunk/drivers/s390/cio/css.c
+++ b/trunk/drivers/s390/cio/css.c
@@ -13,7 +13,6 @@
#include
#include
#include
-#include
#include "css.h"
#include "cio.h"
@@ -28,7 +27,7 @@ int css_init_done = 0;
static int need_reprobe = 0;
static int max_ssid = 0;
-struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
+struct channel_subsystem *css[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
@@ -178,7 +177,7 @@ static int css_register_subchannel(struct subchannel *sch)
int ret;
/* Initialize the subchannel structure */
- sch->dev.parent = &channel_subsystems[0]->device;
+ sch->dev.parent = &css[0]->device;
sch->dev.bus = &css_bus_type;
sch->dev.release = &css_subchannel_release;
sch->dev.groups = subch_attr_groups;
@@ -607,55 +606,30 @@ static int __init setup_css(int nr)
{
u32 tod_high;
int ret;
- struct channel_subsystem *css;
- css = channel_subsystems[nr];
- memset(css, 0, sizeof(struct channel_subsystem));
- css->pseudo_subchannel =
- kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
- if (!css->pseudo_subchannel)
+ memset(css[nr], 0, sizeof(struct channel_subsystem));
+ css[nr]->pseudo_subchannel =
+ kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
+ if (!css[nr]->pseudo_subchannel)
return -ENOMEM;
- css->pseudo_subchannel->dev.parent = &css->device;
- css->pseudo_subchannel->dev.release = css_subchannel_release;
- sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
- ret = cio_create_sch_lock(css->pseudo_subchannel);
+ css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
+ css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
if (ret) {
- kfree(css->pseudo_subchannel);
+ kfree(css[nr]->pseudo_subchannel);
return ret;
}
- mutex_init(&css->mutex);
- css->valid = 1;
- css->cssid = nr;
- sprintf(css->device.bus_id, "css%x", nr);
- css->device.release = channel_subsystem_release;
+ mutex_init(&css[nr]->mutex);
+ css[nr]->valid = 1;
+ css[nr]->cssid = nr;
+ sprintf(css[nr]->device.bus_id, "css%x", nr);
+ css[nr]->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
- css_generate_pgid(css, tod_high);
+ css_generate_pgid(css[nr], tod_high);
return 0;
}
-static int css_reboot_event(struct notifier_block *this,
- unsigned long event,
- void *ptr)
-{
- int ret, i;
-
- ret = NOTIFY_DONE;
- for (i = 0; i <= __MAX_CSSID; i++) {
- struct channel_subsystem *css;
-
- css = channel_subsystems[i];
- if (css->cm_enabled)
- if (chsc_secm(css, 0))
- ret = NOTIFY_BAD;
- }
-
- return ret;
-}
-
-static struct notifier_block css_reboot_notifier = {
- .notifier_call = css_reboot_event,
-};
-
/*
* Now that the driver core is running, we can setup our channel subsystem.
* The struct subchannel's are created during probing (except for the
@@ -696,63 +670,51 @@ init_channel_subsystem (void)
}
/* Setup css structure. */
for (i = 0; i <= __MAX_CSSID; i++) {
- struct channel_subsystem *css;
-
- css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
- if (!css) {
+ css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+ if (!css[i]) {
ret = -ENOMEM;
goto out_unregister;
}
- channel_subsystems[i] = css;
ret = setup_css(i);
if (ret)
goto out_free;
- ret = device_register(&css->device);
+ ret = device_register(&css[i]->device);
if (ret)
goto out_free_all;
if (css_characteristics_avail &&
css_chsc_characteristics.secm) {
- ret = device_create_file(&css->device,
+ ret = device_create_file(&css[i]->device,
&dev_attr_cm_enable);
if (ret)
goto out_device;
}
- ret = device_register(&css->pseudo_subchannel->dev);
+ ret = device_register(&css[i]->pseudo_subchannel->dev);
if (ret)
goto out_file;
}
- ret = register_reboot_notifier(&css_reboot_notifier);
- if (ret)
- goto out_pseudo;
css_init_done = 1;
ctl_set_bit(6, 28);
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
-out_pseudo:
- device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
out_file:
- device_remove_file(&channel_subsystems[i]->device,
- &dev_attr_cm_enable);
+ device_remove_file(&css[i]->device, &dev_attr_cm_enable);
out_device:
- device_unregister(&channel_subsystems[i]->device);
+ device_unregister(&css[i]->device);
out_free_all:
- kfree(channel_subsystems[i]->pseudo_subchannel->lock);
- kfree(channel_subsystems[i]->pseudo_subchannel);
+ kfree(css[i]->pseudo_subchannel->lock);
+ kfree(css[i]->pseudo_subchannel);
out_free:
- kfree(channel_subsystems[i]);
+ kfree(css[i]);
out_unregister:
while (i > 0) {
- struct channel_subsystem *css;
-
i--;
- css = channel_subsystems[i];
- device_unregister(&css->pseudo_subchannel->dev);
+ device_unregister(&css[i]->pseudo_subchannel->dev);
if (css_characteristics_avail && css_chsc_characteristics.secm)
- device_remove_file(&css->device,
+ device_remove_file(&css[i]->device,
&dev_attr_cm_enable);
- device_unregister(&css->device);
+ device_unregister(&css[i]->device);
}
out_bus:
bus_unregister(&css_bus_type);
diff --git a/trunk/drivers/s390/cio/css.h b/trunk/drivers/s390/cio/css.h
index 81215ef32435..5d65e83ca66e 100644
--- a/trunk/drivers/s390/cio/css.h
+++ b/trunk/drivers/s390/cio/css.h
@@ -167,7 +167,7 @@ struct channel_subsystem {
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
extern struct bus_type css_bus_type;
-extern struct channel_subsystem *channel_subsystems[];
+extern struct channel_subsystem *css[];
/* Some helper functions for disconnected state. */
int device_is_disconnected(struct subchannel *);
@@ -191,5 +191,6 @@ int sch_is_pseudo_sch(struct subchannel *);
extern struct workqueue_struct *slow_path_wq;
+int subchannel_add_files (struct device *);
extern struct attribute_group *subch_attr_groups[];
#endif
diff --git a/trunk/drivers/s390/cio/device.c b/trunk/drivers/s390/cio/device.c
index 39f02b48e4c7..e44d92eac8e9 100644
--- a/trunk/drivers/s390/cio/device.c
+++ b/trunk/drivers/s390/cio/device.c
@@ -21,7 +21,6 @@
#include
#include
#include /* HZ */
-#include
#include "cio.h"
#include "cio_debug.h"
@@ -358,18 +357,8 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
cdev->private->dev_id.devno);
}
-/**
- * ccw_device_set_offline() - disable a ccw device for I/O
- * @cdev: target ccw device
- *
- * This function calls the driver's set_offline() function for @cdev, if
- * given, and then disables @cdev.
- * Returns:
- * %0 on success and a negative error value on failure.
- * Context:
- * enabled, ccw device lock not held
- */
-int ccw_device_set_offline(struct ccw_device *cdev)
+int
+ccw_device_set_offline(struct ccw_device *cdev)
{
int ret;
@@ -407,19 +396,8 @@ int ccw_device_set_offline(struct ccw_device *cdev)
return ret;
}
-/**
- * ccw_device_set_online() - enable a ccw device for I/O
- * @cdev: target ccw device
- *
- * This function first enables @cdev and then calls the driver's set_online()
- * function for @cdev, if given. If set_online() returns an error, @cdev is
- * disabled again.
- * Returns:
- * %0 on success and a negative error value on failure.
- * Context:
- * enabled, ccw device lock not held
- */
-int ccw_device_set_online(struct ccw_device *cdev)
+int
+ccw_device_set_online(struct ccw_device *cdev)
{
int ret;
@@ -969,7 +947,8 @@ io_subchannel_register(struct work_struct *work)
wake_up(&ccw_device_init_wq);
}
-static void ccw_device_call_sch_unregister(struct work_struct *work)
+void
+ccw_device_call_sch_unregister(struct work_struct *work)
{
struct ccw_device_private *priv;
struct ccw_device *cdev;
@@ -1122,7 +1101,6 @@ io_subchannel_probe (struct subchannel *sch)
* device, e.g. the console.
*/
cdev = sch->dev.driver_data;
- cdev->dev.groups = ccwdev_attr_groups;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
/*
@@ -1348,19 +1326,8 @@ __ccwdev_check_busid(struct device *dev, void *id)
}
-/**
- * get_ccwdev_by_busid() - obtain device from a bus id
- * @cdrv: driver the device is owned by
- * @bus_id: bus id of the device to be searched
- *
- * This function searches all devices owned by @cdrv for a device with a bus
- * id matching @bus_id.
- * Returns:
- * If a match is found, its reference count of the found device is increased
- * and it is returned; else %NULL is returned.
- */
-struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
- const char *bus_id)
+struct ccw_device *
+get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
{
struct device *dev;
struct device_driver *drv;
@@ -1434,34 +1401,16 @@ ccw_device_remove (struct device *dev)
return 0;
}
-static void ccw_device_shutdown(struct device *dev)
-{
- struct ccw_device *cdev;
-
- cdev = to_ccwdev(dev);
- if (cdev->drv && cdev->drv->shutdown)
- cdev->drv->shutdown(cdev);
- disable_cmf(cdev);
-}
-
struct bus_type ccw_bus_type = {
.name = "ccw",
.match = ccw_bus_match,
.uevent = ccw_uevent,
.probe = ccw_device_probe,
.remove = ccw_device_remove,
- .shutdown = ccw_device_shutdown,
};
-/**
- * ccw_driver_register() - register a ccw driver
- * @cdriver: driver to be registered
- *
- * This function is mainly a wrapper around driver_register().
- * Returns:
- * %0 on success and a negative error value on failure.
- */
-int ccw_driver_register(struct ccw_driver *cdriver)
+int
+ccw_driver_register (struct ccw_driver *cdriver)
{
struct device_driver *drv = &cdriver->driver;
@@ -1471,13 +1420,8 @@ int ccw_driver_register(struct ccw_driver *cdriver)
return driver_register(drv);
}
-/**
- * ccw_driver_unregister() - deregister a ccw driver
- * @cdriver: driver to be deregistered
- *
- * This function is mainly a wrapper around driver_unregister().
- */
-void ccw_driver_unregister(struct ccw_driver *cdriver)
+void
+ccw_driver_unregister (struct ccw_driver *cdriver)
{
driver_unregister(&cdriver->driver);
}
diff --git a/trunk/drivers/s390/cio/device.h b/trunk/drivers/s390/cio/device.h
index 0d4089600439..b66338b76579 100644
--- a/trunk/drivers/s390/cio/device.h
+++ b/trunk/drivers/s390/cio/device.h
@@ -80,6 +80,7 @@ void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
void ccw_device_do_unreg_rereg(struct work_struct *);
+void ccw_device_call_sch_unregister(struct work_struct *);
void ccw_device_move_to_orphanage(struct work_struct *);
int ccw_device_is_orphan(struct ccw_device *);
diff --git a/trunk/drivers/s390/cio/device_fsm.c b/trunk/drivers/s390/cio/device_fsm.c
index 8867443b8060..8633dc537695 100644
--- a/trunk/drivers/s390/cio/device_fsm.c
+++ b/trunk/drivers/s390/cio/device_fsm.c
@@ -446,8 +446,7 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
if (cdev->private->pgid[last].inf.ps.state1 ==
SNID_STATE1_RESET)
/* No previous pgid found */
- memcpy(&cdev->private->pgid[0],
- &channel_subsystems[0]->global_pgid,
+ memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
sizeof(struct pgid));
else
/* Use existing pgid */
@@ -544,6 +543,51 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
}
+static void
+ccw_device_nopath_notify(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+ struct subchannel *sch;
+ int ret;
+ unsigned long flags;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ sch = to_subchannel(cdev->dev.parent);
+ /* Extra sanity. */
+ if (sch->lpm)
+ goto out_unlock;
+ if (sch->driver && sch->driver->notify) {
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ } else
+ ret = 0;
+ if (!ret) {
+ if (get_device(&sch->dev)) {
+ /* Driver doesn't want to keep device. */
+ cio_disable_subchannel(sch);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister);
+ queue_work(ccw_device_work,
+ &cdev->private->kick_work);
+ } else
+ put_device(&sch->dev);
+ }
+ } else {
+ cio_disable_subchannel(sch);
+ ccw_device_set_timeout(cdev, 0);
+ cdev->private->flags.fake_irb = 0;
+ cdev->private->state = DEV_STATE_DISCONNECTED;
+ wake_up(&cdev->private->wait_q);
+ }
+out_unlock:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+}
+
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
@@ -587,9 +631,12 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
default:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
- if (cdev->online)
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- else
+ if (cdev->online) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_nopath_notify);
+ queue_work(ccw_device_notify_work,
+ &cdev->private->kick_work);
+ } else
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -643,7 +690,11 @@ ccw_device_disband_done(struct ccw_device *cdev, int err)
break;
default:
cdev->private->flags.donotify = 0;
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -714,16 +765,59 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
}
/*
- * Handle not operational event in non-special state.
+ * Handle not operational event while offline.
*/
-static void ccw_device_generic_notoper(struct ccw_device *cdev,
- enum dev_event dev_event)
+static void
+ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
cdev->private->state = DEV_STATE_NOT_OPER;
sch = to_subchannel(cdev->dev.parent);
- css_schedule_eval(sch->schid);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ wake_up(&cdev->private->wait_q);
+}
+
+/*
+ * Handle not operational event while online.
+ */
+static void
+ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+{
+ struct subchannel *sch;
+ int ret;
+
+ sch = to_subchannel(cdev->dev.parent);
+ if (sch->driver->notify) {
+ spin_unlock_irq(cdev->ccwlock);
+ ret = sch->driver->notify(&sch->dev,
+ sch->lpm ? CIO_GONE : CIO_NO_PATH);
+ spin_lock_irq(cdev->ccwlock);
+ } else
+ ret = 0;
+ if (ret) {
+ ccw_device_set_timeout(cdev, 0);
+ cdev->private->flags.fake_irb = 0;
+ cdev->private->state = DEV_STATE_DISCONNECTED;
+ wake_up(&cdev->private->wait_q);
+ return;
+ }
+ cdev->private->state = DEV_STATE_NOT_OPER;
+ cio_disable_subchannel(sch);
+ if (sch->schib.scsw.actl != 0) {
+ // FIXME: not-oper indication to device driver ?
+ ccw_device_call_handler(cdev);
+ }
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ wake_up(&cdev->private->wait_q);
}
/*
@@ -821,9 +915,18 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
cdev->private->state = DEV_STATE_TIMEOUT_KILL;
return;
}
- if (ret == -ENODEV)
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- else if (cdev->handler)
+ if (ret == -ENODEV) {
+ struct subchannel *sch;
+
+ sch = to_subchannel(cdev->dev.parent);
+ if (!sch->lpm) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_nopath_notify);
+ queue_work(ccw_device_notify_work,
+ &cdev->private->kick_work);
+ } else
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ } else if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-ETIMEDOUT));
}
@@ -1130,7 +1233,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_SENSE_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
@@ -1142,50 +1245,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_OFFLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_ONLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_online_timeout,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_W4SENSE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_w4sense,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_DISBAND_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_disband_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_BOXED] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_stlck_done,
[DEV_EVENT_TIMEOUT] = ccw_device_stlck_done,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
/* states to wait for i/o completion before doing something */
[DEV_STATE_CLEAR_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_clear_verify,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_TIMEOUT_KILL] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
diff --git a/trunk/drivers/s390/cio/device_ops.c b/trunk/drivers/s390/cio/device_ops.c
index 7fd2dadc3297..14eba854b155 100644
--- a/trunk/drivers/s390/cio/device_ops.c
+++ b/trunk/drivers/s390/cio/device_ops.c
@@ -25,16 +25,6 @@
#include "device.h"
#include "chp.h"
-/**
- * ccw_device_set_options_mask() - set some options and unset the rest
- * @cdev: device for which the options are to be set
- * @flags: options to be set
- *
- * All flags specified in @flags are set, all flags not specified in @flags
- * are cleared.
- * Returns:
- * %0 on success, -%EINVAL on an invalid flag combination.
- */
int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -50,15 +40,6 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
return 0;
}
-/**
- * ccw_device_set_options() - set some options
- * @cdev: device for which the options are to be set
- * @flags: options to be set
- *
- * All flags specified in @flags are set, the remainder is left untouched.
- * Returns:
- * %0 on success, -%EINVAL if an invalid flag combination would ensue.
- */
int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -78,13 +59,6 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
return 0;
}
-/**
- * ccw_device_clear_options() - clear some options
- * @cdev: device for which the options are to be cleared
- * @flags: options to be cleared
- *
- * All flags specified in @flags are cleared, the remainder is left untouched.
- */
void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
{
cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -93,22 +67,8 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
}
-/**
- * ccw_device_clear() - terminate I/O request processing
- * @cdev: target ccw device
- * @intparm: interruption parameter; value is only used if no I/O is
- * outstanding, otherwise the intparm associated with the I/O request
- * is returned
- *
- * ccw_device_clear() calls csch on @cdev's subchannel.
- * Returns:
- * %0 on success,
- * -%ENODEV on device not operational,
- * -%EINVAL on invalid device state.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+int
+ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -129,33 +89,10 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-/**
- * ccw_device_start_key() - start a s390 channel program with key
- * @cdev: target ccw device
- * @cpa: logical start address of channel program
- * @intparm: user specific interruption parameter; will be presented back to
- * @cdev's interrupt handler. Allows a device driver to associate
- * the interrupt with a particular I/O request.
- * @lpm: defines the channel path to be used for a specific I/O request. A
- * value of 0 will make cio use the opm.
- * @key: storage key to be used for the I/O
- * @flags: additional flags; defines the action to be performed for I/O
- * processing.
- *
- * Start a S/390 channel program. When the interrupt arrives, the
- * IRQ handler is called, either immediately, delayed (dev-end missing,
- * or sense required) or never (no IRQ handler registered).
- * Returns:
- * %0, if the operation was successful;
- * -%EBUSY, if the device is busy, or status pending;
- * -%EACCES, if no path specified in @lpm is operational;
- * -%ENODEV, if the device is not operational.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags)
+int
+ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags)
{
struct subchannel *sch;
int ret;
@@ -198,38 +135,11 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-/**
- * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
- * @cdev: target ccw device
- * @cpa: logical start address of channel program
- * @intparm: user specific interruption parameter; will be presented back to
- * @cdev's interrupt handler. Allows a device driver to associate
- * the interrupt with a particular I/O request.
- * @lpm: defines the channel path to be used for a specific I/O request. A
- * value of 0 will make cio use the opm.
- * @key: storage key to be used for the I/O
- * @flags: additional flags; defines the action to be performed for I/O
- * processing.
- * @expires: timeout value in jiffies
- *
- * Start a S/390 channel program. When the interrupt arrives, the
- * IRQ handler is called, either immediately, delayed (dev-end missing,
- * or sense required) or never (no IRQ handler registered).
- * This function notifies the device driver if the channel program has not
- * completed during the time specified by @expires. If a timeout occurs, the
- * channel program is terminated via xsch, hsch or csch, and the device's
- * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
- * Returns:
- * %0, if the operation was successful;
- * -%EBUSY, if the device is busy, or status pending;
- * -%EACCES, if no path specified in @lpm is operational;
- * -%ENODEV, if the device is not operational.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags, int expires)
+
+int
+ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags, int expires)
{
int ret;
@@ -242,67 +152,18 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-/**
- * ccw_device_start() - start a s390 channel program
- * @cdev: target ccw device
- * @cpa: logical start address of channel program
- * @intparm: user specific interruption parameter; will be presented back to
- * @cdev's interrupt handler. Allows a device driver to associate
- * the interrupt with a particular I/O request.
- * @lpm: defines the channel path to be used for a specific I/O request. A
- * value of 0 will make cio use the opm.
- * @flags: additional flags; defines the action to be performed for I/O
- * processing.
- *
- * Start a S/390 channel program. When the interrupt arrives, the
- * IRQ handler is called, either immediately, delayed (dev-end missing,
- * or sense required) or never (no IRQ handler registered).
- * Returns:
- * %0, if the operation was successful;
- * -%EBUSY, if the device is busy, or status pending;
- * -%EACCES, if no path specified in @lpm is operational;
- * -%ENODEV, if the device is not operational.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags)
+int
+ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, unsigned long flags)
{
return ccw_device_start_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags);
}
-/**
- * ccw_device_start_timeout() - start a s390 channel program with timeout
- * @cdev: target ccw device
- * @cpa: logical start address of channel program
- * @intparm: user specific interruption parameter; will be presented back to
- * @cdev's interrupt handler. Allows a device driver to associate
- * the interrupt with a particular I/O request.
- * @lpm: defines the channel path to be used for a specific I/O request. A
- * value of 0 will make cio use the opm.
- * @flags: additional flags; defines the action to be performed for I/O
- * processing.
- * @expires: timeout value in jiffies
- *
- * Start a S/390 channel program. When the interrupt arrives, the
- * IRQ handler is called, either immediately, delayed (dev-end missing,
- * or sense required) or never (no IRQ handler registered).
- * This function notifies the device driver if the channel program has not
- * completed during the time specified by @expires. If a timeout occurs, the
- * channel program is terminated via xsch, hsch or csch, and the device's
- * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
- * Returns:
- * %0, if the operation was successful;
- * -%EBUSY, if the device is busy, or status pending;
- * -%EACCES, if no path specified in @lpm is operational;
- * -%ENODEV, if the device is not operational.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm,
- unsigned long flags, int expires)
+int
+ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, unsigned long flags,
+ int expires)
{
return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags,
@@ -310,23 +171,8 @@ int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
}
-/**
- * ccw_device_halt() - halt I/O request processing
- * @cdev: target ccw device
- * @intparm: interruption parameter; value is only used if no I/O is
- * outstanding, otherwise the intparm associated with the I/O request
- * is returned
- *
- * ccw_device_halt() calls hsch on @cdev's subchannel.
- * Returns:
- * %0 on success,
- * -%ENODEV on device not operational,
- * -%EINVAL on invalid device state,
- * -%EBUSY on device busy or interrupt pending.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+int
+ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -347,20 +193,8 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-/**
- * ccw_device_resume() - resume channel program execution
- * @cdev: target ccw device
- *
- * ccw_device_resume() calls rsch on @cdev's subchannel.
- * Returns:
- * %0 on success,
- * -%ENODEV on device not operational,
- * -%EINVAL on invalid device state,
- * -%EBUSY on device busy or interrupt pending.
- * Context:
- * Interrupts disabled, ccw device lock held
- */
-int ccw_device_resume(struct ccw_device *cdev)
+int
+ccw_device_resume(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -426,21 +260,11 @@ ccw_device_call_handler(struct ccw_device *cdev)
return 1;
}
-/**
- * ccw_device_get_ciw() - Search for CIW command in extended sense data.
- * @cdev: ccw device to inspect
- * @ct: command type to look for
- *
- * During SenseID, command information words (CIWs) describing special
- * commands available to the device may have been stored in the extended
- * sense data. This function searches for CIWs of a specified command
- * type in the extended sense data.
- * Returns:
- * %NULL if no extended sense data has been stored or if no CIW of the
- * specified command type could be found,
- * else a pointer to the CIW of the specified command type.
+/*
+ * Search for CIW command in extended sense data.
*/
-struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *
+ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
{
int ciw_cnt;
@@ -452,14 +276,8 @@ struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
return NULL;
}
-/**
- * ccw_device_get_path_mask() - get currently available paths
- * @cdev: ccw device to be queried
- * Returns:
- * %0 if no subchannel for the device is available,
- * else the mask of currently available paths for the ccw device's subchannel.
- */
-__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
+__u8
+ccw_device_get_path_mask(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -539,7 +357,8 @@ ccw_device_stlck(struct ccw_device *cdev)
return ret;
}
-void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *
+ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
{
struct subchannel *sch;
struct chp_id chpid;
diff --git a/trunk/drivers/s390/cio/qdio.c b/trunk/drivers/s390/cio/qdio.c
index 40a3208c7cf3..d8d479876ec7 100644
--- a/trunk/drivers/s390/cio/qdio.c
+++ b/trunk/drivers/s390/cio/qdio.c
@@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q)
}
static void
-qdio_outbound_processing(unsigned long q)
+qdio_outbound_processing(struct qdio_q *q)
{
- __qdio_outbound_processing((struct qdio_q *) q);
+ __qdio_outbound_processing(q);
}
/************************* INBOUND ROUTINES *******************************/
@@ -1449,10 +1449,9 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
}
static void
-tiqdio_inbound_processing(unsigned long q)
+tiqdio_inbound_processing(struct qdio_q *q)
{
- __tiqdio_inbound_processing((struct qdio_q *) q,
- atomic_read(&spare_indicator_usecount));
+ __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
}
static void
@@ -1495,9 +1494,9 @@ __qdio_inbound_processing(struct qdio_q *q)
}
static void
-qdio_inbound_processing(unsigned long q)
+qdio_inbound_processing(struct qdio_q *q)
{
- __qdio_inbound_processing((struct qdio_q *) q);
+ __qdio_inbound_processing(q);
}
/************************* MAIN ROUTINES *******************************/
@@ -1761,15 +1760,12 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->handler=input_handler;
q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
+ q->tasklet.data=(unsigned long)q;
/* q->is_thinint_q isn't valid at this time, but
- * irq_ptr->is_thinint_irq is
- */
- if (irq_ptr->is_thinint_irq)
- tasklet_init(&q->tasklet, tiqdio_inbound_processing,
- (unsigned long) q);
- else
- tasklet_init(&q->tasklet, qdio_inbound_processing,
- (unsigned long) q);
+ * irq_ptr->is_thinint_irq is */
+ q->tasklet.func=(void(*)(unsigned long))
+ ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
+ &qdio_inbound_processing);
/* actually this is not used for inbound queues. yet. */
atomic_set(&q->busy_siga_counter,0);
@@ -1840,10 +1836,13 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->last_move_ftc=0;
q->handler=output_handler;
- tasklet_init(&q->tasklet, qdio_outbound_processing,
- (unsigned long) q);
- setup_timer(&q->timer, qdio_outbound_processing,
- (unsigned long) q);
+ q->tasklet.data=(unsigned long)q;
+ q->tasklet.func=(void(*)(unsigned long))
+ &qdio_outbound_processing;
+ q->timer.function=(void(*)(unsigned long))
+ &qdio_outbound_processing;
+ q->timer.data = (long)q;
+ init_timer(&q->timer);
atomic_set(&q->busy_siga_counter,0);
q->timing.busy_start=0;
@@ -3727,7 +3726,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count
#endif /* CONFIG_64BIT */
}
} else {
- QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
+ QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c
index d334b0f7a1ec..90bd22014513 100644
--- a/trunk/drivers/s390/crypto/ap_bus.c
+++ b/trunk/drivers/s390/crypto/ap_bus.c
@@ -1231,9 +1231,8 @@ static void ap_reset_domain(void)
{
int i;
- if (ap_domain_index != -1)
- for (i = 0; i < AP_DEVICES; i++)
- ap_reset_queue(AP_MKQID(i, ap_domain_index));
+ for (i = 0; i < AP_DEVICES; i++)
+ ap_reset_queue(AP_MKQID(i, ap_domain_index));
}
static void ap_reset_all(void)
diff --git a/trunk/drivers/s390/crypto/zcrypt_mono.c b/trunk/drivers/s390/crypto/zcrypt_mono.c
index 44253fdd4136..2a9349ad68b7 100644
--- a/trunk/drivers/s390/crypto/zcrypt_mono.c
+++ b/trunk/drivers/s390/crypto/zcrypt_mono.c
@@ -45,7 +45,7 @@
/**
* The module initialization code.
*/
-static int __init zcrypt_init(void)
+int __init zcrypt_init(void)
{
int rc;
@@ -86,7 +86,7 @@ static int __init zcrypt_init(void)
/**
* The module termination code.
*/
-static void __exit zcrypt_exit(void)
+void __exit zcrypt_exit(void)
{
zcrypt_cex2a_exit();
zcrypt_pcixcc_exit();
diff --git a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c
index 70b9ddc8cf9d..64948788d301 100644
--- a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
};
struct {
struct type6_hdr hdr;
- struct CPRBX cprbx;
+ struct ica_CPRBX cprbx;
} __attribute__((packed)) *msg = ap_msg->message;
int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,17 +432,14 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
}
if (service_rc == 8 && service_rs == 770) {
PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
- return -EINVAL;
+ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+ return -EAGAIN;
}
if (service_rc == 8 && service_rs == 783) {
PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
return -EAGAIN;
}
- if (service_rc == 12 && service_rs == 769) {
- PDEBUG("Invalid key on PCIXCC/CEX2C\n");
- return -EINVAL;
- }
PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
service_rc, service_rs);
zdev->online = 0;
diff --git a/trunk/drivers/s390/crypto/zcrypt_pcixcc.h b/trunk/drivers/s390/crypto/zcrypt_pcixcc.h
index 8cb7d7a6973b..a78ff307fd19 100644
--- a/trunk/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/trunk/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -28,6 +28,51 @@
#ifndef _ZCRYPT_PCIXCC_H_
#define _ZCRYPT_PCIXCC_H_
+/**
+ * CPRBX
+ * Note that all shorts and ints are big-endian.
+ * All pointer fields are 16 bytes long, and mean nothing.
+ *
+ * A request CPRB is followed by a request_parameter_block.
+ *
+ * The request (or reply) parameter block is organized thus:
+ * function code
+ * VUD block
+ * key block
+ */
+struct CPRBX {
+ unsigned short cprb_len; /* CPRB length 220 */
+ unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
+ unsigned char pad_000[3]; /* Alignment pad bytes */
+ unsigned char func_id[2]; /* function id 0x5432 */
+ unsigned char cprb_flags[4]; /* Flags */
+ unsigned int req_parml; /* request parameter buffer len */
+ unsigned int req_datal; /* request data buffer */
+ unsigned int rpl_msgbl; /* reply message block length */
+ unsigned int rpld_parml; /* replied parameter block len */
+ unsigned int rpl_datal; /* reply data block len */
+ unsigned int rpld_datal; /* replied data block len */
+ unsigned int req_extbl; /* request extension block len */
+ unsigned char pad_001[4]; /* reserved */
+ unsigned int rpld_extbl; /* replied extension block len */
+ unsigned char req_parmb[16]; /* request parm block 'address' */
+ unsigned char req_datab[16]; /* request data block 'address' */
+ unsigned char rpl_parmb[16]; /* reply parm block 'address' */
+ unsigned char rpl_datab[16]; /* reply data block 'address' */
+ unsigned char req_extb[16]; /* request extension block 'addr'*/
+ unsigned char rpl_extb[16]; /* reply extension block 'addres'*/
+ unsigned short ccp_rtcode; /* server return code */
+ unsigned short ccp_rscode; /* server reason code */
+ unsigned int mac_data_len; /* Mac Data Length */
+ unsigned char logon_id[8]; /* Logon Identifier */
+ unsigned char mac_value[8]; /* Mac Value */
+ unsigned char mac_content_flgs;/* Mac content flag byte */
+ unsigned char pad_002; /* Alignment */
+ unsigned short domain; /* Domain */
+ unsigned char pad_003[12]; /* Domain masks */
+ unsigned char pad_004[36]; /* reserved */
+} __attribute__((packed));
+
int zcrypt_pcixcc_init(void);
void zcrypt_pcixcc_exit(void);
diff --git a/trunk/drivers/s390/scsi/zfcp_ccw.c b/trunk/drivers/s390/scsi/zfcp_ccw.c
index c0d1c0eb3209..1c8f71a59855 100644
--- a/trunk/drivers/s390/scsi/zfcp_ccw.c
+++ b/trunk/drivers/s390/scsi/zfcp_ccw.c
@@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *);
static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct ccw_device *);
+static void zfcp_ccw_shutdown(struct device *);
static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,7 +51,9 @@ static struct ccw_driver zfcp_ccw_driver = {
.set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
- .shutdown = zfcp_ccw_shutdown,
+ .driver = {
+ .shutdown = zfcp_ccw_shutdown,
+ },
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -275,12 +277,12 @@ zfcp_ccw_register(void)
* Makes sure that QDIO queues are down when the system gets stopped.
*/
static void
-zfcp_ccw_shutdown(struct ccw_device *cdev)
+zfcp_ccw_shutdown(struct device *dev)
{
struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema);
- adapter = dev_get_drvdata(&cdev->dev);
+ adapter = dev_get_drvdata(dev);
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema);
diff --git a/trunk/drivers/s390/scsi/zfcp_dbf.c b/trunk/drivers/s390/scsi/zfcp_dbf.c
index ffa3bf756943..5f3212440f68 100644
--- a/trunk/drivers/s390/scsi/zfcp_dbf.c
+++ b/trunk/drivers/s390/scsi/zfcp_dbf.c
@@ -19,8 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include
#include
+#include
#include "zfcp_ext.h"
static u32 dbfsize = 4;
@@ -35,17 +35,17 @@ static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
- struct timespec dbftime;
+ struct timespec xtime;
int len = 0;
stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
sec = stck >> 12;
do_div(sec, 1000000);
- dbftime.tv_sec = sec;
+ xtime.tv_sec = sec;
stck -= (sec * 1000000) << 12;
- dbftime.tv_nsec = ((stck * 1000) >> 12);
+ xtime.tv_nsec = ((stck * 1000) >> 12);
len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
- label, dbftime.tv_sec, dbftime.tv_nsec);
+ label, xtime.tv_sec, xtime.tv_nsec);
return len;
}
diff --git a/trunk/drivers/s390/scsi/zfcp_erp.c b/trunk/drivers/s390/scsi/zfcp_erp.c
index 16b4418ab257..d8cd75ce2d9a 100644
--- a/trunk/drivers/s390/scsi/zfcp_erp.c
+++ b/trunk/drivers/s390/scsi/zfcp_erp.c
@@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int);
static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
-static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
@@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
static void zfcp_erp_action_ready(struct zfcp_erp_action *);
static int zfcp_erp_action_exists(struct zfcp_erp_action *);
-static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
static void zfcp_erp_memwait_handler(unsigned long);
@@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data)
* action gets an appropriate flag and will be processed
* accordingly
*/
-static void zfcp_erp_timeout_handler(unsigned long data)
+void zfcp_erp_timeout_handler(unsigned long data)
{
struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action,
return retval;
}
-static int
+static inline int
zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
{
return
@@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
* returns: 0 - successful setup
* !0 - failed setup
*/
-static int
+int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{
int retval;
@@ -3248,7 +3248,8 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
zfcp_erp_action_dismiss(&unit->erp_action);
}
-static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static inline void
+zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -3257,7 +3258,8 @@ static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
}
-static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static inline void
+zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
diff --git a/trunk/drivers/usb/Makefile b/trunk/drivers/usb/Makefile
index 516a6400db43..ac49b15fa768 100644
--- a/trunk/drivers/usb/Makefile
+++ b/trunk/drivers/usb/Makefile
@@ -28,7 +28,27 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
-obj-$(CONFIG_USB) += misc/
+obj-$(CONFIG_USB_ADUTUX) += misc/
+obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
+obj-$(CONFIG_USB_AUERSWALD) += misc/
+obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
+obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
+obj-$(CONFIG_USB_CYTHERM) += misc/
+obj-$(CONFIG_USB_EMI26) += misc/
+obj-$(CONFIG_USB_EMI62) += misc/
+obj-$(CONFIG_USB_FTDI_ELAN) += misc/
+obj-$(CONFIG_USB_IDMOUSE) += misc/
+obj-$(CONFIG_USB_LCD) += misc/
+obj-$(CONFIG_USB_LD) += misc/
+obj-$(CONFIG_USB_LED) += misc/
+obj-$(CONFIG_USB_LEGOTOWER) += misc/
+obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
+obj-$(CONFIG_USB_RIO500) += misc/
+obj-$(CONFIG_USB_SISUSBVGA) += misc/
+obj-$(CONFIG_USB_TEST) += misc/
+obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
+obj-$(CONFIG_USB_USS720) += misc/
+obj-$(CONFIG_USB_IOWARRIOR) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/trunk/drivers/usb/atm/cxacru.c b/trunk/drivers/usb/atm/cxacru.c
index a51eeedc18d4..a73e714288e5 100644
--- a/trunk/drivers/usb/atm/cxacru.c
+++ b/trunk/drivers/usb/atm/cxacru.c
@@ -482,9 +482,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
- wbuflen, rbuflen);
+ dbg("too big transfer requested");
ret = -ENOMEM;
goto fail;
}
@@ -495,9 +493,8 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
- cm, ret);
+ dbg("submitting read urb for cm %#x failed", cm);
+ ret = ret;
goto fail;
}
@@ -513,29 +510,27 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
- cm, ret);
+ dbg("submitting write urb for cm %#x failed", cm);
+ ret = ret;
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
+ dbg("sending cm %#x failed", cm);
+ ret = ret;
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
+ dbg("receiving cm %#x failed", cm);
+ ret = ret;
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
- cm, actlen);
+ dbg("response is not a positive multiple of %d: %#x",
+ CMD_PACKET_SIZE, actlen);
ret = -EIO;
goto fail;
}
@@ -543,16 +538,12 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
- rbuf[offb], cm);
+ dbg("wrong cm %#x in response", rbuf[offb]);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
- cm, rbuf[offb + 1]);
+ dbg("response failed: %#x", rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
@@ -591,18 +582,14 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
- cm, l);
+ dbg("wrong data length %#x in response", l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
- if (printk_ratelimit())
- usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
- offd, cm);
+ dbg("wrong index %#x in response", offd);
ret = -EIO;
goto cleanup;
}
diff --git a/trunk/drivers/usb/atm/speedtch.c b/trunk/drivers/usb/atm/speedtch.c
index 8b132c4a503b..eb0615abff68 100644
--- a/trunk/drivers/usb/atm/speedtch.c
+++ b/trunk/drivers/usb/atm/speedtch.c
@@ -251,6 +251,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
{
unsigned char *buffer;
struct usbatm_data *usbatm = instance->usbatm;
+ struct usb_interface *intf;
struct usb_device *usb_dev = usbatm->usb_dev;
int actual_length;
int ret = 0;
@@ -264,7 +265,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
goto out;
}
- if (!usb_ifnum_to_if(usb_dev, 2)) {
+ if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
ret = -ENODEV;
usb_dbg(usbatm, "%s: interface not found!\n", __func__);
goto out_free;
diff --git a/trunk/drivers/usb/atm/ueagle-atm.c b/trunk/drivers/usb/atm/ueagle-atm.c
index 389c5b164eb2..29807d048b04 100644
--- a/trunk/drivers/usb/atm/ueagle-atm.c
+++ b/trunk/drivers/usb/atm/ueagle-atm.c
@@ -2,8 +2,7 @@
* Copyright (c) 2003, 2004
* Damien Bergamini . All rights reserved.
*
- * Copyright (c) 2005-2007 Matthieu Castet
- * Copyright (c) 2005-2007 Stanislaw Gruszka
+ * Copyright (c) 2005 Matthieu Castet
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -108,51 +107,18 @@
#define uea_info(usb_dev, format,args...) \
dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
-struct intr_pkt;
-
-/* cmv's from firmware */
-struct uea_cmvs_v1 {
+struct uea_cmvs {
u32 address;
u16 offset;
u32 data;
} __attribute__ ((packed));
-struct uea_cmvs_v2 {
- u32 group;
- u32 address;
- u32 offset;
- u32 data;
-} __attribute__ ((packed));
-
-/* information about currently processed cmv */
-struct cmv_dsc_e1 {
- u8 function;
- u16 idx;
- u32 address;
- u16 offset;
-};
-
-struct cmv_dsc_e4 {
- u16 function;
- u16 offset;
- u16 address;
- u16 group;
-};
-
-union cmv_dsc {
- struct cmv_dsc_e1 e1;
- struct cmv_dsc_e4 e4;
-};
-
struct uea_softc {
struct usb_device *usb_dev;
struct usbatm_data *usbatm;
int modem_index;
unsigned int driver_info;
- int annex;
-#define ANNEXA 0
-#define ANNEXB 1
int booting;
int reset;
@@ -161,23 +127,20 @@ struct uea_softc {
struct task_struct *kthread;
u32 data;
- u32 data1;
-
+ wait_queue_head_t cmv_ack_wait;
int cmv_ack;
- union cmv_dsc cmv_dsc;
struct work_struct task;
- struct workqueue_struct *work_q;
u16 pageno;
u16 ovl;
const struct firmware *dsp_firm;
struct urb *urb_int;
- void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
- void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
- int (*stat) (struct uea_softc *);
- int (*send_cmvs) (struct uea_softc *);
+ u8 cmv_function;
+ u16 cmv_idx;
+ u32 cmv_address;
+ u16 cmv_offset;
/* keep in sync with eaglectl */
struct uea_stats {
@@ -211,34 +174,10 @@ struct uea_softc {
#define ELSA_PID_PSTFIRM 0x3350
#define ELSA_PID_PREFIRM 0x3351
-#define ELSA_PID_A_PREFIRM 0x3352
-#define ELSA_PID_A_PSTFIRM 0x3353
-#define ELSA_PID_B_PREFIRM 0x3362
-#define ELSA_PID_B_PSTFIRM 0x3363
-
/*
- * Devolo IDs : pots if (pid & 0x10)
+ * Sagem USB IDs
*/
-#define DEVOLO_VID 0x1039
-#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110
-#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111
-
-#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100
-#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101
-
-#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130
-#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131
-
-#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120
-#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121
-
-/*
- * Reference design USB IDs
- */
-#define ANALOG_VID 0x1110
-#define ADI930_PID_PREFIRM 0x9001
-#define ADI930_PID_PSTFIRM 0x9000
-
+#define EAGLE_VID 0x1110
#define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */
#define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */
@@ -248,12 +187,12 @@ struct uea_softc {
#define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */
#define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */
+/*
+ * Eagle III Pid
+ */
#define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */
#define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */
-#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */
-#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */
-
/*
* USR USB IDs
*/
@@ -269,15 +208,11 @@ struct uea_softc {
#define PREFIRM 0
#define PSTFIRM (1<<7)
-#define AUTO_ANNEX_A (1<<8)
-#define AUTO_ANNEX_B (1<<9)
-
enum {
ADI930 = 0,
EAGLE_I,
EAGLE_II,
- EAGLE_III,
- EAGLE_IV
+ EAGLE_III
};
/* macros for both struct usb_device_id and struct uea_softc */
@@ -286,18 +221,15 @@ enum {
#define UEA_CHIP_VERSION(x) \
((x)->driver_info & 0xf)
-#define IS_ISDN(x) \
- ((x)->annex & ANNEXB)
+#define IS_ISDN(usb_dev) \
+ (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
#define INS_TO_USBDEV(ins) ins->usb_dev
#define GET_STATUS(data) \
((data >> 8) & 0xf)
-
#define IS_OPERATIONAL(sc) \
- ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
- (GET_STATUS(sc->stats.phy.state) == 2) : \
- (sc->stats.phy.state == 7))
+ (GET_STATUS(sc->stats.phy.state) == 2)
/*
* Set of macros to handle unaligned data in the firmware blob.
@@ -327,8 +259,7 @@ enum {
#define UEA_INTR_PIPE 0x04
#define UEA_ISO_DATA_PIPE 0x08
-#define UEA_E1_SET_BLOCK 0x0001
-#define UEA_E4_SET_BLOCK 0x002c
+#define UEA_SET_BLOCK 0x0001
#define UEA_SET_MODE 0x0003
#define UEA_SET_2183_DATA 0x0004
#define UEA_SET_TIMEOUT 0x0011
@@ -344,179 +275,71 @@ enum {
#define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000)
#define UEA_MPRX_MAILBOX (0x3fdf | 0x4000)
-/* block information in eagle4 dsp firmware */
-struct block_index {
- __le32 PageOffset;
- __le32 NotLastBlock;
- __le32 dummy;
- __le32 PageSize;
- __le32 PageAddress;
- __le16 dummy1;
- __le16 PageNumber;
-} __attribute__ ((packed));
-
-#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
-#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
-
-#define E4_L1_STRING_HEADER 0x10
-#define E4_MAX_PAGE_NUMBER 0x58
-#define E4_NO_SWAPPAGE_HEADERS 0x31
-
-/* l1_code is eagle4 dsp firmware format */
-struct l1_code {
- u8 string_header[E4_L1_STRING_HEADER];
- u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
- struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
- u8 code [0];
-} __attribute__ ((packed));
-
-/* structures describing a block within a DSP page */
-struct block_info_e1 {
+/* structure describing a block within a DSP page */
+struct block_info {
__le16 wHdr;
+#define UEA_BIHDR 0xabcd
__le16 wAddress;
__le16 wSize;
__le16 wOvlOffset;
__le16 wOvl; /* overlay */
__le16 wLast;
} __attribute__ ((packed));
-#define E1_BLOCK_INFO_SIZE 12
-
-struct block_info_e4 {
- __be16 wHdr;
- __u8 bBootPage;
- __u8 bPageNumber;
- __be32 dwSize;
- __be32 dwAddress;
- __be16 wReserved;
-} __attribute__ ((packed));
-#define E4_BLOCK_INFO_SIZE 14
-
-#define UEA_BIHDR 0xabcd
-#define UEA_RESERVED 0xffff
-
-/* constants describing cmv type */
-#define E1_PREAMBLE 0x535c
-#define E1_MODEMTOHOST 0x01
-#define E1_HOSTTOMODEM 0x10
+#define BLOCK_INFO_SIZE 12
-#define E1_MEMACCESS 0x1
-#define E1_ADSLDIRECTIVE 0x7
-#define E1_FUNCTION_TYPE(f) ((f) >> 4)
-#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
-
-#define E4_MEMACCESS 0
-#define E4_ADSLDIRECTIVE 0xf
-#define E4_FUNCTION_TYPE(f) ((f) >> 8)
-#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
-#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
+/* structure representing a CMV (Configuration and Management Variable) */
+struct cmv {
+ __le16 wPreamble;
+#define PREAMBLE 0x535c
+ __u8 bDirection;
+#define MODEMTOHOST 0x01
+#define HOSTTOMODEM 0x10
+ __u8 bFunction;
+#define FUNCTION_TYPE(f) ((f) >> 4)
+#define MEMACCESS 0x1
+#define ADSLDIRECTIVE 0x7
+#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
/* for MEMACCESS */
-#define E1_REQUESTREAD 0x0
-#define E1_REQUESTWRITE 0x1
-#define E1_REPLYREAD 0x2
-#define E1_REPLYWRITE 0x3
-
-#define E4_REQUESTREAD 0x0
-#define E4_REQUESTWRITE 0x4
-#define E4_REPLYREAD (E4_REQUESTREAD | 1)
-#define E4_REPLYWRITE (E4_REQUESTWRITE | 1)
-
+#define REQUESTREAD 0x0
+#define REQUESTWRITE 0x1
+#define REPLYREAD 0x2
+#define REPLYWRITE 0x3
/* for ADSLDIRECTIVE */
-#define E1_KERNELREADY 0x0
-#define E1_MODEMREADY 0x1
-
-#define E4_KERNELREADY 0x0
-#define E4_MODEMREADY 0x1
+#define KERNELREADY 0x0
+#define MODEMREADY 0x1
-#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
-#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
-
-#define E1_MAKESA(a, b, c, d) \
+#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+ __le16 wIndex;
+ __le32 dwSymbolicAddress;
+#define MAKESA(a, b, c, d) \
(((c) & 0xff) << 24 | \
((d) & 0xff) << 16 | \
((a) & 0xff) << 8 | \
((b) & 0xff))
-
-#define E1_GETSA1(a) ((a >> 8) & 0xff)
-#define E1_GETSA2(a) (a & 0xff)
-#define E1_GETSA3(a) ((a >> 24) & 0xff)
-#define E1_GETSA4(a) ((a >> 16) & 0xff)
-
-#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
-#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
-#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
-#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
-#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
-#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
-
-#define E4_SA_CNTL 1
-#define E4_SA_STAT 2
-#define E4_SA_INFO 3
-#define E4_SA_TEST 4
-#define E4_SA_OPTN 5
-#define E4_SA_RATE 6
-#define E4_SA_DIAG 7
-#define E4_SA_CNFG 8
-
-/* structures representing a CMV (Configuration and Management Variable) */
-struct cmv_e1 {
- __le16 wPreamble;
- __u8 bDirection;
- __u8 bFunction;
- __le16 wIndex;
- __le32 dwSymbolicAddress;
+#define GETSA1(a) ((a >> 8) & 0xff)
+#define GETSA2(a) (a & 0xff)
+#define GETSA3(a) ((a >> 24) & 0xff)
+#define GETSA4(a) ((a >> 16) & 0xff)
+
+#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
+#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
+#define SA_INFO MAKESA('I', 'N', 'F', 'O')
+#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
+#define SA_RATE MAKESA('R', 'A', 'T', 'E')
+#define SA_STAT MAKESA('S', 'T', 'A', 'T')
__le16 wOffsetAddress;
__le32 dwData;
} __attribute__ ((packed));
+#define CMV_SIZE 16
-struct cmv_e4 {
- __be16 wGroup;
- __be16 wFunction;
- __be16 wOffset;
- __be16 wAddress;
- __be32 dwData [6];
-} __attribute__ ((packed));
-
-/* structures representing swap information */
-struct swap_info_e1 {
+/* structure representing swap information */
+struct swap_info {
__u8 bSwapPageNo;
__u8 bOvl; /* overlay */
} __attribute__ ((packed));
-struct swap_info_e4 {
- __u8 bSwapPageNo;
-} __attribute__ ((packed));
-
-/* structures representing interrupt data */
-#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
-#define e1_bOvl u.e1.s1.swapinfo.bOvl
-#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo
-
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV 0x0002
-
-union intr_data_e1 {
- struct {
- struct swap_info_e1 swapinfo;
- __le16 wDataSize;
- } __attribute__ ((packed)) s1;
- struct {
- struct cmv_e1 cmv;
- __le16 wDataSize;
- } __attribute__ ((packed)) s2;
-} __attribute__ ((packed));
-
-union intr_data_e4 {
- struct {
- struct swap_info_e4 swapinfo;
- __le16 wDataSize;
- } __attribute__ ((packed)) s1;
- struct {
- struct cmv_e4 cmv;
- __le16 wDataSize;
- } __attribute__ ((packed)) s2;
-} __attribute__ ((packed));
-
+/* structure representing interrupt data */
struct intr_pkt {
__u8 bType;
__u8 bNotification;
@@ -524,48 +347,43 @@ struct intr_pkt {
__le16 wIndex;
__le16 wLength;
__le16 wInterrupt;
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV 0x0002
union {
- union intr_data_e1 e1;
- union intr_data_e4 e4;
- } u;
-} __attribute__ ((packed));
+ struct {
+ struct swap_info swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
-#define E1_INTR_PKT_SIZE 28
-#define E4_INTR_PKT_SIZE 64
+ struct {
+ struct cmv cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+ } __attribute__ ((packed)) u;
+#define bSwapPageNo u.s1.swapinfo.bSwapPageNo
+#define bOvl u.s1.swapinfo.bOvl
+} __attribute__ ((packed));
+#define INTR_PKT_SIZE 28
static struct usb_driver uea_driver;
static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
static int modem_index;
static unsigned int debug;
-static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
+static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
static int sync_wait[NB_MODEM];
static char *cmv_file[NB_MODEM];
-static int annex[NB_MODEM];
module_param(debug, uint, 0644);
MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(altsetting, uint, NULL, 0644);
-MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
- "1=isoc slowest, ... , 8=isoc fastest (default)");
+module_param_array(use_iso, bool, NULL, 0644);
+MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
module_param_array(sync_wait, bool, NULL, 0644);
MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
module_param_array(cmv_file, charp, NULL, 0644);
MODULE_PARM_DESC(cmv_file,
"file name with configuration and management variables");
-module_param_array(annex, uint, NULL, 0644);
-MODULE_PARM_DESC(annex,
- "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
-
-#define uea_wait(sc, cond, timeo) \
-({ \
- int _r = wait_event_interruptible_timeout(sc->sync_q, \
- (cond) || kthread_should_stop(), timeo); \
- if (kthread_should_stop()) \
- _r = -ENODEV; \
- _r; \
-})
#define UPDATE_ATM_STAT(type, val) \
do { \
@@ -701,9 +519,6 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
case EAGLE_III:
fw_name = FW_DIR "eagleIII.fw";
break;
- case EAGLE_IV:
- fw_name = FW_DIR "eagleIV.fw";
- break;
}
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -722,7 +537,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
/*
* Make sure that the DSP code provided is safe to use.
*/
-static int check_dsp_e1(u8 *dsp, unsigned int len)
+static int check_dsp(u8 *dsp, unsigned int len)
{
u8 pagecount, blockcount;
u16 blocksize;
@@ -773,51 +588,6 @@ static int check_dsp_e1(u8 *dsp, unsigned int len)
return 0;
}
-static int check_dsp_e4(u8 *dsp, int len)
-{
- int i;
- struct l1_code *p = (struct l1_code *) dsp;
- unsigned int sum = p->code - dsp;
-
- if (len < sum)
- return 1;
-
- if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
- strcmp("STRATIPHY ANEXB", p->string_header) != 0)
- return 1;
-
- for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
- struct block_index *blockidx;
- u8 blockno = p->page_number_to_block_index[i];
- if (blockno >= E4_NO_SWAPPAGE_HEADERS)
- continue;
-
- do {
- u64 l;
-
- if (blockno >= E4_NO_SWAPPAGE_HEADERS)
- return 1;
-
- blockidx = &p->page_header[blockno++];
- if ((u8 *)(blockidx + 1) - dsp >= len)
- return 1;
-
- if (le16_to_cpu(blockidx->PageNumber) != i)
- return 1;
-
- l = E4_PAGE_BYTES(blockidx->PageSize);
- sum += l;
- l += le32_to_cpu(blockidx->PageOffset);
- if (l > len)
- return 1;
-
- /* zero is zero regardless endianes */
- } while (blockidx->NotLastBlock);
- }
-
- return (sum == len) ? 0 : 1;
-}
-
/*
* send data to the idma pipe
* */
@@ -854,18 +624,13 @@ static int request_dsp(struct uea_softc *sc)
int ret;
char *dsp_name;
- if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
- if (IS_ISDN(sc))
- dsp_name = FW_DIR "DSP4i.bin";
- else
- dsp_name = FW_DIR "DSP4p.bin";
- } else if (UEA_CHIP_VERSION(sc) == ADI930) {
- if (IS_ISDN(sc))
+ if (UEA_CHIP_VERSION(sc) == ADI930) {
+ if (IS_ISDN(sc->usb_dev))
dsp_name = FW_DIR "DSP9i.bin";
else
dsp_name = FW_DIR "DSP9p.bin";
} else {
- if (IS_ISDN(sc))
+ if (IS_ISDN(sc->usb_dev))
dsp_name = FW_DIR "DSPei.bin";
else
dsp_name = FW_DIR "DSPep.bin";
@@ -875,16 +640,11 @@ static int request_dsp(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"requesting firmware %s failed with error %d\n",
- dsp_name, ret);
+ dsp_name, ret);
return ret;
}
- if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
- ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
- else
- ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
-
- if (ret) {
+ if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
dsp_name);
release_firmware(sc->dsp_firm);
@@ -898,12 +658,12 @@ static int request_dsp(struct uea_softc *sc)
/*
* The uea_load_page() function must be called within a process context
*/
-static void uea_load_page_e1(struct work_struct *work)
+static void uea_load_page(struct work_struct *work)
{
struct uea_softc *sc = container_of(work, struct uea_softc, task);
u16 pageno = sc->pageno;
u16 ovl = sc->ovl;
- struct block_info_e1 bi;
+ struct block_info bi;
u8 *p;
u8 pagecount, blockcount;
@@ -956,7 +716,7 @@ static void uea_load_page_e1(struct work_struct *work)
bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
/* send block info through the IDMA pipe */
- if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
+ if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
goto bad2;
/* send block data through the IDMA pipe */
@@ -975,114 +735,17 @@ static void uea_load_page_e1(struct work_struct *work)
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
}
-static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
-{
- struct block_info_e4 bi;
- struct block_index *blockidx;
- struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
- u8 blockno = p->page_number_to_block_index[pageno];
-
- bi.wHdr = cpu_to_be16(UEA_BIHDR);
- bi.bBootPage = boot;
- bi.bPageNumber = pageno;
- bi.wReserved = cpu_to_be16(UEA_RESERVED);
-
- do {
- u8 *blockoffset;
- unsigned int blocksize;
-
- blockidx = &p->page_header[blockno];
- blocksize = E4_PAGE_BYTES(blockidx->PageSize);
- blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
-
- bi.dwSize = cpu_to_be32(blocksize);
- bi.dwAddress = swab32(blockidx->PageAddress);
-
- uea_dbg(INS_TO_USBDEV(sc),
- "sending block %u for DSP page %u size %u adress %x\n",
- blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
-
- /* send block info through the IDMA pipe */
- if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
- goto bad;
-
- /* send block data through the IDMA pipe */
- if (uea_idma_write(sc, blockoffset, blocksize))
- goto bad;
-
- blockno++;
- } while (blockidx->NotLastBlock);
-
- return;
-
-bad:
- uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
- return;
-}
-
-static void uea_load_page_e4(struct work_struct *work)
-{
- struct uea_softc *sc = container_of(work, struct uea_softc, task);
- u8 pageno = sc->pageno;
- int i;
- struct block_info_e4 bi;
- struct l1_code *p;
-
- uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
-
- /* reload firmware when reboot start and it's loaded already */
- if (pageno == 0 && sc->dsp_firm) {
- release_firmware(sc->dsp_firm);
- sc->dsp_firm = NULL;
- }
-
- if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
- return;
-
- p = (struct l1_code *) sc->dsp_firm->data;
- if (pageno >= p->page_header[0].PageNumber) {
- uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
- return;
- }
-
- if (pageno != 0) {
- __uea_load_page_e4(sc, pageno, 0);
- return;
- }
-
- uea_dbg(INS_TO_USBDEV(sc),
- "sending Main DSP page %u\n", p->page_header[0].PageNumber);
-
- for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
- if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
- __uea_load_page_e4(sc, i, 1);
- }
-
- uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
-
- bi.wHdr = cpu_to_be16(UEA_BIHDR);
- bi.bBootPage = 0;
- bi.bPageNumber = 0xff;
- bi.wReserved = cpu_to_be16(UEA_RESERVED);
- bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
- bi.dwAddress = swab32(p->page_header[0].PageAddress);
-
- /* send block info through the IDMA pipe */
- if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
- uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
-}
-
static inline void wake_up_cmv_ack(struct uea_softc *sc)
{
BUG_ON(sc->cmv_ack);
sc->cmv_ack = 1;
- wake_up(&sc->sync_q);
+ wake_up(&sc->cmv_ack_wait);
}
static inline int wait_cmv_ack(struct uea_softc *sc)
{
- int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
-
+ int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
+ sc->cmv_ack, ACK_TIMEOUT);
sc->cmv_ack = 0;
uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -1129,68 +792,33 @@ static int uea_request(struct uea_softc *sc,
return 0;
}
-static int uea_cmv_e1(struct uea_softc *sc,
+static int uea_cmv(struct uea_softc *sc,
u8 function, u32 address, u16 offset, u32 data)
{
- struct cmv_e1 cmv;
+ struct cmv cmv;
int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
"offset : 0x%04x, data : 0x%08x\n",
- E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
- E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
- E1_GETSA4(address), offset, data);
-
+ FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
+ GETSA1(address), GETSA2(address), GETSA3(address),
+ GETSA4(address), offset, data);
/* we send a request, but we expect a reply */
- sc->cmv_dsc.e1.function = function | 0x2;
- sc->cmv_dsc.e1.idx++;
- sc->cmv_dsc.e1.address = address;
- sc->cmv_dsc.e1.offset = offset;
+ sc->cmv_function = function | 0x2;
+ sc->cmv_idx++;
+ sc->cmv_address = address;
+ sc->cmv_offset = offset;
- cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
- cmv.bDirection = E1_HOSTTOMODEM;
+ cmv.wPreamble = cpu_to_le16(PREAMBLE);
+ cmv.bDirection = HOSTTOMODEM;
cmv.bFunction = function;
- cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
+ cmv.wIndex = cpu_to_le16(sc->cmv_idx);
put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
- ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
- if (ret < 0)
- return ret;
- ret = wait_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
- return ret;
-}
-
-static int uea_cmv_e4(struct uea_softc *sc,
- u16 function, u16 group, u16 address, u16 offset, u32 data)
-{
- struct cmv_e4 cmv;
- int ret;
-
- uea_enters(INS_TO_USBDEV(sc));
- memset(&cmv, 0, sizeof(cmv));
-
- uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
- "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
- E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
- group, address, offset, data);
-
- /* we send a request, but we expect a reply */
- sc->cmv_dsc.e4.function = function | (0x1 << 4);
- sc->cmv_dsc.e4.offset = offset;
- sc->cmv_dsc.e4.address = address;
- sc->cmv_dsc.e4.group = group;
-
- cmv.wFunction = cpu_to_be16(function);
- cmv.wGroup = cpu_to_be16(group);
- cmv.wAddress = cpu_to_be16(address);
- cmv.wOffset = cpu_to_be16(offset);
- cmv.dwData[0] = cpu_to_be32(data);
-
- ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+ ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
if (ret < 0)
return ret;
ret = wait_cmv_ack(sc);
@@ -1198,10 +826,10 @@ static int uea_cmv_e4(struct uea_softc *sc,
return ret;
}
-static inline int uea_read_cmv_e1(struct uea_softc *sc,
+static inline int uea_read_cmv(struct uea_softc *sc,
u32 address, u16 offset, u32 *data)
{
- int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
+ int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
address, offset, 0);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -1212,27 +840,10 @@ static inline int uea_read_cmv_e1(struct uea_softc *sc,
return ret;
}
-static inline int uea_read_cmv_e4(struct uea_softc *sc,
- u8 size, u16 group, u16 address, u16 offset, u32 *data)
-{
- int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
- group, address, offset, 0);
- if (ret < 0)
- uea_err(INS_TO_USBDEV(sc),
- "reading cmv failed with error %d\n", ret);
- else {
- *data = sc->data;
- /* size is in 16-bit word quantities */
- if (size > 2)
- *(data + 1) = sc->data1;
- }
- return ret;
-}
-
-static inline int uea_write_cmv_e1(struct uea_softc *sc,
+static inline int uea_write_cmv(struct uea_softc *sc,
u32 address, u16 offset, u32 data)
{
- int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
+ int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
address, offset, data);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -1241,48 +852,12 @@ static inline int uea_write_cmv_e1(struct uea_softc *sc,
return ret;
}
-static inline int uea_write_cmv_e4(struct uea_softc *sc,
- u8 size, u16 group, u16 address, u16 offset, u32 data)
-{
- int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
- group, address, offset, data);
- if (ret < 0)
- uea_err(INS_TO_USBDEV(sc),
- "writing cmv failed with error %d\n", ret);
-
- return ret;
-}
-
-static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
-{
- int ret;
- u16 timeout;
-
- /* in bulk mode the modem have problem with high rate
- * changing internal timing could improve things, but the
- * value is misterious.
- * ADI930 don't support it (-EPIPE error).
- */
-
- if (UEA_CHIP_VERSION(sc) == ADI930 ||
- altsetting[sc->modem_index] > 0 ||
- sc->stats.phy.dsrate == dsrate)
- return;
-
- /* Original timming (1Mbit/s) from ADI (used in windows driver) */
- timeout = (dsrate <= 1024*1024) ? 0 : 1;
- ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
- uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
- timeout, ret < 0 ? " failed" : "");
-
-}
-
/*
* Monitor the modem and update the stat
* return 0 if everything is ok
* return < 0 if an error occurs (-EAGAIN reboot needed)
*/
-static int uea_stat_e1(struct uea_softc *sc)
+static int uea_stat(struct uea_softc *sc)
{
u32 data;
int ret;
@@ -1290,7 +865,7 @@ static int uea_stat_e1(struct uea_softc *sc)
uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
- ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
+ ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
if (ret < 0)
return ret;
@@ -1310,7 +885,7 @@ static int uea_stat_e1(struct uea_softc *sc)
case 3: /* fail ... */
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
- " (may be try other cmv/dsp)\n");
+ " (may be try other cmv/dsp)\n");
return -EAGAIN;
case 4 ... 6: /* test state */
@@ -1348,7 +923,7 @@ static int uea_stat_e1(struct uea_softc *sc)
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
+ ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
if (ret < 0)
return ret;
sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -1362,223 +937,105 @@ static int uea_stat_e1(struct uea_softc *sc)
return 0;
}
- ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
+ ret = uea_read_cmv(sc, SA_RATE, 0, &data);
if (ret < 0)
return ret;
- uea_set_bulk_timeout(sc, (data >> 16) * 32);
+ /* in bulk mode the modem have problem with high rate
+ * changing internal timing could improve things, but the
+ * value is misterious.
+ * ADI930 don't support it (-EPIPE error).
+ */
+ if (UEA_CHIP_VERSION(sc) != ADI930
+ && !use_iso[sc->modem_index]
+ && sc->stats.phy.dsrate != (data >> 16) * 32) {
+ /* Original timming from ADI(used in windows driver)
+ * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
+ */
+ u16 timeout = (data <= 0x20ffff) ? 0 : 1;
+ ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc),
+ "setting new timeout %d%s\n", timeout,
+ ret < 0?" failed":"");
+ }
sc->stats.phy.dsrate = (data >> 16) * 32;
sc->stats.phy.usrate = (data & 0xffff) * 32;
UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
+ ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
if (ret < 0)
return ret;
sc->stats.phy.dsattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
+ ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
if (ret < 0)
return ret;
sc->stats.phy.usattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
+ ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
+ ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
+ ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
+ ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
+ ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
+ ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
if (ret < 0)
return ret;
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
+ ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
- if (ret < 0)
- return ret;
-
- ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
- if (ret < 0)
- return ret;
-
- ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int uea_stat_e4(struct uea_softc *sc)
-{
- u32 data;
- u32 tmp_arr[2];
- int ret;
-
- uea_enters(INS_TO_USBDEV(sc));
- data = sc->stats.phy.state;
-
- /* XXX only need to be done before operationnal... */
- ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
- if (ret < 0)
- return ret;
-
- switch (sc->stats.phy.state) {
- case 0x0: /* not yet synchronized */
- case 0x1:
- case 0x3:
- case 0x4:
- uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
- return 0;
- case 0x5: /* initialization */
- case 0x6:
- case 0x9:
- case 0xa:
- uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
- return 0;
- case 0x2: /* fail ... */
- uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
- " (may be try other cmv/dsp)\n");
- return -EAGAIN;
- case 0x7: /* operational */
- break;
- default:
- uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
- return 0;
- }
-
- if (data != 7) {
- uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
- uea_info(INS_TO_USBDEV(sc), "modem operational\n");
-
- /* release the dsp firmware as it is not needed until
- * the next failure
- */
- if (sc->dsp_firm) {
- release_firmware(sc->dsp_firm);
- sc->dsp_firm = NULL;
- }
- }
-
- /* always update it as atm layer could not be init when we switch to
- * operational state
- */
- UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
-
- /* wake up processes waiting for synchronization */
- wake_up(&sc->sync_q);
-
- /* TODO improve this state machine :
- * we need some CMV info : what they do and their unit
- * we should find the equivalent of eagle3- CMV
- */
- /* check flags */
- ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+ ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
if (ret < 0)
return ret;
- sc->stats.phy.mflags |= sc->stats.phy.flags;
-
- /* in case of a flags ( for example delineation LOSS (& 0x10)),
- * we check the status again in order to detect the failure earlier
- */
- if (sc->stats.phy.flags) {
- uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
- sc->stats.phy.flags);
- if (sc->stats.phy.flags & 1) //delineation LOSS
- return -EAGAIN;
- if (sc->stats.phy.flags & 0x4000) //Reset Flag
- return -EAGAIN;
- return 0;
- }
- /* rate data may be in upper or lower half of 64 bit word, strange */
- ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+ ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
if (ret < 0)
return ret;
- data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
- sc->stats.phy.usrate = data / 1000;
- ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+ ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
if (ret < 0)
return ret;
- data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
- uea_set_bulk_timeout(sc, data / 1000);
- sc->stats.phy.dsrate = data / 1000;
- UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
-
- ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
- if (ret < 0)
- return ret;
- sc->stats.phy.dsattenuation = data / 10;
-
- ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
- if (ret < 0)
- return ret;
- sc->stats.phy.usattenuation = data / 10;
-
- ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
- if (ret < 0)
- return ret;
- sc->stats.phy.dsmargin = data / 2;
-
- ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
- if (ret < 0)
- return ret;
- sc->stats.phy.usmargin = data / 10;
return 0;
}
-static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+static int request_cmvs(struct uea_softc *sc,
+ struct uea_cmvs **cmvs, const struct firmware **fw)
{
- char file_arr[] = "CMVxy.bin";
+ int ret, size;
+ u8 *data;
char *file;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
- /* set proper name corresponding modem version and line type */
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
- file_arr[3] = '9';
- else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
- file_arr[3] = '4';
+ file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
else
- file_arr[3] = 'e';
-
- file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
- file = file_arr;
+ file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
} else
file = cmv_file[sc->modem_index];
strcpy(cmv_name, FW_DIR);
- strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
- if (ver == 2)
- strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
-}
-
-static int request_cmvs_old(struct uea_softc *sc,
- void **cmvs, const struct firmware **fw)
-{
- int ret, size;
- u8 *data;
- char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ strlcat(cmv_name, file, sizeof(cmv_name));
- cmvs_file_name(sc, cmv_name, 1);
ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
@@ -1588,197 +1045,16 @@ static int request_cmvs_old(struct uea_softc *sc,
}
data = (u8 *) (*fw)->data;
- size = (*fw)->size;
- if (size < 1)
- goto err_fw_corrupted;
-
- if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
- goto err_fw_corrupted;
-
- *cmvs = (void *)(data + 1);
- return *data;
-
-err_fw_corrupted:
- uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
- release_firmware(*fw);
- return -EILSEQ;
-}
-
-static int request_cmvs(struct uea_softc *sc,
- void **cmvs, const struct firmware **fw, int *ver)
-{
- int ret, size;
- u32 crc;
- u8 *data;
- char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
-
- cmvs_file_name(sc, cmv_name, 2);
- ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
- if (ret < 0) {
- /* if caller can handle old version, try to provide it */
- if (*ver == 1) {
- uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
- "try to get older cmvs\n", cmv_name);
- return request_cmvs_old(sc, cmvs, fw);
- }
- uea_err(INS_TO_USBDEV(sc),
- "requesting firmware %s failed with error %d\n",
- cmv_name, ret);
- return ret;
- }
-
- size = (*fw)->size;
- data = (u8 *) (*fw)->data;
- if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
- if (*ver == 1) {
- uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
- "try to get older cmvs\n", cmv_name);
- release_firmware(*fw);
- return request_cmvs_old(sc, cmvs, fw);
- }
- goto err_fw_corrupted;
+ size = *data * sizeof(struct uea_cmvs) + 1;
+ if (size != (*fw)->size) {
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
+ cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
}
- *ver = 2;
-
- data += 4;
- size -= 4;
- if (size < 5)
- goto err_fw_corrupted;
-
- crc = FW_GET_LONG(data);
- data += 4;
- size -= 4;
- if (crc32_be(0, data, size) != crc)
- goto err_fw_corrupted;
-
- if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
- goto err_fw_corrupted;
-
- *cmvs = (void *) (data + 1);
+ *cmvs = (struct uea_cmvs *)(data + 1);
return *data;
-
-err_fw_corrupted:
- uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
- release_firmware(*fw);
- return -EILSEQ;
-}
-
-static int uea_send_cmvs_e1(struct uea_softc *sc)
-{
- int i, ret, len;
- void *cmvs_ptr;
- const struct firmware *cmvs_fw;
- int ver = 1; // we can handle v1 cmv firmware version;
-
- /* Enter in R-IDLE (cmv) until instructed otherwise */
- ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
- if (ret < 0)
- return ret;
-
- /* Dump firmware version */
- ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
- if (ret < 0)
- return ret;
- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
- sc->stats.phy.firmid);
-
- /* get options */
- ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
- if (ret < 0)
- return ret;
-
- /* send options */
- if (ver == 1) {
- struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
-
- uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
- "please update your firmware\n");
-
- for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
- FW_GET_WORD(&cmvs_v1[i].offset),
- FW_GET_LONG(&cmvs_v1[i].data));
- if (ret < 0)
- goto out;
- }
- } else if (ver == 2) {
- struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
-
- for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
- (u16) FW_GET_LONG(&cmvs_v2[i].offset),
- FW_GET_LONG(&cmvs_v2[i].data));
- if (ret < 0)
- goto out;
- }
- } else {
- /* This realy should not happen */
- uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
- goto out;
- }
-
- /* Enter in R-ACT-REQ */
- ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
- uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
- uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
-out:
- release_firmware(cmvs_fw);
- return ret;
-}
-
-static int uea_send_cmvs_e4(struct uea_softc *sc)
-{
- int i, ret, len;
- void *cmvs_ptr;
- const struct firmware *cmvs_fw;
- int ver = 2; // we can only handle v2 cmv firmware version;
-
- /* Enter in R-IDLE (cmv) until instructed otherwise */
- ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
- if (ret < 0)
- return ret;
-
- /* Dump firmware version */
- /* XXX don't read the 3th byte as it is always 6 */
- ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
- if (ret < 0)
- return ret;
- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
- sc->stats.phy.firmid);
-
-
- /* get options */
- ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
- if (ret < 0)
- return ret;
-
- /* send options */
- if (ver == 2) {
- struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
-
- for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e4(sc, 1,
- FW_GET_LONG(&cmvs_v2[i].group),
- FW_GET_LONG(&cmvs_v2[i].address),
- FW_GET_LONG(&cmvs_v2[i].offset),
- FW_GET_LONG(&cmvs_v2[i].data));
- if (ret < 0)
- goto out;
- }
- } else {
- /* This realy should not happen */
- uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
- goto out;
- }
-
- /* Enter in R-ACT-REQ */
- ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
- uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
- uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
-out:
- release_firmware(cmvs_fw);
- return ret;
}
/* Start boot post firmware modem:
@@ -1790,7 +1066,9 @@ static int uea_send_cmvs_e4(struct uea_softc *sc)
static int uea_start_reset(struct uea_softc *sc)
{
u16 zero = 0; /* ;-) */
- int ret;
+ int i, len, ret;
+ struct uea_cmvs *cmvs;
+ const struct firmware *cmvs_fw;
uea_enters(INS_TO_USBDEV(sc));
uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1815,36 +1093,25 @@ static int uea_start_reset(struct uea_softc *sc)
uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
/* original driver use 200ms, but windows driver use 100ms */
- ret = uea_wait(sc, 0, msecs_to_jiffies(100));
- if (ret < 0)
- return ret;
+ msleep(100);
/* leave reset mode */
uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
- if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
- /* clear tx and rx mailboxes */
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
- }
-
- ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
- if (ret < 0)
- return ret;
-
- if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
- sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
- else
- sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
+ /* clear tx and rx mailboxes */
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ msleep(1000);
+ sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
/* demask interrupt */
sc->booting = 0;
/* start loading DSP */
sc->pageno = 0;
sc->ovl = 0;
- queue_work(sc->work_q, &sc->task);
+ schedule_work(&sc->task);
/* wait for modem ready CMV */
ret = wait_cmv_ack(sc);
@@ -1853,10 +1120,38 @@ static int uea_start_reset(struct uea_softc *sc)
uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
- ret = sc->send_cmvs(sc);
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
if (ret < 0)
return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
+ FW_GET_WORD(&cmvs[i].offset),
+ FW_GET_LONG(&cmvs[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "Modem started, "
+ "waiting synchronization\n");
+out:
+ release_firmware(cmvs_fw);
sc->reset = 0;
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1879,10 +1174,12 @@ static int uea_kthread(void *data)
if (ret < 0 || sc->reset)
ret = uea_start_reset(sc);
if (!ret)
- ret = sc->stat(sc);
+ ret = uea_stat(sc);
if (ret != -EAGAIN)
- uea_wait(sc, 0, msecs_to_jiffies(1000));
- try_to_freeze();
+ msleep_interruptible(1000);
+ if (try_to_freeze())
+ uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
+ "please unplug/replug your modem\n");
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1937,6 +1234,7 @@ static int load_XILINX_firmware(struct uea_softc *sc)
if (ret < 0)
uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
+
err1:
release_firmware(fw_entry);
err0:
@@ -1945,41 +1243,40 @@ static int load_XILINX_firmware(struct uea_softc *sc)
}
/* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
+static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
{
- struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
- struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
-
uea_enters(INS_TO_USBDEV(sc));
- if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
+ if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
goto bad1;
- if (cmv->bDirection != E1_MODEMTOHOST)
+ if (cmv->bDirection != MODEMTOHOST)
goto bad1;
/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
* the first MEMACESS cmv. Ignore it...
*/
- if (cmv->bFunction != dsc->function) {
+ if (cmv->bFunction != sc->cmv_function) {
if (UEA_CHIP_VERSION(sc) == ADI930
- && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
- cmv->wIndex = cpu_to_le16(dsc->idx);
- put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
- cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
- } else
+ && cmv->bFunction == MAKEFUNCTION(2, 2)) {
+ cmv->wIndex = cpu_to_le16(sc->cmv_idx);
+ put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
+ cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
+ }
+ else
goto bad2;
}
- if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
+ if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
wake_up_cmv_ack(sc);
uea_leaves(INS_TO_USBDEV(sc));
return;
}
/* in case of MEMACCESS */
- if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
- le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
+ if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
+ le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
+ sc->cmv_address
+ || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
goto bad2;
sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1992,8 +1289,8 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
bad2:
uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
"Function : %d, Subfunction : %d\n",
- E1_FUNCTION_TYPE(cmv->bFunction),
- E1_FUNCTION_SUBTYPE(cmv->bFunction));
+ FUNCTION_TYPE(cmv->bFunction),
+ FUNCTION_SUBTYPE(cmv->bFunction));
uea_leaves(INS_TO_USBDEV(sc));
return;
@@ -2004,61 +1301,6 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
uea_leaves(INS_TO_USBDEV(sc));
}
-/* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
-{
- struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
- struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
-
- uea_enters(INS_TO_USBDEV(sc));
- uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
- be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
- be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
- be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
-
- if (be16_to_cpu(cmv->wFunction) != dsc->function)
- goto bad2;
-
- if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
- wake_up_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
- return;
- }
-
- /* in case of MEMACCESS */
- if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
- be16_to_cpu(cmv->wGroup) != dsc->group ||
- be16_to_cpu(cmv->wAddress) != dsc->address)
- goto bad2;
-
- sc->data = be32_to_cpu(cmv->dwData[0]);
- sc->data1 = be32_to_cpu(cmv->dwData[1]);
- wake_up_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
- return;
-
-bad2:
- uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
- "Function : %d, Subfunction : %d\n",
- E4_FUNCTION_TYPE(cmv->wFunction),
- E4_FUNCTION_SUBTYPE(cmv->wFunction));
- uea_leaves(INS_TO_USBDEV(sc));
- return;
-}
-
-static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
-{
- sc->pageno = intr->e1_bSwapPageNo;
- sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
- queue_work(sc->work_q, &sc->task);
-}
-
-static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
-{
- sc->pageno = intr->e4_bSwapPageNo;
- queue_work(sc->work_q, &sc->task);
-}
-
/*
* interrupt handler
*/
@@ -2084,11 +1326,13 @@ static void uea_intr(struct urb *urb)
switch (le16_to_cpu(intr->wInterrupt)) {
case INT_LOADSWAPPAGE:
- sc->schedule_load_page(sc, intr);
+ sc->pageno = intr->bSwapPageNo;
+ sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
+ schedule_work(&sc->task);
break;
case INT_INCOMINGCMV:
- sc->dispatch_cmv(sc, intr);
+ uea_dispatch_cmv(sc, &intr->u.s2.cmv);
break;
default:
@@ -2105,55 +1349,35 @@ static void uea_intr(struct urb *urb)
*/
static int uea_boot(struct uea_softc *sc)
{
- int ret, size;
+ int ret;
struct intr_pkt *intr;
uea_enters(INS_TO_USBDEV(sc));
- if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
- size = E4_INTR_PKT_SIZE;
- sc->dispatch_cmv = uea_dispatch_cmv_e4;
- sc->schedule_load_page = uea_schedule_load_page_e4;
- sc->stat = uea_stat_e4;
- sc->send_cmvs = uea_send_cmvs_e4;
- INIT_WORK(&sc->task, uea_load_page_e4);
- } else {
- size = E1_INTR_PKT_SIZE;
- sc->dispatch_cmv = uea_dispatch_cmv_e1;
- sc->schedule_load_page = uea_schedule_load_page_e1;
- sc->stat = uea_stat_e1;
- sc->send_cmvs = uea_send_cmvs_e1;
- INIT_WORK(&sc->task, uea_load_page_e1);
- }
-
+ INIT_WORK(&sc->task, uea_load_page);
init_waitqueue_head(&sc->sync_q);
-
- sc->work_q = create_workqueue("ueagle-dsp");
- if (!sc->work_q) {
- uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
- uea_leaves(INS_TO_USBDEV(sc));
- return -ENOMEM;
- }
+ init_waitqueue_head(&sc->cmv_ack_wait);
if (UEA_CHIP_VERSION(sc) == ADI930)
load_XILINX_firmware(sc);
- intr = kmalloc(size, GFP_KERNEL);
+ intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
if (!intr) {
uea_err(INS_TO_USBDEV(sc),
"cannot allocate interrupt package\n");
- goto err0;
+ uea_leaves(INS_TO_USBDEV(sc));
+ return -ENOMEM;
}
sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
if (!sc->urb_int) {
uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
- goto err1;
+ goto err;
}
usb_fill_int_urb(sc->urb_int, sc->usb_dev,
usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
- intr, size, uea_intr, sc,
+ intr, INTR_PKT_SIZE, uea_intr, sc,
sc->usb_dev->actconfig->interface[0]->altsetting[0].
endpoint[0].desc.bInterval);
@@ -2161,7 +1385,7 @@ static int uea_boot(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"urb submition failed with error %d\n", ret);
- goto err1;
+ goto err;
}
sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -2175,12 +1399,10 @@ static int uea_boot(struct uea_softc *sc)
err2:
usb_kill_urb(sc->urb_int);
-err1:
+err:
usb_free_urb(sc->urb_int);
sc->urb_int = NULL;
kfree(intr);
-err0:
- destroy_workqueue(sc->work_q);
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
@@ -2195,15 +1417,15 @@ static void uea_stop(struct uea_softc *sc)
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
+ /* stop any pending boot process */
+ flush_scheduled_work();
+
uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
usb_kill_urb(sc->urb_int);
kfree(sc->urb_int->transfer_buffer);
usb_free_urb(sc->urb_int);
- /* stop any pending boot process, when no one can schedule work */
- destroy_workqueue(sc->work_q);
-
if (sc->dsp_firm)
release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
@@ -2265,7 +1487,6 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
char *buf)
{
int ret = -ENODEV;
- int modem_state;
struct uea_softc *sc;
mutex_lock(&uea_mutex);
@@ -2273,34 +1494,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
if (!sc)
goto out;
- if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
- switch (sc->stats.phy.state) {
- case 0x0: /* not yet synchronized */
- case 0x1:
- case 0x3:
- case 0x4:
- modem_state = 0;
- break;
- case 0x5: /* initialization */
- case 0x6:
- case 0x9:
- case 0xa:
- modem_state = 1;
- break;
- case 0x7: /* operational */
- modem_state = 2;
- break;
- case 0x2: /* fail ... */
- modem_state = 3;
- break;
- default: /* unknown */
- modem_state = 4;
- break;
- }
- } else
- modem_state = GET_STATUS(sc->stats.phy.state);
-
- switch (modem_state) {
+ switch (GET_STATUS(sc->stats.phy.state)) {
case 0:
ret = sprintf(buf, "Modem is booting\n");
break;
@@ -2310,11 +1504,8 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
case 2:
ret = sprintf(buf, "Modem is operational\n");
break;
- case 3:
- ret = sprintf(buf, "Modem synchronization failed\n");
- break;
default:
- ret = sprintf(buf, "Modem state is unknown\n");
+ ret = sprintf(buf, "Modem synchronization failed\n");
break;
}
out:
@@ -2329,26 +1520,18 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
{
int ret = -ENODEV;
struct uea_softc *sc;
- char *delin = "GOOD";
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev);
if (!sc)
goto out;
- if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
- if (sc->stats.phy.flags & 0x4000)
- delin = "RESET";
- else if (sc->stats.phy.flags & 0x0001)
- delin = "LOSS";
- } else {
- if (sc->stats.phy.flags & 0x0C00)
- delin = "ERROR";
- else if (sc->stats.phy.flags & 0x0030)
- delin = "LOSS";
- }
-
- ret = sprintf(buf, "%s\n", delin);
+ if (sc->stats.phy.flags & 0x0C00)
+ ret = sprintf(buf, "ERROR\n");
+ else if (sc->stats.phy.flags & 0x0030)
+ ret = sprintf(buf, "LOSS\n");
+ else
+ ret = sprintf(buf, "GOOD\n");
out:
mutex_unlock(&uea_mutex);
return ret;
@@ -2479,7 +1662,6 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
struct usb_device *usb = interface_to_usbdev(intf);
struct uea_softc *sc;
int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
- unsigned int alt;
uea_enters(usb);
@@ -2514,29 +1696,22 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
sc->driver_info = id->driver_info;
- /* first try to use module parameter */
- if (annex[sc->modem_index] == 1)
- sc->annex = ANNEXA;
- else if (annex[sc->modem_index] == 2)
- sc->annex = ANNEXB;
- /* try to autodetect annex */
- else if (sc->driver_info & AUTO_ANNEX_A)
- sc->annex = ANNEXA;
- else if (sc->driver_info & AUTO_ANNEX_B)
- sc->annex = ANNEXB;
- else
- sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
-
- alt = altsetting[sc->modem_index];
/* ADI930 don't support iso */
- if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
- if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
- uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
+ if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
+ int i;
+
+ /* try set fastest alternate for inbound traffic interface */
+ for (i = FASTEST_ISO_INTF; i > 0; i--)
+ if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
+ break;
+
+ if (i > 0) {
+ uea_dbg(usb, "set alternate %d for 2 interface\n", i);
uea_info(usb, "using iso mode\n");
usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
} else {
- uea_err(usb, "setting alternate %u failed for "
- "2 interface, using bulk mode\n", alt);
+ uea_err(usb, "setting any alternate failed for "
+ "2 interface, using bulk mode\n");
}
}
@@ -2582,11 +1757,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
uea_enters(usb);
- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
- le16_to_cpu(usb->descriptor.idVendor),
- le16_to_cpu(usb->descriptor.idProduct),
- le16_to_cpu(usb->descriptor.bcdDevice),
- chip_name[UEA_CHIP_VERSION(id)]);
+ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
+ le16_to_cpu(usb->descriptor.idVendor),
+ le16_to_cpu(usb->descriptor.idProduct),
+ chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
usb_reset_device(usb);
@@ -2619,40 +1793,24 @@ static void uea_disconnect(struct usb_interface *intf)
* List of supported VID/PID
*/
static const struct usb_device_id uea_ids[] = {
- {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
- {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM},
- {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
{USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
- {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM},
- {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
- {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM},
- {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
+ {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
+ {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
{USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
{USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+ {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+ {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
{}
};
diff --git a/trunk/drivers/usb/class/usblp.c b/trunk/drivers/usb/class/usblp.c
index ad632f2d6f94..5192cd9356de 100644
--- a/trunk/drivers/usb/class/usblp.c
+++ b/trunk/drivers/usb/class/usblp.c
@@ -28,7 +28,6 @@
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf ( not on stack);
* use usb_buffer_alloc() for read buf & write buf;
- * none - Maintained in Linux kernel after v0.13
*/
/*
@@ -70,6 +69,7 @@
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
+#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */
+#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
@@ -159,12 +159,10 @@ struct usblp {
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
- unsigned int flags; /* mode flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
- unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
@@ -261,7 +259,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
- request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
+ request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
@@ -327,11 +325,13 @@ static void usblp_bulk_write(struct urb *urb)
usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
- usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock(&usblp->lock);
+ /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
+ kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
usb_free_urb(urb);
}
@@ -346,17 +346,16 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
- mutex_lock(&usblp->mut);
- if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
- mutex_unlock(&usblp->mut);
+ error = usblp_read_status (usblp, usblp->statusbuf);
+ if (error < 0) {
if (printk_ratelimit())
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
+
status = *usblp->statusbuf;
- mutex_unlock(&usblp->mut);
if (~status & LP_PERRORP)
newerr = 3;
@@ -412,10 +411,18 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
/*
- * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
- * - We do not want persistent state which close(2) does not clear
- * - It is not used anyway, according to CUPS people
+ * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
+ * This is #if 0-ed because we *don't* want to fail an open
+ * just because the printer is off-line.
*/
+#if 0
+ if ((retval = usblp_check_status(usblp, 0))) {
+ retval = retval > 1 ? -EIO : -ENOSPC;
+ goto out;
+ }
+#else
+ retval = 0;
+#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
@@ -456,8 +463,6 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
- usblp->flags &= ~LP_ABORT;
-
mutex_lock (&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
@@ -480,8 +485,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
poll_wait(file, &usblp->rwait, wait);
poll_wait(file, &usblp->wwait, wait);
spin_lock_irqsave(&usblp->lock, flags);
- ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) |
- ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
+ ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
+ | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
@@ -670,13 +675,6 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
- case LPABORT:
- if (arg)
- usblp->flags |= LP_ABORT;
- else
- usblp->flags &= ~LP_ABORT;
- break;
-
default:
retval = -ENOTTY;
}
@@ -686,30 +684,10 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return retval;
}
-static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
-{
- struct urb *urb;
- char *writebuf;
-
- if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
- return NULL;
- if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
- kfree(writebuf);
- return NULL;
- }
-
- usb_fill_bulk_urb(urb, usblp->dev,
- usb_sndbulkpipe(usblp->dev,
- usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
- writebuf, transfer_length, usblp_bulk_write, usblp);
- urb->transfer_flags |= URB_FREE_BUFFER;
-
- return urb;
-}
-
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
+ char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
@@ -730,11 +708,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
- if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
+ if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
+ goto raise_buf;
+ if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
goto raise_urb;
+ usb_fill_bulk_urb(writeurb, usblp->dev,
+ usb_sndbulkpipe(usblp->dev,
+ usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+ writebuf, transfer_length, usblp_bulk_write, usblp);
usb_anchor_urb(writeurb, &usblp->urbs);
- if (copy_from_user(writeurb->transfer_buffer,
+ if (copy_from_user(writebuf,
buffer + writecount, transfer_length)) {
rv = -EFAULT;
goto raise_badaddr;
@@ -746,7 +730,6 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
- usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
@@ -764,17 +747,12 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
/* Presume that it's going to complete well. */
writecount += transfer_length;
}
- if (rv == -ENOSPC) {
- spin_lock_irq(&usblp->lock);
- usblp->no_paper = 1; /* Mark for poll(2) */
- spin_unlock_irq(&usblp->lock);
- writecount += transfer_length;
- }
/* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
if (usblp->wstatus < 0) {
+ usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
@@ -793,6 +771,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
usb_unanchor_urb(writeurb);
usb_free_urb(writeurb);
raise_urb:
+ kfree(writebuf);
+raise_buf:
raise_wait:
collect_error: /* Out of raise sequence */
mutex_unlock(&usblp->wmut);
@@ -858,36 +838,32 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
* select(2) or poll(2) to wait for the buffer to drain before closing.
* Alternatively, set blocking mode with fcntl and issue a zero-size write.
+ *
+ * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
+ * to check the return code for timeout expiration, so it had no effect.
+ * Apparently, it was intended to check for error conditons, such as out
+ * of paper. It is going to return when we settle things with CUPS. XXX
*/
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
- int err = 0;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
- rc = usblp_wtest(usblp, nonblock);
- mutex_unlock(&usblp->mut);
- if (rc <= 0)
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
+ mutex_unlock(&usblp->mut);
break;
-
- if (usblp->flags & LP_ABORT) {
- if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
- err = usblp_check_status(usblp, err);
- if (err == 1) { /* Paper out */
- rc = -ENOSPC;
- break;
- }
- }
- } else {
- schedule();
}
+ mutex_unlock(&usblp->mut);
+ if (rc == 0)
+ break;
+ schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);
diff --git a/trunk/drivers/usb/core/config.c b/trunk/drivers/usb/core/config.c
index 1a8edcee7f30..cb69aa1e02e8 100644
--- a/trunk/drivers/usb/core/config.c
+++ b/trunk/drivers/usb/core/config.c
@@ -507,30 +507,18 @@ void usb_destroy_configuration(struct usb_device *dev)
}
-/*
- * Get the USB config descriptors, cache and parse'em
- *
- * hub-only!! ... and only in reset path, or usb_new_device()
- * (used by real hubs and virtual root hubs)
- *
- * NOTE: if this is a WUSB device and is not authorized, we skip the
- * whole thing. A non-authorized USB device has no
- * configurations.
- */
+// hub-only!! ... and only in reset path, or usb_new_device()
+// (used by real hubs and virtual root hubs)
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
- int result = 0;
+ int result = -ENOMEM;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
- cfgno = 0;
- if (dev->authorized == 0) /* Not really an error */
- goto out_not_authorized;
- result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -557,15 +545,14 @@ int usb_get_configuration(struct usb_device *dev)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
- result = 0;
- for (; cfgno < ncfg; cfgno++) {
+ for (cfgno = 0; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s: %d\n", cfgno, "start", result);
+ "descriptor/%s\n", cfgno, "start");
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
@@ -612,7 +599,6 @@ int usb_get_configuration(struct usb_device *dev)
err:
kfree(buffer);
-out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
diff --git a/trunk/drivers/usb/core/devio.c b/trunk/drivers/usb/core/devio.c
index e5ad76b4a738..927a181120a9 100644
--- a/trunk/drivers/usb/core/devio.c
+++ b/trunk/drivers/usb/core/devio.c
@@ -71,7 +71,6 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
- int status;
u32 secid;
};
@@ -290,8 +289,10 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop)
return;
- dev_info(&urb->dev->dev, "direction=%s\n",
- usb_urb_dir_in(urb) ? "IN" : "OUT");
+ if (urb->pipe & USB_DIR_IN)
+ dev_info(&urb->dev->dev, "direction=IN\n");
+ else
+ dev_info(&urb->dev->dev, "direction=OUT\n");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length);
@@ -311,10 +312,9 @@ static void async_completed(struct urb *urb)
spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
- as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
- sinfo.si_errno = as->status;
+ sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,7 +910,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
- int is_in;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET))
@@ -925,18 +924,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum)))
return ret;
}
- if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
- is_in = 1;
- ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- } else {
- is_in = 0;
- ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- }
+ if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
+ ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ else
+ ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
if (!ep)
return -ENOENT;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
- if (!usb_endpoint_xfer_control(&ep->desc))
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_CONTROL)
return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -955,32 +952,23 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return ret;
}
+ uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
- if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
- is_in = 1;
- uurb->endpoint |= USB_DIR_IN;
- } else {
- is_in = 0;
- uurb->endpoint &= ~USB_DIR_IN;
- }
- if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
- uurb->buffer, uurb->buffer_length)) {
+ if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
- dr->bRequest, dr->bRequestType,
- __le16_to_cpup(&dr->wValue),
- __le16_to_cpup(&dr->wIndex),
- __le16_to_cpup(&dr->wLength));
+ dr->bRequest, dr->bRequestType, dr->wValue,
+ dr->wIndex, dr->wLength);
break;
case USBDEVFS_URB_TYPE_BULK:
- switch (usb_endpoint_type(&ep->desc)) {
+ switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
@@ -989,8 +977,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
- uurb->buffer, uurb->buffer_length))
+ if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break;
@@ -999,7 +986,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
- if (!usb_endpoint_xfer_isoc(&ep->desc))
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_ISOC)
return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1026,12 +1014,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
- if (!usb_endpoint_xfer_int(&ep->desc))
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_INT)
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
- uurb->buffer, uurb->buffer_length))
+ if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
@@ -1051,11 +1039,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM;
}
as->urb->dev = ps->dev;
- as->urb->pipe = (uurb->type << 30) |
- __create_pipe(ps->dev, uurb->endpoint & 0xf) |
- (uurb->endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb->flags |
- (is_in ? URB_DIR_IN : URB_DIR_OUT);
+ as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
+ as->urb->transfer_flags = uurb->flags;
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame;
@@ -1085,13 +1070,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
- if (!is_in) {
- if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
- as->urb->transfer_buffer_length)) {
+ if (!(uurb->endpoint & USB_DIR_IN)) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
+ snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1134,14 +1119,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(as->status, &userurb->status))
+ if (put_user(urb->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
+ if (usb_pipeisoc(urb->pipe)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1248,14 +1233,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(as->status, &userurb->status))
+ if (put_user(urb->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
+ if (usb_pipeisoc(urb->pipe)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c
index c27bc080d84e..63b1243a9139 100644
--- a/trunk/drivers/usb/core/driver.c
+++ b/trunk/drivers/usb/core/driver.c
@@ -202,11 +202,6 @@ static int usb_probe_interface(struct device *dev)
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
- if (udev->authorized == 0) {
- dev_err(&intf->dev, "Device is not authorized for usage\n");
- return -ENODEV;
- }
-
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
@@ -950,11 +945,11 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
#ifdef CONFIG_USB_SUSPEND
/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev, int reschedule)
+static int autosuspend_check(struct usb_device *udev)
{
int i;
struct usb_interface *intf;
- unsigned long suspend_time, j;
+ unsigned long suspend_time;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
@@ -996,20 +991,20 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
}
/* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request. If the device
- * _has_ been idle for long enough and the reschedule flag is set,
- * likewise queue a delayed (1 second) autosuspend request.
+ * enough, queue a delayed autosuspend request.
*/
- j = jiffies;
- if (time_before(j, suspend_time))
- reschedule = 1;
- else
- suspend_time = j + HZ;
- if (reschedule) {
+ if (time_after(suspend_time, jiffies)) {
if (!timer_pending(&udev->autosuspend.timer)) {
+
+ /* The value of jiffies may change between the
+ * time_after() comparison above and the subtraction
+ * below. That's okay; the system behaves sanely
+ * when a timer is registered for the present moment
+ * or for the past.
+ */
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- round_jiffies_relative(suspend_time - j));
- }
+ round_jiffies_relative(suspend_time - jiffies));
+ }
return -EAGAIN;
}
return 0;
@@ -1017,7 +1012,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
#else
-static inline int autosuspend_check(struct usb_device *udev, int reschedule)
+static inline int autosuspend_check(struct usb_device *udev)
{
return 0;
}
@@ -1074,7 +1069,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
- status = autosuspend_check(udev, 0);
+ status = autosuspend_check(udev);
if (status < 0)
goto done;
}
@@ -1088,8 +1083,15 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
- if (status == 0)
+ if (status == 0) {
+
+ /* Non-root devices don't need to do anything for FREEZE
+ * or PRETHAW. */
+ if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
+ msg.event == PM_EVENT_PRETHAW))
+ goto done;
status = usb_suspend_device(udev, msg);
+ }
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
@@ -1100,24 +1102,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* Try another autosuspend when the interfaces aren't busy */
if (udev->auto_pm)
- autosuspend_check(udev, status == -EBUSY);
+ autosuspend_check(udev);
- /* If the suspend succeeded then prevent any more URB submissions,
- * flush any outstanding URBs, and propagate the suspend up the tree.
- */
+ /* If the suspend succeeded, propagate it up the tree */
} else {
cancel_delayed_work(&udev->autosuspend);
- udev->can_submit = 0;
- for (i = 0; i < 16; ++i) {
- usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
- usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
- }
-
- /* If this is just a FREEZE or a PRETHAW, udev might
- * not really be suspended. Only true suspends get
- * propagated up the device tree.
- */
- if (parent && udev->state == USB_STATE_SUSPENDED)
+ if (parent)
usb_autosuspend_device(parent);
}
@@ -1166,7 +1156,6 @@ static int usb_resume_both(struct usb_device *udev)
status = -ENODEV;
goto done;
}
- udev->can_submit = 1;
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
@@ -1540,21 +1529,9 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
- struct usb_device *udev;
-
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
- udev = to_usb_device(dev);
-
- /* If udev is already suspended, we can skip this suspend and
- * we should also skip the upcoming system resume. */
- if (udev->state == USB_STATE_SUSPENDED) {
- udev->skip_sys_resume = 1;
- return 0;
- }
-
- udev->skip_sys_resume = 0;
- return usb_external_suspend_device(udev, message);
+ return usb_external_suspend_device(to_usb_device(dev), message);
}
static int usb_resume(struct device *dev)
@@ -1565,14 +1542,13 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
- /* If udev->skip_sys_resume is set then udev was already suspended
- * when the system suspend started, so we don't want to resume
- * udev during this system wakeup. However a reset-resume counts
- * as a wakeup event, so allow a reset-resume to occur if remote
- * wakeup is enabled. */
- if (udev->skip_sys_resume) {
+ /* If autoresume is disabled then we also want to prevent resume
+ * during system wakeup. However, a "persistent-device" reset-resume
+ * after power loss counts as a wakeup event. So allow a
+ * reset-resume to occur if remote wakeup is enabled. */
+ if (udev->autoresume_disabled) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
- return -EHOSTUNREACH;
+ return -EPERM;
}
return usb_external_resume_device(udev);
}
diff --git a/trunk/drivers/usb/core/endpoint.c b/trunk/drivers/usb/core/endpoint.c
index 7dc123d6b2d0..e0ec7045e865 100644
--- a/trunk/drivers/usb/core/endpoint.c
+++ b/trunk/drivers/usb/core/endpoint.c
@@ -267,6 +267,7 @@ static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
+ dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
diff --git a/trunk/drivers/usb/core/generic.c b/trunk/drivers/usb/core/generic.c
index c1cb94e9f242..b2fc2b115256 100644
--- a/trunk/drivers/usb/core/generic.c
+++ b/trunk/drivers/usb/core/generic.c
@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
-int usb_choose_configuration(struct usb_device *udev)
+static int choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
@@ -161,20 +161,17 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
- if (udev->authorized == 0)
- dev_err(&udev->dev, "Device is not authorized for usage\n");
- else {
- c = usb_choose_configuration(udev);
- if (c >= 0) {
- err = usb_set_configuration(udev, c);
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ c = choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
- }
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
}
}
+
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
@@ -206,13 +203,8 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
*/
if (!udev->parent)
rc = hcd_bus_suspend(udev);
-
- /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
- else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
- rc = 0;
else
rc = usb_port_suspend(udev);
-
return rc;
}
diff --git a/trunk/drivers/usb/core/hcd.c b/trunk/drivers/usb/core/hcd.c
index 3dd997df8505..42ef1d5f6c8a 100644
--- a/trunk/drivers/usb/core/hcd.c
+++ b/trunk/drivers/usb/core/hcd.c
@@ -356,18 +356,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
- int status;
+ unsigned long flags;
+ int status = 0;
int n;
- might_sleep();
-
- spin_lock_irq(&hcd_root_hub_lock);
- status = usb_hcd_link_urb_to_ep(hcd, urb);
- spin_unlock_irq(&hcd_root_hub_lock);
- if (status)
- return status;
- urb->hcpriv = hcd; /* Indicate it's queued */
-
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
@@ -531,18 +523,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
}
/* any errors get returned through the urb completion */
- spin_lock_irq(&hcd_root_hub_lock);
- usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- /* This peculiar use of spinlocks echoes what real HC drivers do.
- * Avoiding calls to local_irq_disable/enable makes the code
- * RT-friendly.
- */
- spin_unlock(&hcd_root_hub_lock);
- usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&hcd_root_hub_lock);
-
- spin_unlock_irq(&hcd_root_hub_lock);
+ local_irq_save (flags);
+ spin_lock (&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ spin_unlock (&urb->lock);
+ usb_hcd_giveback_urb (hcd, urb);
+ local_irq_restore (flags);
return 0;
}
@@ -572,23 +559,31 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
if (length > 0) {
/* try to complete the status urb */
- spin_lock_irqsave(&hcd_root_hub_lock, flags);
+ local_irq_save (flags);
+ spin_lock(&hcd_root_hub_lock);
urb = hcd->status_urb;
if (urb) {
- hcd->poll_pending = 0;
- hcd->status_urb = NULL;
- urb->actual_length = length;
- memcpy(urb->transfer_buffer, buffer, length);
-
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&hcd_root_hub_lock);
- usb_hcd_giveback_urb(hcd, urb, 0);
- spin_lock(&hcd_root_hub_lock);
- } else {
+ spin_lock(&urb->lock);
+ if (urb->status == -EINPROGRESS) {
+ hcd->poll_pending = 0;
+ hcd->status_urb = NULL;
+ urb->status = 0;
+ urb->hcpriv = NULL;
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
+ } else /* urb has been unlinked */
+ length = 0;
+ spin_unlock(&urb->lock);
+ } else
length = 0;
+ spin_unlock(&hcd_root_hub_lock);
+
+ /* local irqs are always blocked in completions */
+ if (length > 0)
+ usb_hcd_giveback_urb (hcd, urb);
+ else
hcd->poll_pending = 1;
- }
- spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ local_irq_restore (flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
@@ -616,35 +611,33 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
- if (hcd->status_urb || urb->transfer_buffer_length < len) {
+ if (urb->status != -EINPROGRESS) /* already unlinked */
+ retval = urb->status;
+ else if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
- goto done;
- }
-
- retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval)
- goto done;
+ } else {
+ hcd->status_urb = urb;
+ urb->hcpriv = hcd; /* indicate it's queued */
- hcd->status_urb = urb;
- urb->hcpriv = hcd; /* indicate it's queued */
- if (!hcd->uses_new_polling)
- mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+ if (!hcd->uses_new_polling)
+ mod_timer (&hcd->rh_timer,
+ (jiffies/(HZ/4) + 1) * (HZ/4));
- /* If a status change has already occurred, report it ASAP */
- else if (hcd->poll_pending)
- mod_timer(&hcd->rh_timer, jiffies);
- retval = 0;
- done:
+ /* If a status change has already occurred, report it ASAP */
+ else if (hcd->poll_pending)
+ mod_timer (&hcd->rh_timer, jiffies);
+ retval = 0;
+ }
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_endpoint_xfer_int(&urb->ep->desc))
+ if (usb_pipeint (urb->pipe))
return rh_queue_status (hcd, urb);
- if (usb_endpoint_xfer_control(&urb->ep->desc))
+ if (usb_pipecontrol (urb->pipe))
return rh_call_control (hcd, urb);
return -EINVAL;
}
@@ -654,96 +647,32 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/* Unlinks of root-hub control URBs are legal, but they don't do anything
* since these URBs always execute synchronously.
*/
-static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&hcd_root_hub_lock, flags);
- rc = usb_hcd_check_unlink_urb(hcd, urb, status);
- if (rc)
- goto done;
- if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
+ if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer (&hcd->rh_timer);
+ local_irq_save (flags);
+ spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
- usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- spin_unlock(&hcd_root_hub_lock);
- usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&hcd_root_hub_lock);
- }
+ urb->hcpriv = NULL;
+ } else
+ urb = NULL; /* wasn't fully queued */
+ spin_unlock (&hcd_root_hub_lock);
+ if (urb)
+ usb_hcd_giveback_urb (hcd, urb);
+ local_irq_restore (flags);
}
- done:
- spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
- return rc;
-}
-
-
-
-/*
- * Show & store the current value of authorized_default
- */
-static ssize_t usb_host_authorized_default_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct usb_device *rh_usb_dev = to_usb_device(dev);
- struct usb_bus *usb_bus = rh_usb_dev->bus;
- struct usb_hcd *usb_hcd;
- if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
- return -ENODEV;
- usb_hcd = bus_to_hcd(usb_bus);
- return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
-}
-
-static ssize_t usb_host_authorized_default_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- ssize_t result;
- unsigned val;
- struct usb_device *rh_usb_dev = to_usb_device(dev);
- struct usb_bus *usb_bus = rh_usb_dev->bus;
- struct usb_hcd *usb_hcd;
-
- if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
- return -ENODEV;
- usb_hcd = bus_to_hcd(usb_bus);
- result = sscanf(buf, "%u\n", &val);
- if (result == 1) {
- usb_hcd->authorized_default = val? 1 : 0;
- result = size;
- }
- else
- result = -EINVAL;
- return result;
+ return 0;
}
-static DEVICE_ATTR(authorized_default, 0644,
- usb_host_authorized_default_show,
- usb_host_authorized_default_store);
-
-
-/* Group all the USB bus attributes */
-static struct attribute *usb_bus_attrs[] = {
- &dev_attr_authorized_default.attr,
- NULL,
-};
-
-static struct attribute_group usb_bus_attr_group = {
- .name = NULL, /* we want them in the same directory */
- .attrs = usb_bus_attrs,
-};
-
-
-
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
@@ -797,23 +726,27 @@ static void usb_bus_init (struct usb_bus *bus)
*/
static int usb_register_bus(struct usb_bus *bus)
{
- int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
- if (busnum >= USB_MAXBUS) {
+ if (busnum < USB_MAXBUS) {
+ set_bit (busnum, busmap.busmap);
+ bus->busnum = busnum;
+ } else {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
- goto error_find_busnum;
+ mutex_unlock(&usb_bus_list_lock);
+ return -E2BIG;
}
- set_bit (busnum, busmap.busmap);
- bus->busnum = busnum;
+
bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
- bus->controller, "usb_host%d",
- busnum);
- result = PTR_ERR(bus->class_dev);
- if (IS_ERR(bus->class_dev))
- goto error_create_class_dev;
+ bus->controller, "usb_host%d", busnum);
+ if (IS_ERR(bus->class_dev)) {
+ clear_bit(busnum, busmap.busmap);
+ mutex_unlock(&usb_bus_list_lock);
+ return PTR_ERR(bus->class_dev);
+ }
+
class_set_devdata(bus->class_dev, bus);
/* Add it to the local list of buses */
@@ -822,15 +755,8 @@ static int usb_register_bus(struct usb_bus *bus)
usb_notify_add_bus(bus);
- dev_info (bus->controller, "new USB bus registered, assigned bus "
- "number %d\n", bus->busnum);
+ dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
return 0;
-
-error_create_class_dev:
- clear_bit(busnum, busmap.busmap);
-error_find_busnum:
- mutex_unlock(&usb_bus_list_lock);
- return result;
}
/**
@@ -982,145 +908,103 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
-/**
- * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
- * @hcd: host controller to which @urb was submitted
- * @urb: URB being submitted
- *
- * Host controller drivers should call this routine in their enqueue()
- * method. The HCD's private spinlock must be held and interrupts must
- * be disabled. The actions carried out here are required for URB
- * submission, as well as for endpoint shutdown and for usb_kill_urb.
- *
- * Returns 0 for no error, otherwise a negative error code (in which case
- * the enqueue() method must fail). If no error occurs but enqueue() fails
- * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
- * the private spinlock and returning.
- */
-int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
+static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
{
- int rc = 0;
+ unsigned long flags;
- spin_lock(&hcd_urb_list_lock);
+ /* clear all state linking urb to this dev (and hcd) */
+ spin_lock_irqsave(&hcd_urb_list_lock, flags);
+ list_del_init (&urb->urb_list);
+ spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
- /* Check that the URB isn't being killed */
- if (unlikely(urb->reject)) {
- rc = -EPERM;
- goto done;
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_pipecontrol (urb->pipe)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ dma_unmap_single (hcd->self.controller, urb->setup_dma,
+ sizeof (struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ dma_unmap_single (hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? DMA_FROM_DEVICE
+ : DMA_TO_DEVICE);
}
+}
- if (unlikely(!urb->ep->enabled)) {
- rc = -ENOENT;
- goto done;
- }
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+ int status;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+ struct usb_host_endpoint *ep;
+ unsigned long flags;
- if (unlikely(!urb->dev->can_submit)) {
- rc = -EHOSTUNREACH;
- goto done;
- }
+ if (!hcd)
+ return -ENODEV;
+
+ usbmon_urb_submit(&hcd->self, urb);
/*
- * Check the host controller's state and add the URB to the
- * endpoint's queue.
+ * Atomically queue the urb, first to our records, then to the HCD.
+ * Access to urb->status is controlled by urb->lock ... changes on
+ * i/o completion (normal or fault) or unlinking.
*/
- switch (hcd->state) {
+
+ // FIXME: verify that quiescing hc works right (RH cleans up)
+
+ spin_lock_irqsave(&hcd_urb_list_lock, flags);
+ ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (unlikely (!ep))
+ status = -ENOENT;
+ else if (unlikely (urb->reject))
+ status = -EPERM;
+ else switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
- urb->unlinked = 0;
- list_add_tail(&urb->urb_list, &urb->ep->urb_list);
+ list_add_tail (&urb->urb_list, &ep->urb_list);
+ status = 0;
break;
default:
- rc = -ESHUTDOWN;
- goto done;
+ status = -ESHUTDOWN;
+ break;
}
- done:
- spin_unlock(&hcd_urb_list_lock);
- return rc;
-}
-EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
-
-/**
- * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
- * @hcd: host controller to which @urb was submitted
- * @urb: URB being checked for unlinkability
- * @status: error code to store in @urb if the unlink succeeds
- *
- * Host controller drivers should call this routine in their dequeue()
- * method. The HCD's private spinlock must be held and interrupts must
- * be disabled. The actions carried out here are required for making
- * sure than an unlink is valid.
- *
- * Returns 0 for no error, otherwise a negative error code (in which case
- * the dequeue() method must fail). The possible error codes are:
- *
- * -EIDRM: @urb was not submitted or has already completed.
- * The completion function may not have been called yet.
- *
- * -EBUSY: @urb has already been unlinked.
- */
-int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
- int status)
-{
- struct list_head *tmp;
-
- /* insist the urb is still queued */
- list_for_each(tmp, &urb->ep->urb_list) {
- if (tmp == &urb->urb_list)
- break;
+ spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+ if (status) {
+ INIT_LIST_HEAD (&urb->urb_list);
+ usbmon_urb_submit_error(&hcd->self, urb, status);
+ return status;
}
- if (tmp != &urb->urb_list)
- return -EIDRM;
- /* Any status except -EINPROGRESS means something already started to
- * unlink this URB from the hardware. So there's no more work to do.
- */
- if (urb->unlinked)
- return -EBUSY;
- urb->unlinked = status;
-
- /* IRQ setup can easily be broken so that USB controllers
- * never get completion IRQs ... maybe even the ones we need to
- * finish unlinking the initial failed usb_set_address()
- * or device descriptor fetch.
+ /* increment urb's reference count as part of giving it to the HCD
+ * (which now controls it). HCD guarantees that it either returns
+ * an error or calls giveback(), but not both.
*/
- if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
- !is_root_hub(urb->dev)) {
- dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
- "Controller is probably using the wrong IRQ.\n");
- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+ urb = usb_get_urb (urb);
+ atomic_inc (&urb->use_count);
+
+ if (is_root_hub(urb->dev)) {
+ /* NOTE: requirement on hub callers (usbfs and the hub
+ * driver, for now) that URBs' urb->transfer_buffer be
+ * valid and usb_buffer_{sync,unmap}() not be needed, since
+ * they could clobber root hub response data.
+ */
+ status = rh_urb_enqueue (hcd, urb);
+ goto done;
}
- return 0;
-}
-EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
-
-/**
- * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
- * @hcd: host controller to which @urb was submitted
- * @urb: URB being unlinked
- *
- * Host controller drivers should call this routine before calling
- * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
- * interrupts must be disabled. The actions carried out here are required
- * for URB completion.
- */
-void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
-{
- /* clear all state linking urb to this dev (and hcd) */
- spin_lock(&hcd_urb_list_lock);
- list_del_init(&urb->urb_list);
- spin_unlock(&hcd_urb_list_lock);
-}
-EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
-
-static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
-{
- /* Map the URB's buffers for DMA access.
- * Lower level HCD code should use *_dma exclusively,
+ /* lower level hcd code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
- if (usb_endpoint_xfer_control(&urb->ep->desc)
+ if (hcd->self.uses_dma) {
+ if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
hcd->self.controller,
@@ -1133,75 +1017,20 @@ static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
hcd->self.controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
- usb_urb_dir_in(urb)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
- }
-}
-
-static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
-{
- if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
- if (usb_endpoint_xfer_control(&urb->ep->desc)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- dma_unmap_single(hcd->self.controller, urb->setup_dma,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
- dma_unmap_single(hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- usb_urb_dir_in(urb)
+ usb_pipein (urb->pipe)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
- int status;
- struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
-
- /* increment urb's reference count as part of giving it to the HCD
- * (which will control it). HCD guarantees that it either returns
- * an error or calls giveback(), but not both.
- */
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- usbmon_urb_submit(&hcd->self, urb);
-
- /* NOTE requirements on root-hub callers (usbfs and the hub
- * driver, for now): URBs' urb->transfer_buffer must be
- * valid and usb_buffer_{sync,unmap}() not be needed, since
- * they could clobber root hub response data. Also, control
- * URBs must be submitted in process context with interrupts
- * enabled.
- */
- map_urb_for_dma(hcd, urb);
- if (is_root_hub(urb->dev))
- status = rh_urb_enqueue(hcd, urb);
- else
- status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
- if (unlikely(status)) {
- usbmon_urb_submit_error(&hcd->self, urb, status);
- unmap_urb_for_dma(hcd, urb);
- urb->hcpriv = NULL;
- INIT_LIST_HEAD(&urb->urb_list);
- atomic_dec(&urb->use_count);
- atomic_dec(&urb->dev->urbnum);
+ status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
+done:
+ if (unlikely (status)) {
+ urb_unlink(hcd, urb);
+ atomic_dec (&urb->use_count);
if (urb->reject)
- wake_up(&usb_kill_urb_queue);
- usb_put_urb(urb);
+ wake_up (&usb_kill_urb_queue);
+ usbmon_urb_submit_error(&hcd->self, urb, status);
+ usb_put_urb (urb);
}
return status;
}
@@ -1213,19 +1042,24 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
* soon as practical. we've already set up the urb's return status,
* but we can't know if the callback completed already.
*/
-static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
+static int
+unlink1 (struct usb_hcd *hcd, struct urb *urb)
{
int value;
if (is_root_hub(urb->dev))
- value = usb_rh_urb_dequeue(hcd, urb, status);
+ value = usb_rh_urb_dequeue (hcd, urb);
else {
/* The only reason an HCD might fail this call is if
* it has not yet fully queued the urb to begin with.
* Such failures should be harmless. */
- value = hcd->driver->urb_dequeue(hcd, urb, status);
+ value = hcd->driver->urb_dequeue (hcd, urb);
}
+
+ if (value != 0)
+ dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
+ urb, value);
return value;
}
@@ -1237,17 +1071,88 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
*/
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
- struct usb_hcd *hcd;
- int retval;
+ struct usb_host_endpoint *ep;
+ struct usb_hcd *hcd = NULL;
+ struct device *sys = NULL;
+ unsigned long flags;
+ struct list_head *tmp;
+ int retval;
+
+ if (!urb)
+ return -EINVAL;
+ if (!urb->dev || !urb->dev->bus)
+ return -ENODEV;
+ ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep)
+ return -ENODEV;
+ /*
+ * we contend for urb->status with the hcd core,
+ * which changes it while returning the urb.
+ *
+ * Caller guaranteed that the urb pointer hasn't been freed, and
+ * that it was submitted. But as a rule it can't know whether or
+ * not it's already been unlinked ... so we respect the reversed
+ * lock sequence needed for the usb_hcd_giveback_urb() code paths
+ * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
+ * unlinking it.
+ */
+ spin_lock_irqsave (&urb->lock, flags);
+ spin_lock(&hcd_urb_list_lock);
+
+ sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
- retval = unlink1(hcd, urb, status);
+ if (hcd == NULL) {
+ retval = -ENODEV;
+ goto done;
+ }
+ /* insist the urb is still queued */
+ list_for_each(tmp, &ep->urb_list) {
+ if (tmp == &urb->urb_list)
+ break;
+ }
+ if (tmp != &urb->urb_list) {
+ retval = -EIDRM;
+ goto done;
+ }
+
+ /* Any status except -EINPROGRESS means something already started to
+ * unlink this URB from the hardware. So there's no more work to do.
+ */
+ if (urb->status != -EINPROGRESS) {
+ retval = -EBUSY;
+ goto done;
+ }
+
+ /* IRQ setup can easily be broken so that USB controllers
+ * never get completion IRQs ... maybe even the ones we need to
+ * finish unlinking the initial failed usb_set_address()
+ * or device descriptor fetch.
+ */
+ if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+ !is_root_hub(urb->dev)) {
+ dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
+ "Controller is probably using the wrong IRQ.\n");
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+ }
+
+ urb->status = status;
+
+ spin_unlock(&hcd_urb_list_lock);
+ spin_unlock_irqrestore (&urb->lock, flags);
+
+ retval = unlink1 (hcd, urb);
if (retval == 0)
retval = -EINPROGRESS;
- else if (retval != -EIDRM && retval != -EBUSY)
- dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
- urb, retval);
+ return retval;
+
+done:
+ spin_unlock(&hcd_urb_list_lock);
+ spin_unlock_irqrestore (&urb->lock, flags);
+ if (retval != -EIDRM && sys && sys->driver)
+ dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
return retval;
}
@@ -1257,7 +1162,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
- * @status: completion status code for the URB.
* Context: in_interrupt()
*
* This hands the URB from HCD to its USB device driver, using its
@@ -1265,27 +1169,14 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
* (and is done using urb->hcpriv). It also released all HCD locks;
* the device driver won't cause problems if it frees, modifies,
* or resubmits this URB.
- *
- * If @urb was unlinked, the value of @status will be overridden by
- * @urb->unlinked. Erroneous short transfers are detected in case
- * the HCD hasn't checked for them.
*/
-void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
{
- urb->hcpriv = NULL;
- if (unlikely(urb->unlinked))
- status = urb->unlinked;
- else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length < urb->transfer_buffer_length &&
- !status))
- status = -EREMOTEIO;
-
- unmap_urb_for_dma(hcd, urb);
- usbmon_urb_complete(&hcd->self, urb, status);
+ urb_unlink(hcd, urb);
+ usbmon_urb_complete (&hcd->self, urb);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
- urb->status = status;
urb->complete (urb);
atomic_dec (&urb->use_count);
if (unlikely (urb->reject))
@@ -1296,61 +1187,78 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/
-/* Cancel all URBs pending on this endpoint and wait for the endpoint's
- * queue to drain completely. The caller must first insure that no more
- * URBs can be submitted for this endpoint.
+/* disables the endpoint: cancels any pending urbs, then synchronizes with
+ * the hcd to make sure all endpoint state is gone from hardware, and then
+ * waits until the endpoint's queue is completely drained. use for
+ * set_configuration, set_interface, driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
*/
-void usb_hcd_flush_endpoint(struct usb_device *udev,
+void usb_hcd_endpoint_disable (struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
- if (!ep)
- return;
- might_sleep();
hcd = bus_to_hcd(udev->bus);
+ local_irq_disable ();
- /* No more submits can occur */
+ /* ep is already gone from udev->ep_{in,out}[]; no more submits */
rescan:
- spin_lock_irq(&hcd_urb_list_lock);
+ spin_lock(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
- int is_in;
+ int tmp;
- if (urb->unlinked)
+ /* the urb may already have been unlinked */
+ if (urb->status != -EINPROGRESS)
continue;
usb_get_urb (urb);
- is_in = usb_urb_dir_in(urb);
spin_unlock(&hcd_urb_list_lock);
- /* kick hcd */
- unlink1(hcd, urb, -ESHUTDOWN);
- dev_dbg (hcd->self.controller,
- "shutdown urb %p ep%d%s%s\n",
- urb, usb_endpoint_num(&ep->desc),
- is_in ? "in" : "out",
- ({ char *s;
-
- switch (usb_endpoint_type(&ep->desc)) {
- case USB_ENDPOINT_XFER_CONTROL:
- s = ""; break;
- case USB_ENDPOINT_XFER_BULK:
- s = "-bulk"; break;
- case USB_ENDPOINT_XFER_INT:
- s = "-intr"; break;
- default:
- s = "-iso"; break;
- };
- s;
- }));
+ spin_lock (&urb->lock);
+ tmp = urb->status;
+ if (tmp == -EINPROGRESS)
+ urb->status = -ESHUTDOWN;
+ spin_unlock (&urb->lock);
+
+ /* kick hcd unless it's already returning this */
+ if (tmp == -EINPROGRESS) {
+ tmp = urb->pipe;
+ unlink1 (hcd, urb);
+ dev_dbg (hcd->self.controller,
+ "shutdown urb %p pipe %08x ep%d%s%s\n",
+ urb, tmp, usb_pipeendpoint (tmp),
+ (tmp & USB_DIR_IN) ? "in" : "out",
+ ({ char *s; \
+ switch (usb_pipetype (tmp)) { \
+ case PIPE_CONTROL: s = ""; break; \
+ case PIPE_BULK: s = "-bulk"; break; \
+ case PIPE_INTERRUPT: s = "-intr"; break; \
+ default: s = "-iso"; break; \
+ }; s;}));
+ }
usb_put_urb (urb);
/* list contents may have changed */
goto rescan;
}
- spin_unlock_irq(&hcd_urb_list_lock);
+ spin_unlock(&hcd_urb_list_lock);
+ local_irq_enable ();
+
+ /* synchronize with the hardware, so old configuration state
+ * clears out immediately (and will be freed).
+ */
+ might_sleep ();
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable (hcd, ep);
- /* Wait until the endpoint queue is completely empty */
+ /* Wait until the endpoint queue is completely empty. Most HCDs
+ * will have done this already in their endpoint_disable method,
+ * but some might not. And there could be root-hub control URBs
+ * still pending since they aren't affected by the HCDs'
+ * endpoint_disable methods.
+ */
while (!list_empty (&ep->urb_list)) {
spin_lock_irq(&hcd_urb_list_lock);
@@ -1370,25 +1278,6 @@ void usb_hcd_flush_endpoint(struct usb_device *udev,
}
}
-/* Disables the endpoint: synchronizes with the hcd to make sure all
- * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
- * have been called previously. Use for set_configuration, set_interface,
- * driver removal, physical disconnect.
- *
- * example: a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
- */
-void usb_hcd_disable_endpoint(struct usb_device *udev,
- struct usb_host_endpoint *ep)
-{
- struct usb_hcd *hcd;
-
- might_sleep();
- hcd = bus_to_hcd(udev->bus);
- if (hcd->driver->endpoint_disable)
- hcd->driver->endpoint_disable(hcd, ep);
-}
-
/*-------------------------------------------------------------------------*/
/* called in any context */
@@ -1636,6 +1525,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
+
return hcd;
}
EXPORT_SYMBOL (usb_create_hcd);
@@ -1680,7 +1570,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
- hcd->authorized_default = hcd->wireless? 0 : 1;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* HC is in reset state, but accessible. Now do the one-time init,
@@ -1757,20 +1646,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;
- retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
- if (retval < 0) {
- printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
- retval);
- goto error_create_attr_group;
- }
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
-error_create_attr_group:
- mutex_lock(&usb_bus_list_lock);
- usb_disconnect(&hcd->self.root_hub);
- mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
@@ -1812,7 +1691,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
- sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
diff --git a/trunk/drivers/usb/core/hcd.h b/trunk/drivers/usb/core/hcd.h
index 98e24194a4ab..b5ebb73c2332 100644
--- a/trunk/drivers/usb/core/hcd.h
+++ b/trunk/drivers/usb/core/hcd.h
@@ -19,8 +19,6 @@
#ifdef __KERNEL__
-#include
-
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
@@ -53,12 +51,6 @@
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
- *
- * @authorized_default: Specifies if new devices are authorized to
- * connect by default or they require explicit
- * user space authorization; this bit is settable
- * through /sys/class/usb_host/X/authorized_default.
- * For the rest is RO, so we don't lock to r/w it.
*/
/*-------------------------------------------------------------------------*/
@@ -98,7 +90,6 @@ struct usb_hcd {
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
- unsigned authorized_default:1;
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -191,10 +182,11 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
- int (*urb_enqueue)(struct usb_hcd *hcd,
- struct urb *urb, gfp_t mem_flags);
- int (*urb_dequeue)(struct usb_hcd *hcd,
- struct urb *urb, int status);
+ int (*urb_enqueue) (struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep,
+ struct urb *urb,
+ gfp_t mem_flags);
+ int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
@@ -212,18 +204,10 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
-extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
-extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
- int status);
-extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
-
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
- int status);
-extern void usb_hcd_flush_endpoint(struct usb_device *udev,
- struct usb_host_endpoint *ep);
-extern void usb_hcd_disable_endpoint(struct usb_device *udev,
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+extern void usb_hcd_endpoint_disable (struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
@@ -418,7 +402,7 @@ static inline void usbfs_cleanup(void) { }
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
- void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
+ void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
@@ -437,11 +421,10 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_submit_error)(bus, urb, error);
}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
- int status)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
{
if (bus->monitored)
- (*mon_ops->urb_complete)(bus, urb, status);
+ (*mon_ops->urb_complete)(bus, urb);
}
int usb_mon_register(struct usb_mon_operations *ops);
@@ -452,8 +435,7 @@ void usb_mon_deregister(void);
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
- int status) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
#endif /* CONFIG_USB_MON */
@@ -472,9 +454,5 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
: (in_interrupt () ? "in_interrupt" : "can sleep"))
-/* This rwsem is for use only by the hub driver and ehci-hcd.
- * Nobody else should touch it.
- */
-extern struct rw_semaphore ehci_cf_port_reset_rwsem;
-
#endif /* __KERNEL__ */
+
diff --git a/trunk/drivers/usb/core/hub.c b/trunk/drivers/usb/core/hub.c
index d20cb545a6e4..f7b337feb3ea 100644
--- a/trunk/drivers/usb/core/hub.c
+++ b/trunk/drivers/usb/core/hub.c
@@ -125,12 +125,6 @@ MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "
"first one fails");
-/* Mutual exclusion for EHCI CF initialization. This interferes with
- * port reset on some companion controllers.
- */
-DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
-EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
-
static inline char *portspeed(int portstatus)
{
@@ -353,11 +347,11 @@ void usb_kick_khubd(struct usb_device *hdev)
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
- int status = urb->status;
+ int status;
int i;
unsigned long bits;
- switch (status) {
+ switch (urb->status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
@@ -365,10 +359,10 @@ static void hub_irq(struct urb *urb)
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
- dev_dbg (hub->intfdev, "transfer --> %d\n", status);
+ dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
if ((++hub->nerrors < 10) || hub->error)
goto resubmit;
- hub->error = status;
+ hub->error = urb->status;
/* FALL THROUGH */
/* let khubd handle things */
@@ -1226,14 +1220,54 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#endif
/**
- * usb_configure_device_otg - FIXME (usbcore-internal)
+ * usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * Do configuration for On-The-Go devices
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
*/
-static int usb_configure_device_otg(struct usb_device *udev)
+int usb_new_device(struct usb_device *udev)
{
- int err = 0;
+ int err;
+
+ /* Determine quirks */
+ usb_detect_quirks(udev);
+
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ goto fail;
+ }
+
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+
+ /* Tell the world! */
+ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+ "SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
#ifdef CONFIG_USB_OTG
/*
@@ -1295,82 +1329,8 @@ static int usb_configure_device_otg(struct usb_device *udev)
err = -ENOTSUPP;
goto fail;
}
-fail:
#endif
- return err;
-}
-
-
-/**
- * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is only called by usb_new_device() and usb_authorize_device()
- * and FIXME -- all comments that apply to them apply here wrt to
- * environment.
- *
- * If the device is WUSB and not authorized, we don't attempt to read
- * the string descriptors, as they will be errored out by the device
- * until it has been authorized.
- */
-static int usb_configure_device(struct usb_device *udev)
-{
- int err;
- if (udev->config == NULL) {
- err = usb_get_configuration(udev);
- if (err < 0) {
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
- goto fail;
- }
- }
- if (udev->wusb == 1 && udev->authorized == 0) {
- udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- }
- else {
- /* read the standard strings and cache them if present */
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
- udev->manufacturer = usb_cache_string(udev,
- udev->descriptor.iManufacturer);
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
- }
- err = usb_configure_device_otg(udev);
-fail:
- return err;
-}
-
-
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not. Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
- int err;
-
- usb_detect_quirks(udev); /* Determine quirks */
- err = usb_configure_device(udev); /* detect & probe dev/intfs */
- if (err < 0)
- goto fail;
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1386,106 +1346,19 @@ int usb_new_device(struct usb_device *udev)
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
+ if (udev->parent)
+ usb_autosuspend_device(udev->parent);
goto fail;
}
- /* Tell the world! */
- dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
- "SerialNumber=%d\n",
- udev->descriptor.iManufacturer,
- udev->descriptor.iProduct,
- udev->descriptor.iSerialNumber);
- show_string(udev, "Product", udev->product);
- show_string(udev, "Manufacturer", udev->manufacturer);
- show_string(udev, "SerialNumber", udev->serial);
+exit:
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- return err;
+ goto exit;
}
-
-/**
- * Similar to usb_disconnect()
- *
- * We share a lock (that we have) with device_del(), so we need to
- * defer its call.
- */
-int usb_deauthorize_device(struct usb_device *usb_dev)
-{
- unsigned cnt;
- usb_lock_device(usb_dev);
- if (usb_dev->authorized == 0)
- goto out_unauthorized;
- usb_dev->authorized = 0;
- usb_set_configuration(usb_dev, -1);
- usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- kfree(usb_dev->config);
- usb_dev->config = NULL;
- for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
- kfree(usb_dev->rawdescriptors[cnt]);
- usb_dev->descriptor.bNumConfigurations = 0;
- kfree(usb_dev->rawdescriptors);
-out_unauthorized:
- usb_unlock_device(usb_dev);
- return 0;
-}
-
-
-int usb_authorize_device(struct usb_device *usb_dev)
-{
- int result = 0, c;
- usb_lock_device(usb_dev);
- if (usb_dev->authorized == 1)
- goto out_authorized;
- kfree(usb_dev->product);
- usb_dev->product = NULL;
- kfree(usb_dev->manufacturer);
- usb_dev->manufacturer = NULL;
- kfree(usb_dev->serial);
- usb_dev->serial = NULL;
- result = usb_autoresume_device(usb_dev);
- if (result < 0) {
- dev_err(&usb_dev->dev,
- "can't autoresume for authorization: %d\n", result);
- goto error_autoresume;
- }
- result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
- if (result < 0) {
- dev_err(&usb_dev->dev, "can't re-read device descriptor for "
- "authorization: %d\n", result);
- goto error_device_descriptor;
- }
- usb_dev->authorized = 1;
- result = usb_configure_device(usb_dev);
- if (result < 0)
- goto error_configure;
- /* Choose and set the configuration. This registers the interfaces
- * with the driver core and lets interface drivers bind to them.
- */
- c = usb_choose_configuration(usb_dev);
- if (c >= 0) {
- result = usb_set_configuration(usb_dev, c);
- if (result) {
- dev_err(&usb_dev->dev,
- "can't set config #%d, error %d\n", c, result);
- /* This need not be fatal. The user can try to
- * set other configurations. */
- }
- }
- dev_info(&usb_dev->dev, "authorized to connect\n");
-error_configure:
-error_device_descriptor:
-error_autoresume:
-out_authorized:
- usb_unlock_device(usb_dev); // complements locktree
- return result;
-}
-
-
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
@@ -1587,11 +1460,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
{
int i, status;
- /* Block EHCI CF initialization during the port reset.
- * Some companion controllers don't like it when they mix.
- */
- down_read(&ehci_cf_port_reset_rwsem);
-
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
status = set_port_feature(hub->hdev,
@@ -1613,7 +1481,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
- udev->devnum = 0; /* Device now at address 0 */
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@@ -1623,7 +1490,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
usb_set_device_state(udev, status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
- goto done;
+ return status;
}
dev_dbg (hub->intfdev,
@@ -1636,8 +1503,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
- done:
- up_read(&ehci_cf_port_reset_rwsem);
return status;
}
@@ -1968,7 +1833,14 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
- if (udev && udev->can_submit) {
+ if (udev && msg.event == PM_EVENT_SUSPEND &&
+#ifdef CONFIG_USB_SUSPEND
+ udev->state != USB_STATE_SUSPENDED
+#else
+ udev->dev.power.power_state.event
+ == PM_EVENT_ON
+#endif
+ ) {
if (!hdev->auto_pm)
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
@@ -2127,27 +1999,26 @@ static void ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- usb_enable_endpoint(udev, &udev->ep0);
+ udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
}
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
-static int hub_set_address(struct usb_device *udev, int devnum)
+static int hub_set_address(struct usb_device *udev)
{
int retval;
- if (devnum <= 1)
+ if (udev->devnum == 0)
return -EINVAL;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
- USB_REQ_SET_ADDRESS, 0, devnum, 0,
+ USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
- udev->devnum = devnum; /* Device now using proper address */
usb_set_device_state(udev, USB_STATE_ADDRESS);
ep0_reinit(udev);
}
@@ -2174,7 +2045,6 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
- int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -2204,7 +2074,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
oldspeed = udev->speed;
-
+
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2245,7 +2115,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
- udev->bus->controller->driver->name, devnum);
+ udev->bus->controller->driver->name, udev->devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -2332,7 +2202,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev, devnum);
+ retval = hub_set_address(udev);
if (retval >= 0)
break;
msleep(200);
@@ -2340,7 +2210,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
- devnum, retval);
+ udev->devnum, retval);
goto fail;
}
@@ -2393,10 +2263,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = 0;
fail:
- if (retval) {
+ if (retval)
hub_port_disable(hub, port1, 0);
- udev->devnum = devnum; /* for disconnect processing */
- }
mutex_unlock(&usb_address0_mutex);
return retval;
}
@@ -2831,9 +2699,9 @@ static void hub_events(void)
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
/* FIXME: Is this always true? */
- hub->limited_power = 1;
- else
hub->limited_power = 0;
+ else
+ hub->limited_power = 1;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");
diff --git a/trunk/drivers/usb/core/message.c b/trunk/drivers/usb/core/message.c
index 98fcddba6908..d8f7b089a8f0 100644
--- a/trunk/drivers/usb/core/message.c
+++ b/trunk/drivers/usb/core/message.c
@@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
- usb_endpoint_num(&urb->ep->desc),
- usb_urb_dir_in(urb) ? "in" : "out",
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
@@ -250,8 +250,7 @@ static void sg_clean (struct usb_sg_request *io)
io->urbs = NULL;
}
if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
- io->sg, io->nents);
+ usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = NULL;
}
@@ -279,8 +278,8 @@ static void sg_complete (struct urb *urb)
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
- usb_endpoint_num(&urb->ep->desc),
- usb_urb_dir_in(urb) ? "in" : "out",
+ usb_pipeendpoint (urb->pipe),
+ usb_pipein (urb->pipe) ? "in" : "out",
status, io->status);
// BUG ();
}
@@ -380,8 +379,7 @@ int usb_sg_init (
*/
dma = (dev->dev.dma_mask != NULL);
if (dma)
- io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
- sg, nents);
+ io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
else
io->entries = nents;
@@ -1015,11 +1013,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
- if (ep) {
- ep->enabled = 0;
- usb_hcd_flush_endpoint(dev, ep);
- usb_hcd_disable_endpoint(dev, ep);
- }
+ if (ep && dev->bus)
+ usb_hcd_endpoint_disable(dev, ep);
}
/**
@@ -1101,21 +1096,23 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
* Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
* For control endpoints, both the input and output sides are handled.
*/
-void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+static void
+usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
- int epnum = usb_endpoint_num(&ep->desc);
- int is_out = usb_endpoint_dir_out(&ep->desc);
- int is_control = usb_endpoint_xfer_control(&ep->desc);
+ unsigned int epaddr = ep->desc.bEndpointAddress;
+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
+ int is_control;
- if (is_out || is_control) {
+ is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_CONTROL);
+ if (usb_endpoint_out(epaddr) || is_control) {
usb_settoggle(dev, epnum, 1, 0);
dev->ep_out[epnum] = ep;
}
- if (!is_out || is_control) {
+ if (!usb_endpoint_out(epaddr) || is_control) {
usb_settoggle(dev, epnum, 0, 0);
dev->ep_in[epnum] = ep;
}
- ep->enabled = 1;
}
/*
@@ -1174,7 +1171,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
struct usb_host_interface *alt;
int ret;
int manual = 0;
- int changed;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@@ -1214,8 +1210,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
- changed = (iface->cur_altsetting != alt);
- if (changed && device_is_registered(&iface->dev))
+ if (device_is_registered(&iface->dev))
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface);
@@ -1252,7 +1247,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* (Likewise, EP0 never "halts" on well designed devices.)
*/
usb_enable_interface(dev, iface);
- if (changed && device_is_registered(&iface->dev))
+ if (device_is_registered(&iface->dev))
usb_create_sysfs_intf_files(iface);
return 0;
@@ -1333,7 +1328,7 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
-static void usb_release_interface(struct device *dev)
+void usb_release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@@ -1486,9 +1481,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
* channels are available independently; and choosing between open
* standard device protocols (like CDC) or proprietary ones.
*
- * Note that a non-authorized device (dev->authorized == 0) will only
- * be put in unconfigured mode.
- *
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
@@ -1510,7 +1502,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL;
int n, nintf;
- if (dev->authorized == 0 || configuration == -1)
+ if (configuration == -1)
configuration = 0;
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
diff --git a/trunk/drivers/usb/core/quirks.c b/trunk/drivers/usb/core/quirks.c
index d42c561c75f1..ebf3dc20110a 100644
--- a/trunk/drivers/usb/core/quirks.c
+++ b/trunk/drivers/usb/core/quirks.c
@@ -32,6 +32,52 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+ /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
+ { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* SGS Thomson Microelectronics 4in1 card reader */
+ { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
+ { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Benq S2W 3300U */
+ { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Canon, Inc. CanoScan N1240U/LiDE30 */
+ { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Canon, Inc. CanoScan N650U/N656U */
+ { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Canon, Inc. CanoScan 1220U */
+ { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
+ { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* old Cannon scanner */
+ { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Seiko Epson Corp. Perfection 1200 */
+ { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Seiko Epson Corp. Perfection 660 */
+ { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Epson Perfection 1260 Photo */
+ { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Seiko Epson Corp - Perfection 1670 */
+ { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* EPSON Perfection 2480 */
+ { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Seiko Epson Corp.*/
+ { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Samsung ML-2010 printer */
+ { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Samsung ML-2510 Series printer */
+ { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Elsa MicroLink 56k (V.250) */
+ { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Ultima Electronics Corp.*/
+ { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* Genesys USB-to-IDE */
+ { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* USB Graphical LCD - EEH Datalink GmbH */
+ { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -39,15 +85,44 @@ static const struct usb_device_id usb_quirk_list[] = {
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Agfa Snapscan1212u */
+ { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Seagate RSS LLC */
+ { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Umax [hex] Astra 3400U */
+ { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Alcor multi-card reader */
+ { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* Canon EOS 5D in PC Connection mode */
+ { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* RIM Blackberry */
+ { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* Apple iPhone */
+ { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
/* SKYMEDI USB_DRIVE */
{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */
};
+static void usb_autosuspend_quirk(struct usb_device *udev)
+{
+#ifdef CONFIG_USB_SUSPEND
+ /* disable autosuspend, but allow the user to re-enable it via sysfs */
+ udev->autosuspend_disabled = 1;
+#endif
+}
+
static const struct usb_device_id *find_id(struct usb_device *udev)
{
const struct usb_device_id *id = usb_quirk_list;
@@ -74,9 +149,13 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
+ /* do any special quirk handling here if needed */
+ if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
+ usb_autosuspend_quirk(udev);
+
/* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
- udev->autosuspend_disabled = 1;
+ udev->autosuspend_delay = -1;
#endif
}
diff --git a/trunk/drivers/usb/core/sysfs.c b/trunk/drivers/usb/core/sysfs.c
index b04afd06e502..2ab222be8fd1 100644
--- a/trunk/drivers/usb/core/sysfs.c
+++ b/trunk/drivers/usb/core/sysfs.c
@@ -169,16 +169,6 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
-static ssize_t
-show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct usb_device *udev;
-
- udev = to_usb_device(dev);
- return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
-}
-static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
-
#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
@@ -423,44 +413,6 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
-
-
-/* show if the device is authorized (1) or not (0) */
-static ssize_t usb_dev_authorized_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct usb_device *usb_dev = to_usb_device(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
-}
-
-
-/*
- * Authorize a device to be used in the system
- *
- * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
- */
-static ssize_t usb_dev_authorized_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- ssize_t result;
- struct usb_device *usb_dev = to_usb_device(dev);
- unsigned val;
- result = sscanf(buf, "%u\n", &val);
- if (result != 1)
- result = -EINVAL;
- else if (val == 0)
- result = usb_deauthorize_device(usb_dev);
- else
- result = usb_authorize_device(usb_dev);
- return result < 0? result : size;
-}
-
-static DEVICE_ATTR(authorized, 0644,
- usb_dev_authorized_show, usb_dev_authorized_store);
-
-
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
@@ -468,7 +420,6 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
&dev_attr_bMaxPower.attr,
- &dev_attr_urbnum.attr,
/* device attributes */
&dev_attr_idVendor.attr,
&dev_attr_idProduct.attr,
@@ -484,7 +435,6 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
- &dev_attr_authorized.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
diff --git a/trunk/drivers/usb/core/urb.c b/trunk/drivers/usb/core/urb.c
index c20c03aaf012..be630228461c 100644
--- a/trunk/drivers/usb/core/urb.c
+++ b/trunk/drivers/usb/core/urb.c
@@ -3,7 +3,6 @@
#include
#include
#include
-#include
#include
#include
#include "hcd.h"
@@ -39,6 +38,7 @@ void usb_init_urb(struct urb *urb)
if (urb) {
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
+ spin_lock_init(&urb->lock);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
@@ -277,58 +277,44 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
- int xfertype, max;
- struct usb_device *dev;
- struct usb_host_endpoint *ep;
- int is_out;
+ int pipe, temp, max;
+ struct usb_device *dev;
+ int is_out;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
- if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
+ if (!(dev = urb->dev) ||
+ (dev->state < USB_STATE_DEFAULT) ||
+ (!dev->bus) || (dev->devnum <= 0))
return -ENODEV;
+ if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
+ || dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
- /* For now, get the endpoint from the pipe. Eventually drivers
- * will be required to set urb->ep directly and we will eliminate
- * urb->pipe.
- */
- ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep)
- return -ENOENT;
-
- urb->ep = ep;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
- xfertype = usb_endpoint_type(&ep->desc);
- if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
- struct usb_ctrlrequest *setup =
- (struct usb_ctrlrequest *) urb->setup_packet;
-
- if (!setup)
- return -ENOEXEC;
- is_out = !(setup->bRequestType & USB_DIR_IN) ||
- !setup->wLength;
- } else {
- is_out = usb_endpoint_dir_out(&ep->desc);
- }
-
- /* Cache the direction for later use */
- urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
- (is_out ? URB_DIR_OUT : URB_DIR_IN);
+ pipe = urb->pipe;
+ temp = usb_pipetype(pipe);
+ is_out = usb_pipeout(pipe);
- if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
- dev->state < USB_STATE_CONFIGURED)
+ if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
- max = le16_to_cpu(ep->desc.wMaxPacketSize);
+ /* FIXME there should be a sharable lock protecting us against
+ * config/altsetting changes and disconnects, kicking in here.
+ * (here == before maxpacket, and eventually endpoint type,
+ * checks get made.)
+ */
+
+ max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
+ usb_pipeendpoint(pipe), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -337,7 +323,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
- if (xfertype == USB_ENDPOINT_XFER_ISOC) {
+ if (temp == PIPE_ISOCHRONOUS) {
int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -372,20 +358,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
- URB_NO_INTERRUPT | URB_DIR_MASK);
- switch (xfertype) {
- case USB_ENDPOINT_XFER_BULK:
+ URB_NO_INTERRUPT);
+ switch (temp) {
+ case PIPE_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
- case USB_ENDPOINT_XFER_CONTROL:
+ case PIPE_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
- case USB_ENDPOINT_XFER_ISOC:
+ case PIPE_ISOCHRONOUS:
allowed |= URB_ISO_ASAP;
break;
}
@@ -407,9 +393,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
- switch (xfertype) {
- case USB_ENDPOINT_XFER_ISOC:
- case USB_ENDPOINT_XFER_INT:
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
@@ -419,27 +405,29 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
- max = 1024 * 8;
+ temp = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
- if (xfertype == USB_ENDPOINT_XFER_INT) {
+ if (temp == PIPE_INTERRUPT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
- max = 128;
+ temp = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
- max = 1024;
+ temp = 1024;
}
break;
default:
return -EINVAL;
}
- /* Round down to a power of 2, no more than max */
- urb->interval = min(max, 1 << ilog2(urb->interval));
+ /* power of two? */
+ while (temp > urb->interval)
+ temp >>= 1;
+ urb->interval = temp;
}
return usb_hcd_submit_urb(urb, mem_flags);
@@ -508,10 +496,8 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
- if (!urb->dev)
+ if (!(urb->dev && urb->dev->bus))
return -ENODEV;
- if (!urb->ep)
- return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
@@ -537,21 +523,19 @@ int usb_unlink_urb(struct urb *urb)
*/
void usb_kill_urb(struct urb *urb)
{
- static DEFINE_MUTEX(reject_mutex);
-
might_sleep();
- if (!(urb && urb->dev && urb->ep))
+ if (!(urb && urb->dev && urb->dev->bus))
return;
- mutex_lock(&reject_mutex);
+ spin_lock_irq(&urb->lock);
++urb->reject;
- mutex_unlock(&reject_mutex);
+ spin_unlock_irq(&urb->lock);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
- mutex_lock(&reject_mutex);
+ spin_lock_irq(&urb->lock);
--urb->reject;
- mutex_unlock(&reject_mutex);
+ spin_unlock_irq(&urb->lock);
}
/**
diff --git a/trunk/drivers/usb/core/usb.c b/trunk/drivers/usb/core/usb.c
index c99938d5f78e..0fee5c66fd64 100644
--- a/trunk/drivers/usb/core/usb.c
+++ b/trunk/drivers/usb/core/usb.c
@@ -223,15 +223,6 @@ static void ksuspend_usb_cleanup(void)
#endif /* CONFIG_PM */
-
-/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
-static unsigned usb_bus_is_wusb(struct usb_bus *bus)
-{
- struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
- return hcd->wireless;
-}
-
-
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
@@ -248,8 +239,6 @@ struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
- struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
- unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -266,14 +255,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
- atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
- usb_enable_endpoint(dev, &dev->ep0);
- dev->can_submit = 1;
+ dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
@@ -288,7 +275,6 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.parent = bus->controller;
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
- root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
@@ -315,12 +301,6 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
- if (root_hub) /* Root hub always ok [and always wired] */
- dev->authorized = 1;
- else {
- dev->authorized = usb_hcd->authorized_default;
- dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
- }
return dev;
}
@@ -768,7 +748,7 @@ void usb_buffer_unmap(struct urb *urb)
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
- * @is_in: mapping transfer direction
+ * @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
@@ -791,13 +771,14 @@ void usb_buffer_unmap(struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
-int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
+int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
+ || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
@@ -805,7 +786,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
// FIXME generic api broken like pci, can't report errors
return dma_map_sg(controller, sg, nents,
- is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -818,14 +799,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
- * @is_in: mapping transfer direction
+ * @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
-void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -838,20 +819,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
return;
dma_sync_sg(controller, sg, n_hw_ents,
- is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
- * @is_in: mapping transfer direction
+ * @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
-void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
+void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -864,7 +845,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
return;
dma_unmap_sg(controller, sg, n_hw_ents,
- is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
diff --git a/trunk/drivers/usb/core/usb.h b/trunk/drivers/usb/core/usb.h
index c52626c51f70..ad5fa0338f49 100644
--- a/trunk/drivers/usb/core/usb.h
+++ b/trunk/drivers/usb/core/usb.h
@@ -8,22 +8,17 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
-extern void usb_enable_endpoint(struct usb_device *dev,
- struct usb_host_endpoint *ep);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
-extern int usb_deauthorize_device (struct usb_device *);
-extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
-extern int usb_choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,
diff --git a/trunk/drivers/usb/gadget/Kconfig b/trunk/drivers/usb/gadget/Kconfig
index f81d08d6538b..767aed5b4bea 100644
--- a/trunk/drivers/usb/gadget/Kconfig
+++ b/trunk/drivers/usb/gadget/Kconfig
@@ -67,17 +67,6 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
-config USB_GADGET_DEBUG_FS
- boolean "Debugging information files in debugfs"
- depends on USB_GADGET && DEBUG_FS
- help
- Some of the drivers in the "gadget" framework can expose
- debugging information in files under /sys/kernel/debug/.
- The information in these files may help when you're
- troubleshooting or bringing up a driver on a new board.
- Enable these files by choosing "Y" here. If in doubt, or
- to conserve kernel memory, say "N".
-
config USB_GADGET_SELECTED
boolean
@@ -114,20 +103,6 @@ config USB_AMD5536UDC
default USB_GADGET
select USB_GADGET_SELECTED
-config USB_GADGET_ATMEL_USBA
- boolean "Atmel USBA"
- select USB_GADGET_DUALSPEED
- depends on AVR32
- help
- USBA is the integrated high-speed USB Device controller on
- the AT32AP700x processors from Atmel.
-
-config USB_ATMEL_USBA
- tristate
- depends on USB_GADGET_ATMEL_USBA
- default USB_GADGET
- select USB_GADGET_SELECTED
-
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -253,6 +228,7 @@ config USB_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
+
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
diff --git a/trunk/drivers/usb/gadget/Makefile b/trunk/drivers/usb/gadget/Makefile
index 904e57bf6112..1bc0f03550ce 100644
--- a/trunk/drivers/usb/gadget/Makefile
+++ b/trunk/drivers/usb/gadget/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
-obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
diff --git a/trunk/drivers/usb/gadget/amd5536udc.c b/trunk/drivers/usb/gadget/amd5536udc.c
index 1c8040602525..714156ca8fe4 100644
--- a/trunk/drivers/usb/gadget/amd5536udc.c
+++ b/trunk/drivers/usb/gadget/amd5536udc.c
@@ -69,7 +69,7 @@
/* gadget stack */
#include
-#include
+#include
/* udc specific */
#include "amd5536udc.h"
@@ -3244,6 +3244,7 @@ static int udc_pci_probe(
retval = -ENOMEM;
goto finished;
}
+ memset(dev, 0, sizeof(struct udc));
/* pci setup */
if (pci_enable_device(pdev) < 0) {
@@ -3285,12 +3286,14 @@ static int udc_pci_probe(
pci_set_drvdata(pdev, dev);
- /* chip revision for Hs AMD5536 */
- dev->chiprev = pdev->revision;
+ /* chip revision */
+ dev->chiprev = 0;
pci_set_master(pdev);
pci_set_mwi(pdev);
+ /* chip rev for Hs AMD5536 */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
/* init dma pools */
if (use_dma) {
retval = init_dma_pools(dev);
diff --git a/trunk/drivers/usb/gadget/at91_udc.c b/trunk/drivers/usb/gadget/at91_udc.c
index a6adf7e0f6f8..63d7d6568699 100644
--- a/trunk/drivers/usb/gadget/at91_udc.c
+++ b/trunk/drivers/usb/gadget/at91_udc.c
@@ -38,7 +38,7 @@
#include
#include
#include
-#include
+#include
#include
#include
diff --git a/trunk/drivers/usb/gadget/atmel_usba_udc.c b/trunk/drivers/usb/gadget/atmel_usba_udc.c
deleted file mode 100644
index 4fb5ff469574..000000000000
--- a/trunk/drivers/usb/gadget/atmel_usba_udc.c
+++ /dev/null
@@ -1,2077 +0,0 @@
-/*
- * Driver for the Atmel USBA high speed USB device controller
- *
- * Copyright (C) 2005-2007 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "atmel_usba_udc.h"
-
-
-static struct usba_udc the_udc;
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
-#include
-#include
-
-static int queue_dbg_open(struct inode *inode, struct file *file)
-{
- struct usba_ep *ep = inode->i_private;
- struct usba_request *req, *req_copy;
- struct list_head *queue_data;
-
- queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
- if (!queue_data)
- return -ENOMEM;
- INIT_LIST_HEAD(queue_data);
-
- spin_lock_irq(&ep->udc->lock);
- list_for_each_entry(req, &ep->queue, queue) {
- req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
- if (!req_copy)
- goto fail;
- memcpy(req_copy, req, sizeof(*req_copy));
- list_add_tail(&req_copy->queue, queue_data);
- }
- spin_unlock_irq(&ep->udc->lock);
-
- file->private_data = queue_data;
- return 0;
-
-fail:
- spin_unlock_irq(&ep->udc->lock);
- list_for_each_entry_safe(req, req_copy, queue_data, queue) {
- list_del(&req->queue);
- kfree(req);
- }
- kfree(queue_data);
- return -ENOMEM;
-}
-
-/*
- * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
- *
- * b: buffer address
- * l: buffer length
- * I/i: interrupt/no interrupt
- * Z/z: zero/no zero
- * S/s: short ok/short not ok
- * s: status
- * n: nr_packets
- * F/f: submitted/not submitted to FIFO
- * D/d: using/not using DMA
- * L/l: last transaction/not last transaction
- */
-static ssize_t queue_dbg_read(struct file *file, char __user *buf,
- size_t nbytes, loff_t *ppos)
-{
- struct list_head *queue = file->private_data;
- struct usba_request *req, *tmp_req;
- size_t len, remaining, actual = 0;
- char tmpbuf[38];
-
- if (!access_ok(VERIFY_WRITE, buf, nbytes))
- return -EFAULT;
-
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
- list_for_each_entry_safe(req, tmp_req, queue, queue) {
- len = snprintf(tmpbuf, sizeof(tmpbuf),
- "%8p %08x %c%c%c %5d %c%c%c\n",
- req->req.buf, req->req.length,
- req->req.no_interrupt ? 'i' : 'I',
- req->req.zero ? 'Z' : 'z',
- req->req.short_not_ok ? 's' : 'S',
- req->req.status,
- req->submitted ? 'F' : 'f',
- req->using_dma ? 'D' : 'd',
- req->last_transaction ? 'L' : 'l');
- len = min(len, sizeof(tmpbuf));
- if (len > nbytes)
- break;
-
- list_del(&req->queue);
- kfree(req);
-
- remaining = __copy_to_user(buf, tmpbuf, len);
- actual += len - remaining;
- if (remaining)
- break;
-
- nbytes -= len;
- buf += len;
- }
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
-
- return actual;
-}
-
-static int queue_dbg_release(struct inode *inode, struct file *file)
-{
- struct list_head *queue_data = file->private_data;
- struct usba_request *req, *tmp_req;
-
- list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
- list_del(&req->queue);
- kfree(req);
- }
- kfree(queue_data);
- return 0;
-}
-
-static int regs_dbg_open(struct inode *inode, struct file *file)
-{
- struct usba_udc *udc;
- unsigned int i;
- u32 *data;
- int ret = -ENOMEM;
-
- mutex_lock(&inode->i_mutex);
- udc = inode->i_private;
- data = kmalloc(inode->i_size, GFP_KERNEL);
- if (!data)
- goto out;
-
- spin_lock_irq(&udc->lock);
- for (i = 0; i < inode->i_size / 4; i++)
- data[i] = __raw_readl(udc->regs + i * 4);
- spin_unlock_irq(&udc->lock);
-
- file->private_data = data;
- ret = 0;
-
-out:
- mutex_unlock(&inode->i_mutex);
-
- return ret;
-}
-
-static ssize_t regs_dbg_read(struct file *file, char __user *buf,
- size_t nbytes, loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int ret;
-
- mutex_lock(&inode->i_mutex);
- ret = simple_read_from_buffer(buf, nbytes, ppos,
- file->private_data,
- file->f_dentry->d_inode->i_size);
- mutex_unlock(&inode->i_mutex);
-
- return ret;
-}
-
-static int regs_dbg_release(struct inode *inode, struct file *file)
-{
- kfree(file->private_data);
- return 0;
-}
-
-const struct file_operations queue_dbg_fops = {
- .owner = THIS_MODULE,
- .open = queue_dbg_open,
- .llseek = no_llseek,
- .read = queue_dbg_read,
- .release = queue_dbg_release,
-};
-
-const struct file_operations regs_dbg_fops = {
- .owner = THIS_MODULE,
- .open = regs_dbg_open,
- .llseek = generic_file_llseek,
- .read = regs_dbg_read,
- .release = regs_dbg_release,
-};
-
-static void usba_ep_init_debugfs(struct usba_udc *udc,
- struct usba_ep *ep)
-{
- struct dentry *ep_root;
-
- ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
- if (!ep_root)
- goto err_root;
- ep->debugfs_dir = ep_root;
-
- ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
- ep, &queue_dbg_fops);
- if (!ep->debugfs_queue)
- goto err_queue;
-
- if (ep->can_dma) {
- ep->debugfs_dma_status
- = debugfs_create_u32("dma_status", 0400, ep_root,
- &ep->last_dma_status);
- if (!ep->debugfs_dma_status)
- goto err_dma_status;
- }
- if (ep_is_control(ep)) {
- ep->debugfs_state
- = debugfs_create_u32("state", 0400, ep_root,
- &ep->state);
- if (!ep->debugfs_state)
- goto err_state;
- }
-
- return;
-
-err_state:
- if (ep->can_dma)
- debugfs_remove(ep->debugfs_dma_status);
-err_dma_status:
- debugfs_remove(ep->debugfs_queue);
-err_queue:
- debugfs_remove(ep_root);
-err_root:
- dev_err(&ep->udc->pdev->dev,
- "failed to create debugfs directory for %s\n", ep->ep.name);
-}
-
-static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
-{
- debugfs_remove(ep->debugfs_queue);
- debugfs_remove(ep->debugfs_dma_status);
- debugfs_remove(ep->debugfs_state);
- debugfs_remove(ep->debugfs_dir);
- ep->debugfs_dma_status = NULL;
- ep->debugfs_dir = NULL;
-}
-
-static void usba_init_debugfs(struct usba_udc *udc)
-{
- struct dentry *root, *regs;
- struct resource *regs_resource;
-
- root = debugfs_create_dir(udc->gadget.name, NULL);
- if (IS_ERR(root) || !root)
- goto err_root;
- udc->debugfs_root = root;
-
- regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops);
- if (!regs)
- goto err_regs;
-
- regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
- CTRL_IOMEM_ID);
- regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
- udc->debugfs_regs = regs;
-
- usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
-
- return;
-
-err_regs:
- debugfs_remove(root);
-err_root:
- udc->debugfs_root = NULL;
- dev_err(&udc->pdev->dev, "debugfs is not available\n");
-}
-
-static void usba_cleanup_debugfs(struct usba_udc *udc)
-{
- usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
- debugfs_remove(udc->debugfs_regs);
- debugfs_remove(udc->debugfs_root);
- udc->debugfs_regs = NULL;
- udc->debugfs_root = NULL;
-}
-#else
-static inline void usba_ep_init_debugfs(struct usba_udc *udc,
- struct usba_ep *ep)
-{
-
-}
-
-static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
-{
-
-}
-
-static inline void usba_init_debugfs(struct usba_udc *udc)
-{
-
-}
-
-static inline void usba_cleanup_debugfs(struct usba_udc *udc)
-{
-
-}
-#endif
-
-static int vbus_is_present(struct usba_udc *udc)
-{
- if (udc->vbus_pin != -1)
- return gpio_get_value(udc->vbus_pin);
-
- /* No Vbus detection: Assume always present */
- return 1;
-}
-
-static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
-{
- unsigned long tmp;
-
- DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
- for (; len > 0; len -= 4, buf += 4, fifo += 4) {
- tmp = *(unsigned long *)buf;
- if (len >= 4) {
- DBG(DBG_FIFO, " -> %08lx\n", tmp);
- __raw_writel(tmp, fifo);
- } else {
- do {
- DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24);
- __raw_writeb(tmp >> 24, fifo);
- fifo++;
- tmp <<= 8;
- } while (--len);
- break;
- }
- }
-}
-
-static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
-{
- union {
- unsigned long *w;
- unsigned char *b;
- } p;
- unsigned long tmp;
-
- DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
- for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
- if (len >= 4) {
- tmp = __raw_readl(fifo);
- *p.w = tmp;
- DBG(DBG_FIFO, " -> %08lx\n", tmp);
- } else {
- do {
- tmp = __raw_readb(fifo);
- *p.b = tmp;
- DBG(DBG_FIFO, " -> %02lx\n", tmp);
- fifo++, p.b++;
- } while (--len);
- }
- }
-}
-
-static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
-{
- unsigned int transaction_len;
-
- transaction_len = req->req.length - req->req.actual;
- req->last_transaction = 1;
- if (transaction_len > ep->ep.maxpacket) {
- transaction_len = ep->ep.maxpacket;
- req->last_transaction = 0;
- } else if (transaction_len == ep->ep.maxpacket && req->req.zero)
- req->last_transaction = 0;
-
- DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
- ep->ep.name, req, transaction_len,
- req->last_transaction ? ", done" : "");
-
- copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
- usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
- req->req.actual += transaction_len;
-}
-
-static void submit_request(struct usba_ep *ep, struct usba_request *req)
-{
- DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
- ep->ep.name, req, req->req.length);
-
- req->req.actual = 0;
- req->submitted = 1;
-
- if (req->using_dma) {
- if (req->req.length == 0) {
- usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
- return;
- }
-
- if (req->req.zero)
- usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
- else
- usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
-
- usba_dma_writel(ep, ADDRESS, req->req.dma);
- usba_dma_writel(ep, CONTROL, req->ctrl);
- } else {
- next_fifo_transaction(ep, req);
- if (req->last_transaction) {
- usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
- } else {
- usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
- }
- }
-}
-
-static void submit_next_request(struct usba_ep *ep)
-{
- struct usba_request *req;
-
- if (list_empty(&ep->queue)) {
- usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
- return;
- }
-
- req = list_entry(ep->queue.next, struct usba_request, queue);
- if (!req->submitted)
- submit_request(ep, req);
-}
-
-static void send_status(struct usba_udc *udc, struct usba_ep *ep)
-{
- ep->state = STATUS_STAGE_IN;
- usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
-}
-
-static void receive_data(struct usba_ep *ep)
-{
- struct usba_udc *udc = ep->udc;
- struct usba_request *req;
- unsigned long status;
- unsigned int bytecount, nr_busy;
- int is_complete = 0;
-
- status = usba_ep_readl(ep, STA);
- nr_busy = USBA_BFEXT(BUSY_BANKS, status);
-
- DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
-
- while (nr_busy > 0) {
- if (list_empty(&ep->queue)) {
- usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
- break;
- }
- req = list_entry(ep->queue.next,
- struct usba_request, queue);
-
- bytecount = USBA_BFEXT(BYTE_COUNT, status);
-
- if (status & (1 << 31))
- is_complete = 1;
- if (req->req.actual + bytecount >= req->req.length) {
- is_complete = 1;
- bytecount = req->req.length - req->req.actual;
- }
-
- copy_from_fifo(req->req.buf + req->req.actual,
- ep->fifo, bytecount);
- req->req.actual += bytecount;
-
- usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
-
- if (is_complete) {
- DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
- req->req.status = 0;
- list_del_init(&req->queue);
- usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
- spin_unlock(&udc->lock);
- req->req.complete(&ep->ep, &req->req);
- spin_lock(&udc->lock);
- }
-
- status = usba_ep_readl(ep, STA);
- nr_busy = USBA_BFEXT(BUSY_BANKS, status);
-
- if (is_complete && ep_is_control(ep)) {
- send_status(udc, ep);
- break;
- }
- }
-}
-
-static void
-request_complete(struct usba_ep *ep, struct usba_request *req, int status)
-{
- struct usba_udc *udc = ep->udc;
-
- WARN_ON(!list_empty(&req->queue));
-
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
-
- if (req->mapped) {
- dma_unmap_single(
- &udc->pdev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
-
- DBG(DBG_GADGET | DBG_REQ,
- "%s: req %p complete: status %d, actual %u\n",
- ep->ep.name, req, req->req.status, req->req.actual);
-
- spin_unlock(&udc->lock);
- req->req.complete(&ep->ep, &req->req);
- spin_lock(&udc->lock);
-}
-
-static void
-request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
-{
- struct usba_request *req, *tmp_req;
-
- list_for_each_entry_safe(req, tmp_req, list, queue) {
- list_del_init(&req->queue);
- request_complete(ep, req, status);
- }
-}
-
-static int
-usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
-{
- struct usba_ep *ep = to_usba_ep(_ep);
- struct usba_udc *udc = ep->udc;
- unsigned long flags, ept_cfg, maxpacket;
- unsigned int nr_trans;
-
- DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
-
- maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
-
- if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
- || ep->index == 0
- || desc->bDescriptorType != USB_DT_ENDPOINT
- || maxpacket == 0
- || maxpacket > ep->fifo_size) {
- DBG(DBG_ERR, "ep_enable: Invalid argument");
- return -EINVAL;
- }
-
- ep->is_isoc = 0;
- ep->is_in = 0;
-
- if (maxpacket <= 8)
- ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
- else
- /* LSB is bit 1, not 0 */
- ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
-
- DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
- ep->ep.name, ept_cfg, maxpacket);
-
- if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
- ep->is_in = 1;
- ept_cfg |= USBA_EPT_DIR_IN;
- }
-
- switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_CONTROL:
- ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
- ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (!ep->can_isoc) {
- DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
- ep->ep.name);
- return -EINVAL;
- }
-
- /*
- * Bits 11:12 specify number of _additional_
- * transactions per microframe.
- */
- nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
- if (nr_trans > 3)
- return -EINVAL;
-
- ep->is_isoc = 1;
- ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
-
- /*
- * Do triple-buffering on high-bandwidth iso endpoints.
- */
- if (nr_trans > 1 && ep->nr_banks == 3)
- ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
- else
- ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
- ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
- break;
- case USB_ENDPOINT_XFER_BULK:
- ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
- ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
- break;
- case USB_ENDPOINT_XFER_INT:
- ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
- ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
- break;
- }
-
- spin_lock_irqsave(&ep->udc->lock, flags);
-
- if (ep->desc) {
- spin_unlock_irqrestore(&ep->udc->lock, flags);
- DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
- return -EBUSY;
- }
-
- ep->desc = desc;
- ep->ep.maxpacket = maxpacket;
-
- usba_ep_writel(ep, CFG, ept_cfg);
- usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
-
- if (ep->can_dma) {
- u32 ctrl;
-
- usba_writel(udc, INT_ENB,
- (usba_readl(udc, INT_ENB)
- | USBA_BF(EPT_INT, 1 << ep->index)
- | USBA_BF(DMA_INT, 1 << ep->index)));
- ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
- usba_ep_writel(ep, CTL_ENB, ctrl);
- } else {
- usba_writel(udc, INT_ENB,
- (usba_readl(udc, INT_ENB)
- | USBA_BF(EPT_INT, 1 << ep->index)));
- }
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
- (unsigned long)usba_ep_readl(ep, CFG));
- DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
- (unsigned long)usba_readl(udc, INT_ENB));
-
- return 0;
-}
-
-static int usba_ep_disable(struct usb_ep *_ep)
-{
- struct usba_ep *ep = to_usba_ep(_ep);
- struct usba_udc *udc = ep->udc;
- LIST_HEAD(req_list);
- unsigned long flags;
-
- DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
-
- spin_lock_irqsave(&udc->lock, flags);
-
- if (!ep->desc) {
- spin_unlock_irqrestore(&udc->lock, flags);
- DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
- return -EINVAL;
- }
- ep->desc = NULL;
-
- list_splice_init(&ep->queue, &req_list);
- if (ep->can_dma) {
- usba_dma_writel(ep, CONTROL, 0);
- usba_dma_writel(ep, ADDRESS, 0);
- usba_dma_readl(ep, STATUS);
- }
- usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
- usba_writel(udc, INT_ENB,
- usba_readl(udc, INT_ENB)
- & ~USBA_BF(EPT_INT, 1 << ep->index));
-
- request_complete_list(ep, &req_list, -ESHUTDOWN);
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-}
-
-static struct usb_request *
-usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
-{
- struct usba_request *req;
-
- DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
-
- req = kzalloc(sizeof(*req), gfp_flags);
- if (!req)
- return NULL;
-
- INIT_LIST_HEAD(&req->queue);
- req->req.dma = DMA_ADDR_INVALID;
-
- return &req->req;
-}
-
-static void
-usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct usba_request *req = to_usba_req(_req);
-
- DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
-
- kfree(req);
-}
-
-static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
- struct usba_request *req, gfp_t gfp_flags)
-{
- unsigned long flags;
- int ret;
-
- DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
- ep->ep.name, req->req.length, req->req.dma,
- req->req.zero ? 'Z' : 'z',
- req->req.short_not_ok ? 'S' : 's',
- req->req.no_interrupt ? 'I' : 'i');
-
- if (req->req.length > 0x10000) {
- /* Lengths from 0 to 65536 (inclusive) are supported */
- DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
- return -EINVAL;
- }
-
- req->using_dma = 1;
-
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(
- &udc->pdev->dev, req->req.buf, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(
- &udc->pdev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
-
- req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
- | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
- | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
-
- if (ep->is_in)
- req->ctrl |= USBA_DMA_END_BUF_EN;
-
- /*
- * Add this request to the queue and submit for DMA if
- * possible. Check if we're still alive first -- we may have
- * received a reset since last time we checked.
- */
- ret = -ESHUTDOWN;
- spin_lock_irqsave(&udc->lock, flags);
- if (ep->desc) {
- if (list_empty(&ep->queue))
- submit_request(ep, req);
-
- list_add_tail(&req->queue, &ep->queue);
- ret = 0;
- }
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return ret;
-}
-
-static int
-usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
-{
- struct usba_request *req = to_usba_req(_req);
- struct usba_ep *ep = to_usba_ep(_ep);
- struct usba_udc *udc = ep->udc;
- unsigned long flags;
- int ret;
-
- DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
- ep->ep.name, req, _req->length);
-
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
- return -ESHUTDOWN;
-
- req->submitted = 0;
- req->using_dma = 0;
- req->last_transaction = 0;
-
- _req->status = -EINPROGRESS;
- _req->actual = 0;
-
- if (ep->can_dma)
- return queue_dma(udc, ep, req, gfp_flags);
-
- /* May have received a reset since last time we checked */
- ret = -ESHUTDOWN;
- spin_lock_irqsave(&udc->lock, flags);
- if (ep->desc) {
- list_add_tail(&req->queue, &ep->queue);
-
- if (ep->is_in || (ep_is_control(ep)
- && (ep->state == DATA_STAGE_IN
- || ep->state == STATUS_STAGE_IN)))
- usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
- else
- usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
- ret = 0;
- }
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return ret;
-}
-
-static void
-usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
-{
- req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
-}
-
-static int stop_dma(struct usba_ep *ep, u32 *pstatus)
-{
- unsigned int timeout;
- u32 status;
-
- /*
- * Stop the DMA controller. When writing both CH_EN
- * and LINK to 0, the other bits are not affected.
- */
- usba_dma_writel(ep, CONTROL, 0);
-
- /* Wait for the FIFO to empty */
- for (timeout = 40; timeout; --timeout) {
- status = usba_dma_readl(ep, STATUS);
- if (!(status & USBA_DMA_CH_EN))
- break;
- udelay(1);
- }
-
- if (pstatus)
- *pstatus = status;
-
- if (timeout == 0) {
- dev_err(&ep->udc->pdev->dev,
- "%s: timed out waiting for DMA FIFO to empty\n",
- ep->ep.name);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct usba_ep *ep = to_usba_ep(_ep);
- struct usba_udc *udc = ep->udc;
- struct usba_request *req = to_usba_req(_req);
- unsigned long flags;
- u32 status;
-
- DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
- ep->ep.name, req);
-
- spin_lock_irqsave(&udc->lock, flags);
-
- if (req->using_dma) {
- /*
- * If this request is currently being transferred,
- * stop the DMA controller and reset the FIFO.
- */
- if (ep->queue.next == &req->queue) {
- status = usba_dma_readl(ep, STATUS);
- if (status & USBA_DMA_CH_EN)
- stop_dma(ep, &status);
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- ep->last_dma_status = status;
-#endif
-
- usba_writel(udc, EPT_RST, 1 << ep->index);
-
- usba_update_req(ep, req, status);
- }
- }
-
- /*
- * Errors should stop the queue from advancing until the
- * completion function returns.
- */
- list_del_init(&req->queue);
-
- request_complete(ep, req, -ECONNRESET);
-
- /* Process the next request if any */
- submit_next_request(ep);
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-}
-
-static int usba_ep_set_halt(struct usb_ep *_ep, int value)
-{
- struct usba_ep *ep = to_usba_ep(_ep);
- struct usba_udc *udc = ep->udc;
- unsigned long flags;
- int ret = 0;
-
- DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
- value ? "set" : "clear");
-
- if (!ep->desc) {
- DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
- ep->ep.name);
- return -ENODEV;
- }
- if (ep->is_isoc) {
- DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
- ep->ep.name);
- return -ENOTTY;
- }
-
- spin_lock_irqsave(&udc->lock, flags);
-
- /*
- * We can't halt IN endpoints while there are still data to be
- * transferred
- */
- if (!list_empty(&ep->queue)
- || ((value && ep->is_in && (usba_ep_readl(ep, STA)
- & USBA_BF(BUSY_BANKS, -1L))))) {
- ret = -EAGAIN;
- } else {
- if (value)
- usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
- else
- usba_ep_writel(ep, CLR_STA,
- USBA_FORCE_STALL | USBA_TOGGLE_CLR);
- usba_ep_readl(ep, STA);
- }
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return ret;
-}
-
-static int usba_ep_fifo_status(struct usb_ep *_ep)
-{
- struct usba_ep *ep = to_usba_ep(_ep);
-
- return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
-}
-
-static void usba_ep_fifo_flush(struct usb_ep *_ep)
-{
- struct usba_ep *ep = to_usba_ep(_ep);
- struct usba_udc *udc = ep->udc;
-
- usba_writel(udc, EPT_RST, 1 << ep->index);
-}
-
-static const struct usb_ep_ops usba_ep_ops = {
- .enable = usba_ep_enable,
- .disable = usba_ep_disable,
- .alloc_request = usba_ep_alloc_request,
- .free_request = usba_ep_free_request,
- .queue = usba_ep_queue,
- .dequeue = usba_ep_dequeue,
- .set_halt = usba_ep_set_halt,
- .fifo_status = usba_ep_fifo_status,
- .fifo_flush = usba_ep_fifo_flush,
-};
-
-static int usba_udc_get_frame(struct usb_gadget *gadget)
-{
- struct usba_udc *udc = to_usba_udc(gadget);
-
- return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
-}
-
-static int usba_udc_wakeup(struct usb_gadget *gadget)
-{
- struct usba_udc *udc = to_usba_udc(gadget);
- unsigned long flags;
- u32 ctrl;
- int ret = -EINVAL;
-
- spin_lock_irqsave(&udc->lock, flags);
- if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
- ctrl = usba_readl(udc, CTRL);
- usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
- ret = 0;
- }
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return ret;
-}
-
-static int
-usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
-{
- struct usba_udc *udc = to_usba_udc(gadget);
- unsigned long flags;
-
- spin_lock_irqsave(&udc->lock, flags);
- if (is_selfpowered)
- udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
- else
- udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-}
-
-static const struct usb_gadget_ops usba_udc_ops = {
- .get_frame = usba_udc_get_frame,
- .wakeup = usba_udc_wakeup,
- .set_selfpowered = usba_udc_set_selfpowered,
-};
-
-#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
-{ \
- .ep = { \
- .ops = &usba_ep_ops, \
- .name = nam, \
- .maxpacket = maxpkt, \
- }, \
- .udc = &the_udc, \
- .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \
- .fifo_size = maxpkt, \
- .nr_banks = maxbk, \
- .index = idx, \
- .can_dma = dma, \
- .can_isoc = isoc, \
-}
-
-static struct usba_ep usba_ep[] = {
- EP("ep0", 0, 64, 1, 0, 0),
- EP("ep1in-bulk", 1, 512, 2, 1, 1),
- EP("ep2out-bulk", 2, 512, 2, 1, 1),
- EP("ep3in-int", 3, 64, 3, 1, 0),
- EP("ep4out-int", 4, 64, 3, 1, 0),
- EP("ep5in-iso", 5, 1024, 3, 1, 1),
- EP("ep6out-iso", 6, 1024, 3, 1, 1),
-};
-#undef EP
-
-static struct usb_endpoint_descriptor usba_ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = __constant_cpu_to_le16(64),
- /* FIXME: I have no idea what to put here */
- .bInterval = 1,
-};
-
-static void nop_release(struct device *dev)
-{
-
-}
-
-static struct usba_udc the_udc = {
- .gadget = {
- .ops = &usba_udc_ops,
- .ep0 = &usba_ep[0].ep,
- .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list),
- .is_dualspeed = 1,
- .name = "atmel_usba_udc",
- .dev = {
- .bus_id = "gadget",
- .release = nop_release,
- },
- },
-
- .lock = SPIN_LOCK_UNLOCKED,
-};
-
-/*
- * Called with interrupts disabled and udc->lock held.
- */
-static void reset_all_endpoints(struct usba_udc *udc)
-{
- struct usba_ep *ep;
- struct usba_request *req, *tmp_req;
-
- usba_writel(udc, EPT_RST, ~0UL);
-
- ep = to_usba_ep(udc->gadget.ep0);
- list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
- list_del_init(&req->queue);
- request_complete(ep, req, -ECONNRESET);
- }
-
- list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
- spin_unlock(&udc->lock);
- usba_ep_disable(&ep->ep);
- spin_lock(&udc->lock);
- }
- }
-}
-
-static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
-{
- struct usba_ep *ep;
-
- if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
- return to_usba_ep(udc->gadget.ep0);
-
- list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
- u8 bEndpointAddress;
-
- if (!ep->desc)
- continue;
- bEndpointAddress = ep->desc->bEndpointAddress;
- if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
- continue;
- if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
- == (wIndex & USB_ENDPOINT_NUMBER_MASK))
- return ep;
- }
-
- return NULL;
-}
-
-/* Called with interrupts disabled and udc->lock held */
-static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
-{
- usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
- ep->state = WAIT_FOR_SETUP;
-}
-
-static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
-{
- if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
- return 1;
- return 0;
-}
-
-static inline void set_address(struct usba_udc *udc, unsigned int addr)
-{
- u32 regval;
-
- DBG(DBG_BUS, "setting address %u...\n", addr);
- regval = usba_readl(udc, CTRL);
- regval = USBA_BFINS(DEV_ADDR, addr, regval);
- usba_writel(udc, CTRL, regval);
-}
-
-static int do_test_mode(struct usba_udc *udc)
-{
- static const char test_packet_buffer[] = {
- /* JKJKJKJK * 9 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* JJKKJJKK * 8 */
- 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
- /* JJKKJJKK * 8 */
- 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
- /* JJJJJJJKKKKKKK * 8 */
- 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- /* JJJJJJJK * 8 */
- 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
- /* {JKKKKKKK * 10}, JK */
- 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
- };
- struct usba_ep *ep;
- struct device *dev = &udc->pdev->dev;
- int test_mode;
-
- test_mode = udc->test_mode;
-
- /* Start from a clean slate */
- reset_all_endpoints(udc);
-
- switch (test_mode) {
- case 0x0100:
- /* Test_J */
- usba_writel(udc, TST, USBA_TST_J_MODE);
- dev_info(dev, "Entering Test_J mode...\n");
- break;
- case 0x0200:
- /* Test_K */
- usba_writel(udc, TST, USBA_TST_K_MODE);
- dev_info(dev, "Entering Test_K mode...\n");
- break;
- case 0x0300:
- /*
- * Test_SE0_NAK: Force high-speed mode and set up ep0
- * for Bulk IN transfers
- */
- ep = &usba_ep[0];
- usba_writel(udc, TST,
- USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
- usba_ep_writel(ep, CFG,
- USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
- | USBA_EPT_DIR_IN
- | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
- | USBA_BF(BK_NUMBER, 1));
- if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
- set_protocol_stall(udc, ep);
- dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
- } else {
- usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
- dev_info(dev, "Entering Test_SE0_NAK mode...\n");
- }
- break;
- case 0x0400:
- /* Test_Packet */
- ep = &usba_ep[0];
- usba_ep_writel(ep, CFG,
- USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
- | USBA_EPT_DIR_IN
- | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
- | USBA_BF(BK_NUMBER, 1));
- if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
- set_protocol_stall(udc, ep);
- dev_err(dev, "Test_Packet: ep0 not mapped\n");
- } else {
- usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
- usba_writel(udc, TST, USBA_TST_PKT_MODE);
- copy_to_fifo(ep->fifo, test_packet_buffer,
- sizeof(test_packet_buffer));
- usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
- dev_info(dev, "Entering Test_Packet mode...\n");
- }
- break;
- default:
- dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Avoid overly long expressions */
-static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
-{
- if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
- return true;
- return false;
-}
-
-static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
-{
- if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
- return true;
- return false;
-}
-
-static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
-{
- if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
- return true;
- return false;
-}
-
-static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
- struct usb_ctrlrequest *crq)
-{
- int retval = 0;;
-
- switch (crq->bRequest) {
- case USB_REQ_GET_STATUS: {
- u16 status;
-
- if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
- status = cpu_to_le16(udc->devstatus);
- } else if (crq->bRequestType
- == (USB_DIR_IN | USB_RECIP_INTERFACE)) {
- status = __constant_cpu_to_le16(0);
- } else if (crq->bRequestType
- == (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
- struct usba_ep *target;
-
- target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
- if (!target)
- goto stall;
-
- status = 0;
- if (is_stalled(udc, target))
- status |= __constant_cpu_to_le16(1);
- } else
- goto delegate;
-
- /* Write directly to the FIFO. No queueing is done. */
- if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
- goto stall;
- ep->state = DATA_STAGE_IN;
- __raw_writew(status, ep->fifo);
- usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
- break;
- }
-
- case USB_REQ_CLEAR_FEATURE: {
- if (crq->bRequestType == USB_RECIP_DEVICE) {
- if (feature_is_dev_remote_wakeup(crq))
- udc->devstatus
- &= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
- else
- /* Can't CLEAR_FEATURE TEST_MODE */
- goto stall;
- } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
- struct usba_ep *target;
-
- if (crq->wLength != __constant_cpu_to_le16(0)
- || !feature_is_ep_halt(crq))
- goto stall;
- target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
- if (!target)
- goto stall;
-
- usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
- if (target->index != 0)
- usba_ep_writel(target, CLR_STA,
- USBA_TOGGLE_CLR);
- } else {
- goto delegate;
- }
-
- send_status(udc, ep);
- break;
- }
-
- case USB_REQ_SET_FEATURE: {
- if (crq->bRequestType == USB_RECIP_DEVICE) {
- if (feature_is_dev_test_mode(crq)) {
- send_status(udc, ep);
- ep->state = STATUS_STAGE_TEST;
- udc->test_mode = le16_to_cpu(crq->wIndex);
- return 0;
- } else if (feature_is_dev_remote_wakeup(crq)) {
- udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
- } else {
- goto stall;
- }
- } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
- struct usba_ep *target;
-
- if (crq->wLength != __constant_cpu_to_le16(0)
- || !feature_is_ep_halt(crq))
- goto stall;
-
- target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
- if (!target)
- goto stall;
-
- usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
- } else
- goto delegate;
-
- send_status(udc, ep);
- break;
- }
-
- case USB_REQ_SET_ADDRESS:
- if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
- goto delegate;
-
- set_address(udc, le16_to_cpu(crq->wValue));
- send_status(udc, ep);
- ep->state = STATUS_STAGE_ADDR;
- break;
-
- default:
-delegate:
- spin_unlock(&udc->lock);
- retval = udc->driver->setup(&udc->gadget, crq);
- spin_lock(&udc->lock);
- }
-
- return retval;
-
-stall:
- printk(KERN_ERR
- "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
- "halting endpoint...\n",
- ep->ep.name, crq->bRequestType, crq->bRequest,
- le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
- le16_to_cpu(crq->wLength));
- set_protocol_stall(udc, ep);
- return -1;
-}
-
-static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
-{
- struct usba_request *req;
- u32 epstatus;
- u32 epctrl;
-
-restart:
- epstatus = usba_ep_readl(ep, STA);
- epctrl = usba_ep_readl(ep, CTL);
-
- DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
- ep->ep.name, ep->state, epstatus, epctrl);
-
- req = NULL;
- if (!list_empty(&ep->queue))
- req = list_entry(ep->queue.next,
- struct usba_request, queue);
-
- if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
- if (req->submitted)
- next_fifo_transaction(ep, req);
- else
- submit_request(ep, req);
-
- if (req->last_transaction) {
- usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
- }
- goto restart;
- }
- if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
- usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
-
- switch (ep->state) {
- case DATA_STAGE_IN:
- usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
- usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
- ep->state = STATUS_STAGE_OUT;
- break;
- case STATUS_STAGE_ADDR:
- /* Activate our new address */
- usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
- | USBA_FADDR_EN));
- usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
- ep->state = WAIT_FOR_SETUP;
- break;
- case STATUS_STAGE_IN:
- if (req) {
- list_del_init(&req->queue);
- request_complete(ep, req, 0);
- submit_next_request(ep);
- }
- usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
- ep->state = WAIT_FOR_SETUP;
- break;
- case STATUS_STAGE_TEST:
- usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
- ep->state = WAIT_FOR_SETUP;
- if (do_test_mode(udc))
- set_protocol_stall(udc, ep);
- break;
- default:
- printk(KERN_ERR
- "udc: %s: TXCOMP: Invalid endpoint state %d, "
- "halting endpoint...\n",
- ep->ep.name, ep->state);
- set_protocol_stall(udc, ep);
- break;
- }
-
- goto restart;
- }
- if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
- switch (ep->state) {
- case STATUS_STAGE_OUT:
- usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
- usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
-
- if (req) {
- list_del_init(&req->queue);
- request_complete(ep, req, 0);
- }
- ep->state = WAIT_FOR_SETUP;
- break;
-
- case DATA_STAGE_OUT:
- receive_data(ep);
- break;
-
- default:
- usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
- usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
- printk(KERN_ERR
- "udc: %s: RXRDY: Invalid endpoint state %d, "
- "halting endpoint...\n",
- ep->ep.name, ep->state);
- set_protocol_stall(udc, ep);
- break;
- }
-
- goto restart;
- }
- if (epstatus & USBA_RX_SETUP) {
- union {
- struct usb_ctrlrequest crq;
- unsigned long data[2];
- } crq;
- unsigned int pkt_len;
- int ret;
-
- if (ep->state != WAIT_FOR_SETUP) {
- /*
- * Didn't expect a SETUP packet at this
- * point. Clean up any pending requests (which
- * may be successful).
- */
- int status = -EPROTO;
-
- /*
- * RXRDY and TXCOMP are dropped when SETUP
- * packets arrive. Just pretend we received
- * the status packet.
- */
- if (ep->state == STATUS_STAGE_OUT
- || ep->state == STATUS_STAGE_IN) {
- usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
- status = 0;
- }
-
- if (req) {
- list_del_init(&req->queue);
- request_complete(ep, req, status);
- }
- }
-
- pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
- DBG(DBG_HW, "Packet length: %u\n", pkt_len);
- if (pkt_len != sizeof(crq)) {
- printk(KERN_WARNING "udc: Invalid packet length %u "
- "(expected %lu)\n", pkt_len, sizeof(crq));
- set_protocol_stall(udc, ep);
- return;
- }
-
- DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
- copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
-
- /* Free up one bank in the FIFO so that we can
- * generate or receive a reply right away. */
- usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
-
- /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
- ep->state, crq.crq.bRequestType,
- crq.crq.bRequest); */
-
- if (crq.crq.bRequestType & USB_DIR_IN) {
- /*
- * The USB 2.0 spec states that "if wLength is
- * zero, there is no data transfer phase."
- * However, testusb #14 seems to actually
- * expect a data phase even if wLength = 0...
- */
- ep->state = DATA_STAGE_IN;
- } else {
- if (crq.crq.wLength != __constant_cpu_to_le16(0))
- ep->state = DATA_STAGE_OUT;
- else
- ep->state = STATUS_STAGE_IN;
- }
-
- ret = -1;
- if (ep->index == 0)
- ret = handle_ep0_setup(udc, ep, &crq.crq);
- else {
- spin_unlock(&udc->lock);
- ret = udc->driver->setup(&udc->gadget, &crq.crq);
- spin_lock(&udc->lock);
- }
-
- DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
- crq.crq.bRequestType, crq.crq.bRequest,
- le16_to_cpu(crq.crq.wLength), ep->state, ret);
-
- if (ret < 0) {
- /* Let the host know that we failed */
- set_protocol_stall(udc, ep);
- }
- }
-}
-
-static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
-{
- struct usba_request *req;
- u32 epstatus;
- u32 epctrl;
-
- epstatus = usba_ep_readl(ep, STA);
- epctrl = usba_ep_readl(ep, CTL);
-
- DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
-
- while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
- DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
-
- if (list_empty(&ep->queue)) {
- dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
- usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
- return;
- }
-
- req = list_entry(ep->queue.next, struct usba_request, queue);
-
- if (req->using_dma) {
- /* Send a zero-length packet */
- usba_ep_writel(ep, SET_STA,
- USBA_TX_PK_RDY);
- usba_ep_writel(ep, CTL_DIS,
- USBA_TX_PK_RDY);
- list_del_init(&req->queue);
- submit_next_request(ep);
- request_complete(ep, req, 0);
- } else {
- if (req->submitted)
- next_fifo_transaction(ep, req);
- else
- submit_request(ep, req);
-
- if (req->last_transaction) {
- list_del_init(&req->queue);
- submit_next_request(ep);
- request_complete(ep, req, 0);
- }
- }
-
- epstatus = usba_ep_readl(ep, STA);
- epctrl = usba_ep_readl(ep, CTL);
- }
- if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
- DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
- receive_data(ep);
- usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
- }
-}
-
-static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
-{
- struct usba_request *req;
- u32 status, control, pending;
-
- status = usba_dma_readl(ep, STATUS);
- control = usba_dma_readl(ep, CONTROL);
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- ep->last_dma_status = status;
-#endif
- pending = status & control;
- DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
-
- if (status & USBA_DMA_CH_EN) {
- dev_err(&udc->pdev->dev,
- "DMA_CH_EN is set after transfer is finished!\n");
- dev_err(&udc->pdev->dev,
- "status=%#08x, pending=%#08x, control=%#08x\n",
- status, pending, control);
-
- /*
- * try to pretend nothing happened. We might have to
- * do something here...
- */
- }
-
- if (list_empty(&ep->queue))
- /* Might happen if a reset comes along at the right moment */
- return;
-
- if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
- req = list_entry(ep->queue.next, struct usba_request, queue);
- usba_update_req(ep, req, status);
-
- list_del_init(&req->queue);
- submit_next_request(ep);
- request_complete(ep, req, 0);
- }
-}
-
-static irqreturn_t usba_udc_irq(int irq, void *devid)
-{
- struct usba_udc *udc = devid;
- u32 status;
- u32 dma_status;
- u32 ep_status;
-
- spin_lock(&udc->lock);
-
- status = usba_readl(udc, INT_STA);
- DBG(DBG_INT, "irq, status=%#08x\n", status);
-
- if (status & USBA_DET_SUSPEND) {
- usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
- DBG(DBG_BUS, "Suspend detected\n");
- if (udc->gadget.speed != USB_SPEED_UNKNOWN
- && udc->driver && udc->driver->suspend) {
- spin_unlock(&udc->lock);
- udc->driver->suspend(&udc->gadget);
- spin_lock(&udc->lock);
- }
- }
-
- if (status & USBA_WAKE_UP) {
- usba_writel(udc, INT_CLR, USBA_WAKE_UP);
- DBG(DBG_BUS, "Wake Up CPU detected\n");
- }
-
- if (status & USBA_END_OF_RESUME) {
- usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
- DBG(DBG_BUS, "Resume detected\n");
- if (udc->gadget.speed != USB_SPEED_UNKNOWN
- && udc->driver && udc->driver->resume) {
- spin_unlock(&udc->lock);
- udc->driver->resume(&udc->gadget);
- spin_lock(&udc->lock);
- }
- }
-
- dma_status = USBA_BFEXT(DMA_INT, status);
- if (dma_status) {
- int i;
-
- for (i = 1; i < USBA_NR_ENDPOINTS; i++)
- if (dma_status & (1 << i))
- usba_dma_irq(udc, &usba_ep[i]);
- }
-
- ep_status = USBA_BFEXT(EPT_INT, status);
- if (ep_status) {
- int i;
-
- for (i = 0; i < USBA_NR_ENDPOINTS; i++)
- if (ep_status & (1 << i)) {
- if (ep_is_control(&usba_ep[i]))
- usba_control_irq(udc, &usba_ep[i]);
- else
- usba_ep_irq(udc, &usba_ep[i]);
- }
- }
-
- if (status & USBA_END_OF_RESET) {
- struct usba_ep *ep0;
-
- usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
- reset_all_endpoints(udc);
-
- if (status & USBA_HIGH_SPEED) {
- DBG(DBG_BUS, "High-speed bus reset detected\n");
- udc->gadget.speed = USB_SPEED_HIGH;
- } else {
- DBG(DBG_BUS, "Full-speed bus reset detected\n");
- udc->gadget.speed = USB_SPEED_FULL;
- }
-
- ep0 = &usba_ep[0];
- ep0->desc = &usba_ep0_desc;
- ep0->state = WAIT_FOR_SETUP;
- usba_ep_writel(ep0, CFG,
- (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
- | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
- | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
- usba_ep_writel(ep0, CTL_ENB,
- USBA_EPT_ENABLE | USBA_RX_SETUP);
- usba_writel(udc, INT_ENB,
- (usba_readl(udc, INT_ENB)
- | USBA_BF(EPT_INT, 1)
- | USBA_DET_SUSPEND
- | USBA_END_OF_RESUME));
-
- if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
- dev_warn(&udc->pdev->dev,
- "WARNING: EP0 configuration is invalid!\n");
- }
-
- spin_unlock(&udc->lock);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
-{
- struct usba_udc *udc = devid;
- int vbus;
-
- /* debounce */
- udelay(10);
-
- spin_lock(&udc->lock);
-
- /* May happen if Vbus pin toggles during probe() */
- if (!udc->driver)
- goto out;
-
- vbus = gpio_get_value(udc->vbus_pin);
- if (vbus != udc->vbus_prev) {
- if (vbus) {
- usba_writel(udc, CTRL, USBA_EN_USBA);
- usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
- } else {
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- reset_all_endpoints(udc);
- usba_writel(udc, CTRL, 0);
- spin_unlock(&udc->lock);
- udc->driver->disconnect(&udc->gadget);
- spin_lock(&udc->lock);
- }
- udc->vbus_prev = vbus;
- }
-
-out:
- spin_unlock(&udc->lock);
-
- return IRQ_HANDLED;
-}
-
-int usb_gadget_register_driver(struct usb_gadget_driver *driver)
-{
- struct usba_udc *udc = &the_udc;
- unsigned long flags;
- int ret;
-
- if (!udc->pdev)
- return -ENODEV;
-
- spin_lock_irqsave(&udc->lock, flags);
- if (udc->driver) {
- spin_unlock_irqrestore(&udc->lock, flags);
- return -EBUSY;
- }
-
- udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
- udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
- spin_unlock_irqrestore(&udc->lock, flags);
-
- clk_enable(udc->pclk);
- clk_enable(udc->hclk);
-
- ret = driver->bind(&udc->gadget);
- if (ret) {
- DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
- driver->driver.name, ret);
- goto err_driver_bind;
- }
-
- DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
-
- udc->vbus_prev = 0;
- if (udc->vbus_pin != -1)
- enable_irq(gpio_to_irq(udc->vbus_pin));
-
- /* If Vbus is present, enable the controller and wait for reset */
- spin_lock_irqsave(&udc->lock, flags);
- if (vbus_is_present(udc) && udc->vbus_prev == 0) {
- usba_writel(udc, CTRL, USBA_EN_USBA);
- usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
- }
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-
-err_driver_bind:
- udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
- return ret;
-}
-EXPORT_SYMBOL(usb_gadget_register_driver);
-
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
-{
- struct usba_udc *udc = &the_udc;
- unsigned long flags;
-
- if (!udc->pdev)
- return -ENODEV;
- if (driver != udc->driver)
- return -EINVAL;
-
- if (udc->vbus_pin != -1)
- disable_irq(gpio_to_irq(udc->vbus_pin));
-
- spin_lock_irqsave(&udc->lock, flags);
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- reset_all_endpoints(udc);
- spin_unlock_irqrestore(&udc->lock, flags);
-
- /* This will also disable the DP pullup */
- usba_writel(udc, CTRL, 0);
-
- driver->unbind(&udc->gadget);
- udc->gadget.dev.driver = NULL;
- udc->driver = NULL;
-
- clk_disable(udc->hclk);
- clk_disable(udc->pclk);
-
- DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
-
- return 0;
-}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
-static int __init usba_udc_probe(struct platform_device *pdev)
-{
- struct usba_platform_data *pdata = pdev->dev.platform_data;
- struct resource *regs, *fifo;
- struct clk *pclk, *hclk;
- struct usba_udc *udc = &the_udc;
- int irq, ret, i;
-
- regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
- fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
- if (!regs || !fifo)
- return -ENXIO;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- pclk = clk_get(&pdev->dev, "pclk");
- if (IS_ERR(pclk))
- return PTR_ERR(pclk);
- hclk = clk_get(&pdev->dev, "hclk");
- if (IS_ERR(hclk)) {
- ret = PTR_ERR(hclk);
- goto err_get_hclk;
- }
-
- udc->pdev = pdev;
- udc->pclk = pclk;
- udc->hclk = hclk;
- udc->vbus_pin = -1;
-
- ret = -ENOMEM;
- udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
- if (!udc->regs) {
- dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
- goto err_map_regs;
- }
- dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
- (unsigned long)regs->start, udc->regs);
- udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
- if (!udc->fifo) {
- dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
- goto err_map_fifo;
- }
- dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
- (unsigned long)fifo->start, udc->fifo);
-
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- platform_set_drvdata(pdev, udc);
-
- /* Make sure we start from a clean slate */
- clk_enable(pclk);
- usba_writel(udc, CTRL, 0);
- clk_disable(pclk);
-
- INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
- usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
- usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
- usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
- for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
- struct usba_ep *ep = &usba_ep[i];
-
- ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
- ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
- ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
-
- list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
- }
-
- ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
- if (ret) {
- dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
- irq, ret);
- goto err_request_irq;
- }
- udc->irq = irq;
-
- ret = device_add(&udc->gadget.dev);
- if (ret) {
- dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
- goto err_device_add;
- }
-
- if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
- if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
- udc->vbus_pin = pdata->vbus_pin;
-
- ret = request_irq(gpio_to_irq(udc->vbus_pin),
- usba_vbus_irq, 0,
- "atmel_usba_udc", udc);
- if (ret) {
- gpio_free(udc->vbus_pin);
- udc->vbus_pin = -1;
- dev_warn(&udc->pdev->dev,
- "failed to request vbus irq; "
- "assuming always on\n");
- } else {
- disable_irq(gpio_to_irq(udc->vbus_pin));
- }
- }
- }
-
- usba_init_debugfs(udc);
- for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
- usba_ep_init_debugfs(udc, &usba_ep[i]);
-
- return 0;
-
-err_device_add:
- free_irq(irq, udc);
-err_request_irq:
- iounmap(udc->fifo);
-err_map_fifo:
- iounmap(udc->regs);
-err_map_regs:
- clk_put(hclk);
-err_get_hclk:
- clk_put(pclk);
-
- platform_set_drvdata(pdev, NULL);
-
- return ret;
-}
-
-static int __exit usba_udc_remove(struct platform_device *pdev)
-{
- struct usba_udc *udc;
- int i;
-
- udc = platform_get_drvdata(pdev);
-
- for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
- usba_ep_cleanup_debugfs(&usba_ep[i]);
- usba_cleanup_debugfs(udc);
-
- if (udc->vbus_pin != -1)
- gpio_free(udc->vbus_pin);
-
- free_irq(udc->irq, udc);
- iounmap(udc->fifo);
- iounmap(udc->regs);
- clk_put(udc->hclk);
- clk_put(udc->pclk);
-
- device_unregister(&udc->gadget.dev);
-
- return 0;
-}
-
-static struct platform_driver udc_driver = {
- .remove = __exit_p(usba_udc_remove),
- .driver = {
- .name = "atmel_usba_udc",
- },
-};
-
-static int __init udc_init(void)
-{
- return platform_driver_probe(&udc_driver, usba_udc_probe);
-}
-module_init(udc_init);
-
-static void __exit udc_exit(void)
-{
- platform_driver_unregister(&udc_driver);
-}
-module_exit(udc_exit);
-
-MODULE_DESCRIPTION("Atmel USBA UDC driver");
-MODULE_AUTHOR("Haavard Skinnemoen ");
-MODULE_LICENSE("GPL");
diff --git a/trunk/drivers/usb/gadget/atmel_usba_udc.h b/trunk/drivers/usb/gadget/atmel_usba_udc.h
deleted file mode 100644
index a68304e31a68..000000000000
--- a/trunk/drivers/usb/gadget/atmel_usba_udc.h
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Driver for the Atmel USBA high speed USB device controller
- *
- * Copyright (C) 2005-2007 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
-#define __LINUX_USB_GADGET_USBA_UDC_H__
-
-/* USB register offsets */
-#define USBA_CTRL 0x0000
-#define USBA_FNUM 0x0004
-#define USBA_INT_ENB 0x0010
-#define USBA_INT_STA 0x0014
-#define USBA_INT_CLR 0x0018
-#define USBA_EPT_RST 0x001c
-#define USBA_TST 0x00e0
-
-/* USB endpoint register offsets */
-#define USBA_EPT_CFG 0x0000
-#define USBA_EPT_CTL_ENB 0x0004
-#define USBA_EPT_CTL_DIS 0x0008
-#define USBA_EPT_CTL 0x000c
-#define USBA_EPT_SET_STA 0x0014
-#define USBA_EPT_CLR_STA 0x0018
-#define USBA_EPT_STA 0x001c
-
-/* USB DMA register offsets */
-#define USBA_DMA_NXT_DSC 0x0000
-#define USBA_DMA_ADDRESS 0x0004
-#define USBA_DMA_CONTROL 0x0008
-#define USBA_DMA_STATUS 0x000c
-
-/* Bitfields in CTRL */
-#define USBA_DEV_ADDR_OFFSET 0
-#define USBA_DEV_ADDR_SIZE 7
-#define USBA_FADDR_EN (1 << 7)
-#define USBA_EN_USBA (1 << 8)
-#define USBA_DETACH (1 << 9)
-#define USBA_REMOTE_WAKE_UP (1 << 10)
-
-/* Bitfields in FNUM */
-#define USBA_MICRO_FRAME_NUM_OFFSET 0
-#define USBA_MICRO_FRAME_NUM_SIZE 3
-#define USBA_FRAME_NUMBER_OFFSET 3
-#define USBA_FRAME_NUMBER_SIZE 11
-#define USBA_FRAME_NUM_ERROR (1 << 31)
-
-/* Bitfields in INT_ENB/INT_STA/INT_CLR */
-#define USBA_HIGH_SPEED (1 << 0)
-#define USBA_DET_SUSPEND (1 << 1)
-#define USBA_MICRO_SOF (1 << 2)
-#define USBA_SOF (1 << 3)
-#define USBA_END_OF_RESET (1 << 4)
-#define USBA_WAKE_UP (1 << 5)
-#define USBA_END_OF_RESUME (1 << 6)
-#define USBA_UPSTREAM_RESUME (1 << 7)
-#define USBA_EPT_INT_OFFSET 8
-#define USBA_EPT_INT_SIZE 16
-#define USBA_DMA_INT_OFFSET 24
-#define USBA_DMA_INT_SIZE 8
-
-/* Bitfields in EPT_RST */
-#define USBA_RST_OFFSET 0
-#define USBA_RST_SIZE 16
-
-/* Bitfields in USBA_TST */
-#define USBA_SPEED_CFG_OFFSET 0
-#define USBA_SPEED_CFG_SIZE 2
-#define USBA_TST_J_MODE (1 << 2)
-#define USBA_TST_K_MODE (1 << 3)
-#define USBA_TST_PKT_MODE (1 << 4)
-#define USBA_OPMODE2 (1 << 5)
-
-/* Bitfields in EPT_CFG */
-#define USBA_EPT_SIZE_OFFSET 0
-#define USBA_EPT_SIZE_SIZE 3
-#define USBA_EPT_DIR_IN (1 << 3)
-#define USBA_EPT_TYPE_OFFSET 4
-#define USBA_EPT_TYPE_SIZE 2
-#define USBA_BK_NUMBER_OFFSET 6
-#define USBA_BK_NUMBER_SIZE 2
-#define USBA_NB_TRANS_OFFSET 8
-#define USBA_NB_TRANS_SIZE 2
-#define USBA_EPT_MAPPED (1 << 31)
-
-/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
-#define USBA_EPT_ENABLE (1 << 0)
-#define USBA_AUTO_VALID (1 << 1)
-#define USBA_INTDIS_DMA (1 << 3)
-#define USBA_NYET_DIS (1 << 4)
-#define USBA_DATAX_RX (1 << 6)
-#define USBA_MDATA_RX (1 << 7)
-/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
-#define USBA_BUSY_BANK_IE (1 << 18)
-
-/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
-#define USBA_FORCE_STALL (1 << 5)
-#define USBA_TOGGLE_CLR (1 << 6)
-#define USBA_TOGGLE_SEQ_OFFSET 6
-#define USBA_TOGGLE_SEQ_SIZE 2
-#define USBA_ERR_OVFLW (1 << 8)
-#define USBA_RX_BK_RDY (1 << 9)
-#define USBA_KILL_BANK (1 << 9)
-#define USBA_TX_COMPLETE (1 << 10)
-#define USBA_TX_PK_RDY (1 << 11)
-#define USBA_ISO_ERR_TRANS (1 << 11)
-#define USBA_RX_SETUP (1 << 12)
-#define USBA_ISO_ERR_FLOW (1 << 12)
-#define USBA_STALL_SENT (1 << 13)
-#define USBA_ISO_ERR_CRC (1 << 13)
-#define USBA_ISO_ERR_NBTRANS (1 << 13)
-#define USBA_NAK_IN (1 << 14)
-#define USBA_ISO_ERR_FLUSH (1 << 14)
-#define USBA_NAK_OUT (1 << 15)
-#define USBA_CURRENT_BANK_OFFSET 16
-#define USBA_CURRENT_BANK_SIZE 2
-#define USBA_BUSY_BANKS_OFFSET 18
-#define USBA_BUSY_BANKS_SIZE 2
-#define USBA_BYTE_COUNT_OFFSET 20
-#define USBA_BYTE_COUNT_SIZE 11
-#define USBA_SHORT_PACKET (1 << 31)
-
-/* Bitfields in DMA_CONTROL */
-#define USBA_DMA_CH_EN (1 << 0)
-#define USBA_DMA_LINK (1 << 1)
-#define USBA_DMA_END_TR_EN (1 << 2)
-#define USBA_DMA_END_BUF_EN (1 << 3)
-#define USBA_DMA_END_TR_IE (1 << 4)
-#define USBA_DMA_END_BUF_IE (1 << 5)
-#define USBA_DMA_DESC_LOAD_IE (1 << 6)
-#define USBA_DMA_BURST_LOCK (1 << 7)
-#define USBA_DMA_BUF_LEN_OFFSET 16
-#define USBA_DMA_BUF_LEN_SIZE 16
-
-/* Bitfields in DMA_STATUS */
-#define USBA_DMA_CH_ACTIVE (1 << 1)
-#define USBA_DMA_END_TR_ST (1 << 4)
-#define USBA_DMA_END_BUF_ST (1 << 5)
-#define USBA_DMA_DESC_LOAD_ST (1 << 6)
-
-/* Constants for SPEED_CFG */
-#define USBA_SPEED_CFG_NORMAL 0
-#define USBA_SPEED_CFG_FORCE_HIGH 2
-#define USBA_SPEED_CFG_FORCE_FULL 3
-
-/* Constants for EPT_SIZE */
-#define USBA_EPT_SIZE_8 0
-#define USBA_EPT_SIZE_16 1
-#define USBA_EPT_SIZE_32 2
-#define USBA_EPT_SIZE_64 3
-#define USBA_EPT_SIZE_128 4
-#define USBA_EPT_SIZE_256 5
-#define USBA_EPT_SIZE_512 6
-#define USBA_EPT_SIZE_1024 7
-
-/* Constants for EPT_TYPE */
-#define USBA_EPT_TYPE_CONTROL 0
-#define USBA_EPT_TYPE_ISO 1
-#define USBA_EPT_TYPE_BULK 2
-#define USBA_EPT_TYPE_INT 3
-
-/* Constants for BK_NUMBER */
-#define USBA_BK_NUMBER_ZERO 0
-#define USBA_BK_NUMBER_ONE 1
-#define USBA_BK_NUMBER_DOUBLE 2
-#define USBA_BK_NUMBER_TRIPLE 3
-
-/* Bit manipulation macros */
-#define USBA_BF(name, value) \
- (((value) & ((1 << USBA_##name##_SIZE) - 1)) \
- << USBA_##name##_OFFSET)
-#define USBA_BFEXT(name, value) \
- (((value) >> USBA_##name##_OFFSET) \
- & ((1 << USBA_##name##_SIZE) - 1))
-#define USBA_BFINS(name, value, old) \
- (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \
- << USBA_##name##_OFFSET)) \
- | USBA_BF(name, value))
-
-/* Register access macros */
-#define usba_readl(udc, reg) \
- __raw_readl((udc)->regs + USBA_##reg)
-#define usba_writel(udc, reg, value) \
- __raw_writel((value), (udc)->regs + USBA_##reg)
-#define usba_ep_readl(ep, reg) \
- __raw_readl((ep)->ep_regs + USBA_EPT_##reg)
-#define usba_ep_writel(ep, reg, value) \
- __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
-#define usba_dma_readl(ep, reg) \
- __raw_readl((ep)->dma_regs + USBA_DMA_##reg)
-#define usba_dma_writel(ep, reg, value) \
- __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
-
-/* Calculate base address for a given endpoint or DMA controller */
-#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20)
-#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10)
-#define USBA_FIFO_BASE(x) ((x) << 16)
-
-/* Synth parameters */
-#define USBA_NR_ENDPOINTS 7
-
-#define EP0_FIFO_SIZE 64
-#define EP0_EPT_SIZE USBA_EPT_SIZE_64
-#define EP0_NR_BANKS 1
-
-/*
- * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
- * provide this information?
- */
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-#define FIFO_IOMEM_ID 0
-#define CTRL_IOMEM_ID 1
-
-#ifdef DEBUG
-#define DBG_ERR 0x0001 /* report all error returns */
-#define DBG_HW 0x0002 /* debug hardware initialization */
-#define DBG_GADGET 0x0004 /* calls to/from gadget driver */
-#define DBG_INT 0x0008 /* interrupts */
-#define DBG_BUS 0x0010 /* report changes in bus state */
-#define DBG_QUEUE 0x0020 /* debug request queue processing */
-#define DBG_FIFO 0x0040 /* debug FIFO contents */
-#define DBG_DMA 0x0080 /* debug DMA handling */
-#define DBG_REQ 0x0100 /* print out queued request length */
-#define DBG_ALL 0xffff
-#define DBG_NONE 0x0000
-
-#define DEBUG_LEVEL (DBG_ERR)
-#define DBG(level, fmt, ...) \
- do { \
- if ((level) & DEBUG_LEVEL) \
- printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
- } while (0)
-#else
-#define DBG(level, fmt...)
-#endif
-
-enum usba_ctrl_state {
- WAIT_FOR_SETUP,
- DATA_STAGE_IN,
- DATA_STAGE_OUT,
- STATUS_STAGE_IN,
- STATUS_STAGE_OUT,
- STATUS_STAGE_ADDR,
- STATUS_STAGE_TEST,
-};
-/*
- EP_STATE_IDLE,
- EP_STATE_SETUP,
- EP_STATE_IN_DATA,
- EP_STATE_OUT_DATA,
- EP_STATE_SET_ADDR_STATUS,
- EP_STATE_RX_STATUS,
- EP_STATE_TX_STATUS,
- EP_STATE_HALT,
-*/
-
-struct usba_dma_desc {
- dma_addr_t next;
- dma_addr_t addr;
- u32 ctrl;
-};
-
-struct usba_ep {
- int state;
- void __iomem *ep_regs;
- void __iomem *dma_regs;
- void __iomem *fifo;
- struct usb_ep ep;
- struct usba_udc *udc;
-
- struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
-
- u16 fifo_size;
- u8 nr_banks;
- u8 index;
- unsigned int can_dma:1;
- unsigned int can_isoc:1;
- unsigned int is_isoc:1;
- unsigned int is_in:1;
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- u32 last_dma_status;
- struct dentry *debugfs_dir;
- struct dentry *debugfs_queue;
- struct dentry *debugfs_dma_status;
- struct dentry *debugfs_state;
-#endif
-};
-
-struct usba_request {
- struct usb_request req;
- struct list_head queue;
-
- u32 ctrl;
-
- unsigned int submitted:1;
- unsigned int last_transaction:1;
- unsigned int using_dma:1;
- unsigned int mapped:1;
-};
-
-struct usba_udc {
- /* Protect hw registers from concurrent modifications */
- spinlock_t lock;
-
- void __iomem *regs;
- void __iomem *fifo;
-
- struct usb_gadget gadget;
- struct usb_gadget_driver *driver;
- struct platform_device *pdev;
- int irq;
- int vbus_pin;
- struct clk *pclk;
- struct clk *hclk;
-
- u16 devstatus;
-
- u16 test_mode;
- int vbus_prev;
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- struct dentry *debugfs_root;
- struct dentry *debugfs_regs;
-#endif
-};
-
-static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
-{
- return container_of(ep, struct usba_ep, ep);
-}
-
-static inline struct usba_request *to_usba_req(struct usb_request *req)
-{
- return container_of(req, struct usba_request, req);
-}
-
-static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
-{
- return container_of(gadget, struct usba_udc, gadget);
-}
-
-#define ep_is_control(ep) ((ep)->index == 0)
-#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE)
-
-#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/trunk/drivers/usb/gadget/config.c b/trunk/drivers/usb/gadget/config.c
index a4e54b2743f0..c6760aee1e5c 100644
--- a/trunk/drivers/usb/gadget/config.c
+++ b/trunk/drivers/usb/gadget/config.c
@@ -25,7 +25,7 @@
#include
#include
-#include
+#include
/**
diff --git a/trunk/drivers/usb/gadget/dummy_hcd.c b/trunk/drivers/usb/gadget/dummy_hcd.c
index 9db2482bdfa2..d008d1360a7a 100644
--- a/trunk/drivers/usb/gadget/dummy_hcd.c
+++ b/trunk/drivers/usb/gadget/dummy_hcd.c
@@ -46,7 +46,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
static int dummy_urb_enqueue (
struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
unsigned long flags;
- int rc;
if (!urb->transfer_buffer && urb->transfer_buffer_length)
return -EINVAL;
@@ -980,11 +980,6 @@ static int dummy_urb_enqueue (
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
- rc = usb_hcd_link_urb_to_ep(hcd, urb);
- if (rc) {
- kfree(urbp);
- goto done;
- }
if (!dum->udev) {
dum->udev = urb->dev;
@@ -1001,35 +996,36 @@ static int dummy_urb_enqueue (
if (!timer_pending (&dum->timer))
mod_timer (&dum->timer, jiffies + 1);
- done:
- spin_unlock_irqrestore(&dum->lock, flags);
- return rc;
+ spin_unlock_irqrestore (&dum->lock, flags);
+ return 0;
}
-static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
struct dummy *dum;
unsigned long flags;
- int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
-
- rc = usb_hcd_check_unlink_urb(hcd, urb, status);
- if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
- !list_empty(&dum->urbp_list))
+ if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
-
spin_unlock_irqrestore (&dum->lock, flags);
- return rc;
+ return 0;
+}
+
+static void maybe_set_status (struct urb *urb, int status)
+{
+ spin_lock (&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ spin_unlock (&urb->lock);
}
/* transfer up to a frame's worth; caller must own lock */
static int
-transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
- int *status)
+transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
{
struct dummy_request *req;
@@ -1092,20 +1088,24 @@ transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
*
* partially filling a buffer optionally blocks queue advances
* (so completion handlers can clean up the queue) but we don't
- * need to emulate such data-in-flight.
+ * need to emulate such data-in-flight. so we only show part
+ * of the URB_SHORT_NOT_OK effect: completion status.
*/
if (is_short) {
if (host_len == dev_len) {
req->req.status = 0;
- *status = 0;
+ maybe_set_status (urb, 0);
} else if (to_host) {
req->req.status = 0;
if (dev_len > host_len)
- *status = -EOVERFLOW;
+ maybe_set_status (urb, -EOVERFLOW);
else
- *status = 0;
+ maybe_set_status (urb,
+ (urb->transfer_flags
+ & URB_SHORT_NOT_OK)
+ ? -EREMOTEIO : 0);
} else if (!to_host) {
- *status = 0;
+ maybe_set_status (urb, 0);
if (host_len > dev_len)
req->req.status = -EOVERFLOW;
else
@@ -1119,8 +1119,9 @@ transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
req->req.status = 0;
if (urb->transfer_buffer_length == urb->actual_length
&& !(urb->transfer_flags
- & URB_ZERO_PACKET))
- *status = 0;
+ & URB_ZERO_PACKET)) {
+ maybe_set_status (urb, 0);
+ }
}
/* device side completion --> continuable */
@@ -1136,7 +1137,7 @@ transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
}
/* host side completion --> terminate */
- if (*status != -EINPROGRESS)
+ if (urb->status != -EINPROGRESS)
break;
/* rescan to continue with any other queued i/o */
@@ -1247,12 +1248,12 @@ static void dummy_timer (unsigned long _dum)
u8 address;
struct dummy_ep *ep = NULL;
int type;
- int status = -EINPROGRESS;
urb = urbp->urb;
- if (urb->unlinked)
+ if (urb->status != -EINPROGRESS) {
+ /* likely it was just unlinked */
goto return_urb;
- else if (dum->rh_state != DUMMY_RH_RUNNING)
+ } else if (dum->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype (urb->pipe);
@@ -1273,7 +1274,7 @@ static void dummy_timer (unsigned long _dum)
dev_dbg (dummy_dev(dum),
"no ep configured for urb %p\n",
urb);
- status = -EPROTO;
+ maybe_set_status (urb, -EPROTO);
goto return_urb;
}
@@ -1288,7 +1289,7 @@ static void dummy_timer (unsigned long _dum)
/* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
ep->ep.name, urb);
- status = -EPIPE;
+ maybe_set_status (urb, -EPIPE);
goto return_urb;
}
/* FIXME make sure both ends agree on maxpacket */
@@ -1306,7 +1307,7 @@ static void dummy_timer (unsigned long _dum)
w_value = le16_to_cpu(setup.wValue);
if (le16_to_cpu(setup.wLength) !=
urb->transfer_buffer_length) {
- status = -EOVERFLOW;
+ maybe_set_status (urb, -EOVERFLOW);
goto return_urb;
}
@@ -1336,7 +1337,7 @@ static void dummy_timer (unsigned long _dum)
if (setup.bRequestType != Dev_Request)
break;
dum->address = w_value;
- status = 0;
+ maybe_set_status (urb, 0);
dev_dbg (udc_dev(dum), "set_address = %d\n",
w_value);
value = 0;
@@ -1363,7 +1364,7 @@ static void dummy_timer (unsigned long _dum)
if (value == 0) {
dum->devstatus |=
(1 << w_value);
- status = 0;
+ maybe_set_status (urb, 0);
}
} else if (setup.bRequestType == Ep_Request) {
@@ -1375,7 +1376,7 @@ static void dummy_timer (unsigned long _dum)
}
ep2->halted = 1;
value = 0;
- status = 0;
+ maybe_set_status (urb, 0);
}
break;
case USB_REQ_CLEAR_FEATURE:
@@ -1385,7 +1386,7 @@ static void dummy_timer (unsigned long _dum)
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
- status = 0;
+ maybe_set_status (urb, 0);
break;
default:
value = -EOPNOTSUPP;
@@ -1400,7 +1401,7 @@ static void dummy_timer (unsigned long _dum)
}
ep2->halted = 0;
value = 0;
- status = 0;
+ maybe_set_status (urb, 0);
}
break;
case USB_REQ_GET_STATUS:
@@ -1437,7 +1438,7 @@ static void dummy_timer (unsigned long _dum)
urb->actual_length = min (2,
urb->transfer_buffer_length);
value = 0;
- status = 0;
+ maybe_set_status (urb, 0);
}
break;
}
@@ -1464,7 +1465,7 @@ static void dummy_timer (unsigned long _dum)
dev_dbg (udc_dev(dum),
"setup --> %d\n",
value);
- status = -EPIPE;
+ maybe_set_status (urb, -EPIPE);
urb->actual_length = 0;
}
@@ -1481,7 +1482,7 @@ static void dummy_timer (unsigned long _dum)
* report random errors, to debug drivers.
*/
limit = max (limit, periodic_bytes (dum, ep));
- status = -ENOSYS;
+ maybe_set_status (urb, -ENOSYS);
break;
case PIPE_INTERRUPT:
@@ -1495,23 +1496,23 @@ static void dummy_timer (unsigned long _dum)
default:
treat_control_like_bulk:
ep->last_io = jiffies;
- total = transfer(dum, urb, ep, limit, &status);
+ total = transfer (dum, urb, ep, limit);
break;
}
/* incomplete transfer? */
- if (status == -EINPROGRESS)
+ if (urb->status == -EINPROGRESS)
continue;
return_urb:
+ urb->hcpriv = NULL;
list_del (&urbp->urbp_list);
kfree (urbp);
if (ep)
ep->already_seen = ep->setup_stage = 0;
- usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
spin_unlock (&dum->lock);
- usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
+ usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
spin_lock (&dum->lock);
goto restart;
diff --git a/trunk/drivers/usb/gadget/epautoconf.c b/trunk/drivers/usb/gadget/epautoconf.c
index f9d07108bc30..3aa46cfa66ba 100644
--- a/trunk/drivers/usb/gadget/epautoconf.c
+++ b/trunk/drivers/usb/gadget/epautoconf.c
@@ -28,7 +28,7 @@
#include
#include
-#include
+#include
#include "gadget_chips.h"
diff --git a/trunk/drivers/usb/gadget/ether.c b/trunk/drivers/usb/gadget/ether.c
index 9e732bff9df0..f70055473a00 100644
--- a/trunk/drivers/usb/gadget/ether.c
+++ b/trunk/drivers/usb/gadget/ether.c
@@ -19,18 +19,40 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* #define VERBOSE_DEBUG */
+// #define DEBUG 1
+// #define VERBOSE
+
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
+#include
#include
-#include
-#include
+
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
-#include
+#include
+
+#include
+#include
+#include
+#include
#include "gadget_chips.h"
@@ -334,15 +356,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
#define qlen(gadget) \
(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
+/* also defer IRQs on highspeed TX */
+#define TX_DELAY qmult
+
static inline int BITRATE(struct usb_gadget *g)
{
return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
}
#else /* full speed (low speed doesn't do bulk) */
-
-#define qmult 1
-
#define DEVSPEED USB_SPEED_FULL
#define qlen(gadget) DEFAULT_QLEN
@@ -368,7 +390,7 @@ static inline int BITRATE(struct usb_gadget *g)
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE_DEBUG
+#ifdef VERBOSE
#define VDEBUG DEBUG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -808,6 +830,8 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
};
#endif
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -910,15 +934,18 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
/* maxpacket and other transfer characteristics vary by speed. */
-static inline struct usb_endpoint_descriptor *
-ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
- struct usb_endpoint_descriptor *fs)
+#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g,hs,fs) (((void)(g)), (fs))
+
+static inline void __init hs_subset_descriptors(void)
{
- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
- return hs;
- return fs;
}
+#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
@@ -962,19 +989,22 @@ static struct usb_gadget_strings stringtab = {
* complications: class descriptors, and an altsetting.
*/
static int
-config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
+config_buf (enum usb_device_speed speed,
+ u8 *buf, u8 type,
+ unsigned index, int is_otg)
{
int len;
const struct usb_config_descriptor *config;
const struct usb_descriptor_header **function;
- int hs = 0;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ int hs = (speed == USB_SPEED_HIGH);
- if (gadget_is_dualspeed(g)) {
- hs = (g->speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
- }
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
+#else
+#define which_fn(t) (fs_ ## t ## _function)
+#endif
if (index >= device_desc.bNumConfigurations)
return -EINVAL;
@@ -1187,7 +1217,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
if (number)
eth_reset_config (dev);
usb_gadget_vbus_draw(dev->gadget,
- gadget_is_otg(dev->gadget) ? 8 : 100);
+ dev->gadget->is_otg ? 8 : 100);
} else {
char *speed;
unsigned power;
@@ -1369,22 +1399,24 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget->is_dualspeed)
break;
value = min (wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget->is_dualspeed)
break;
// FALLTHROUGH
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- value = config_buf(gadget, req->buf,
+ value = config_buf (gadget->speed, req->buf,
wValue >> 8,
wValue & 0xff,
- gadget_is_otg(gadget));
+ gadget->is_otg);
if (value >= 0)
value = min (wLength, (u16) value);
break;
@@ -1553,12 +1585,12 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
&& rndis_control_intf.bInterfaceNumber
== wIndex) {
u8 *buf;
- u32 n;
/* return the result */
- buf = rndis_get_next_response(dev->rndis_config, &n);
+ buf = rndis_get_next_response (dev->rndis_config,
+ &value);
if (buf) {
- memcpy(req->buf, buf, n);
+ memcpy (req->buf, buf, value);
req->complete = rndis_response_complete;
rndis_free_response(dev->rndis_config, buf);
}
@@ -1957,20 +1989,8 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
spin_lock_irqsave(&dev->req_lock, flags);
- /*
- * this freelist can be empty if an interrupt triggered disconnect()
- * and reconfigured the gadget (shutting down this queue) after the
- * network stack decided to xmit but before we got the spinlock.
- */
- if (list_empty(&dev->tx_reqs)) {
- spin_unlock_irqrestore(&dev->req_lock, flags);
- return 1;
- }
-
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
-
- /* temporarily stop TX queue when the freelist empties */
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2006,11 +2026,12 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
req->length = length;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
- if (gadget_is_dualspeed(dev->gadget))
- req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
- ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
- : 0;
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
+ : 0;
+#endif
retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
switch (retval) {
@@ -2167,7 +2188,8 @@ static int eth_stop (struct net_device *net)
}
if (rndis_active(dev)) {
- rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
+ rndis_set_param_medium (dev->rndis_config,
+ NDIS_MEDIUM_802_3, 0);
(void) rndis_signal_disconnect (dev->rndis_config);
}
@@ -2421,28 +2443,26 @@ eth_bind (struct usb_gadget *gadget)
if (rndis)
device_desc.bNumConfigurations = 2;
- if (gadget_is_dualspeed(gadget)) {
- if (rndis)
- dev_qualifier.bNumConfigurations = 2;
- else if (!cdc)
- dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ if (rndis)
+ dev_qualifier.bNumConfigurations = 2;
+ else if (!cdc)
+ dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
- /* assumes ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ /* assumes ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress =
- fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress =
- fs_sink_desc.bEndpointAddress;
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
- if (status_ep)
- hs_status_desc.bEndpointAddress =
- fs_status_desc.bEndpointAddress;
+ if (status_ep)
+ hs_status_desc.bEndpointAddress =
+ fs_status_desc.bEndpointAddress;
#endif
- }
+#endif /* DUALSPEED */
- if (gadget_is_otg(gadget)) {
+ if (gadget->is_otg) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
eth_config.bMaxPower = 4;
@@ -2578,11 +2598,12 @@ eth_bind (struct usb_gadget *gadget)
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats, &dev->cdc_filter))
goto fail0;
- if (rndis_set_param_vendor(dev->rndis_config, vendorID,
- manufacturer))
+ if (rndis_set_param_vendor (dev->rndis_config, vendorID,
+ manufacturer))
goto fail0;
- if (rndis_set_param_medium(dev->rndis_config,
- NDIS_MEDIUM_802_3, 0))
+ if (rndis_set_param_medium (dev->rndis_config,
+ NDIS_MEDIUM_802_3,
+ 0))
goto fail0;
INFO (dev, "RNDIS ready\n");
}
diff --git a/trunk/drivers/usb/gadget/file_storage.c b/trunk/drivers/usb/gadget/file_storage.c
index 73726c570a6e..965ad7bec7b7 100644
--- a/trunk/drivers/usb/gadget/file_storage.c
+++ b/trunk/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
- * Copyright (C) 2003-2007 Alan Stern
+ * Copyright (C) 2003-2005 Alan Stern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,11 +217,17 @@
*/
-/* #define VERBOSE_DEBUG */
-/* #define DUMP_MSGS */
+#undef DEBUG
+#undef VERBOSE
+#undef DUMP_MSGS
+
+#include
+#include
+#include
#include
+#include
#include
#include
#include
@@ -229,10 +235,18 @@
#include
#include
#include