Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 10 Jul 2007 20:56:13 +0000 (13:56 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 10 Jul 2007 20:56:13 +0000 (13:56 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw: (57 commits)
  [GFS2] Accept old format NFS filehandles
  [GFS2] Small fixes to logging code
  [DLM] dump more lock values
  [GFS2] Remove i_mode passing from NFS File Handle
  [GFS2] Obtaining no_formal_ino from directory entry
  [GFS2] git-gfs2-nmw-build-fix
  [GFS2] System won't suspend with GFS2 file system mounted
  [GFS2] remounting w/o acl option leaves acls enabled
  [GFS2] inode size inconsistency
  [DLM] Telnet to port 21064 can stop all lockspaces
  [GFS2] Fix gfs2_block_truncate_page err return
  [GFS2] Addendum to the journaled file/unmount patch
  [GFS2] Simplify multiple glock aquisition
  [GFS2] assertion failure after writing to journaled file, umount
  [GFS2] Use zero_user_page() in stuffed_readpage()
  [GFS2] Remove bogus '\0' in rgrp.c
  [GFS2] Journaled file write/unstuff bug
  [DLM] don't require FS flag on all nodes
  [GFS2] Fix deallocation issues
  [GFS2] return conflicts for GETLK
  ...

351 files changed:
Documentation/ABI/removed/raw1394_legacy_isochronous [new file with mode: 0644]
Documentation/DocBook/kernel-api.tmpl
Documentation/block/barrier.txt
Documentation/feature-removal-schedule.txt
Documentation/kernel-parameters.txt
Documentation/networking/spider_net.txt [new file with mode: 0644]
Documentation/sched-design-CFS.txt [new file with mode: 0644]
MAINTAINERS
arch/i386/kernel/smpboot.c
arch/i386/kernel/tsc.c
arch/ia64/kernel/setup.c
arch/mips/kernel/smp.c
arch/sparc/kernel/smp.c
arch/sparc64/kernel/smp.c
block/Kconfig
block/cfq-iosched.c
block/elevator.c
block/ll_rw_blk.c
drivers/Kconfig
drivers/acorn/block/fd1772.c
drivers/acorn/block/mfmhd.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/acsi.c [deleted file]
drivers/block/amiflop.c
drivers/block/cciss.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/cdrom/Kconfig [deleted file]
drivers/cdrom/Makefile
drivers/cdrom/aztcd.c [deleted file]
drivers/cdrom/aztcd.h [deleted file]
drivers/cdrom/cdrom.c
drivers/cdrom/cdu31a.c [deleted file]
drivers/cdrom/cdu31a.h [deleted file]
drivers/cdrom/cm206.c [deleted file]
drivers/cdrom/cm206.h [deleted file]
drivers/cdrom/gscd.c [deleted file]
drivers/cdrom/gscd.h [deleted file]
drivers/cdrom/isp16.c [deleted file]
drivers/cdrom/isp16.h [deleted file]
drivers/cdrom/mcdx.c [deleted file]
drivers/cdrom/mcdx.h [deleted file]
drivers/cdrom/optcd.c [deleted file]
drivers/cdrom/optcd.h [deleted file]
drivers/cdrom/sbpcd.c [deleted file]
drivers/cdrom/sbpcd.h [deleted file]
drivers/cdrom/sjcd.c [deleted file]
drivers/cdrom/sjcd.h [deleted file]
drivers/cdrom/sonycd535.c [deleted file]
drivers/cdrom/sonycd535.h [deleted file]
drivers/char/keyboard.c
drivers/char/mem.c
drivers/firewire/fw-card.c
drivers/firewire/fw-cdev.c
drivers/firewire/fw-device.c
drivers/firewire/fw-device.h
drivers/firewire/fw-ohci.c
drivers/firewire/fw-sbp2.c
drivers/firewire/fw-topology.c
drivers/firewire/fw-topology.h
drivers/firewire/fw-transaction.h
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-input.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-lgff.c
drivers/hid/usbhid/hid-pidff.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hid-tmff.c
drivers/hid/usbhid/hid-zpff.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbkbd.c
drivers/ide/arm/icside.c
drivers/ide/cris/ide-cris.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-timing.h
drivers/ide/ide.c
drivers/ide/legacy/hd.c
drivers/ide/legacy/macide.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/jmicron.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/via82cxxx.c
drivers/ide/ppc/pmac.c
drivers/ieee1394/dv1394.c
drivers/ieee1394/eth1394.c
drivers/ieee1394/highlevel.c
drivers/ieee1394/highlevel.h
drivers/ieee1394/hosts.c
drivers/ieee1394/hosts.h
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/ieee1394_core.h
drivers/ieee1394/ieee1394_transactions.c
drivers/ieee1394/ieee1394_transactions.h
drivers/ieee1394/nodemgr.c
drivers/ieee1394/nodemgr.h
drivers/ieee1394/ohci1394.c
drivers/ieee1394/ohci1394.h
drivers/ieee1394/pcilynx.c
drivers/ieee1394/raw1394-private.h
drivers/ieee1394/raw1394.c
drivers/ieee1394/raw1394.h
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.h
drivers/ieee1394/video1394.c
drivers/input/evdev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/Kconfig
drivers/input/joystick/grip_mp.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/pxa27x_keyboard.c
drivers/input/misc/Kconfig
drivers/input/misc/wistron_btns.c
drivers/input/mouse/Kconfig
drivers/input/mouse/Makefile
drivers/input/mouse/gpio_mouse.c [new file with mode: 0644]
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mousedev.c
drivers/input/serio/serio_raw.c
drivers/input/tablet/aiptek.c
drivers/input/tablet/wacom.h
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/tsdev.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/eeprom_93cx6.c [new file with mode: 0644]
drivers/net/8139cp.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/acenic.c
drivers/net/arm/Kconfig
drivers/net/b44.c
drivers/net/b44.h
drivers/net/cxgb3/adapter.h
drivers/net/cxgb3/common.h
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/regs.h
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_hw.c
drivers/net/cxgb3/version.h
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_hw.h
drivers/net/ehea/ehea_main.c
drivers/net/ehea/ehea_qmr.c
drivers/net/fec_8xx/Kconfig
drivers/net/fs_enet/Kconfig
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/gianfar_mii.c
drivers/net/lasi_82596.c
drivers/net/lib82596.c [new file with mode: 0644]
drivers/net/mlx4/qp.c
drivers/net/netxen/netxen_nic_niu.c
drivers/net/pasemi_mac.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/icplus.c [new file with mode: 0644]
drivers/net/phy/marvell.c
drivers/net/qla3xxx.c
drivers/net/r8169.c
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/sni_82596.c [new file with mode: 0644]
drivers/net/spider_net.c
drivers/net/spider_net.h
drivers/net/tulip/Kconfig
drivers/net/tulip/de2104x.c
drivers/net/tulip/de4x5.c
drivers/net/tulip/de4x5.h
drivers/net/usb/usbnet.c
drivers/net/usb/usbnet.h
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/bcm43xx/bcm43xx_phy.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_config.h
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/hostap/hostap_main.c
drivers/net/wireless/hostap/hostap_pci.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/rtl8187.h [new file with mode: 0644]
drivers/net/wireless/rtl8187_dev.c [new file with mode: 0644]
drivers/net/wireless/rtl8187_rtl8225.c [new file with mode: 0644]
drivers/net/wireless/rtl8187_rtl8225.h [new file with mode: 0644]
drivers/net/wireless/rtl818x.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/Makefile
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/wireless/zd1211rw/zd_chip.h
drivers/net/wireless/zd1211rw/zd_rf.c
drivers/net/wireless/zd1211rw/zd_rf.h
drivers/net/wireless/zd1211rw/zd_rf_al2230.c
drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
drivers/net/wireless/zd1211rw/zd_rf_uw2453.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/serial/serial_cs.c
fs/adfs/file.c
fs/affs/file.c
fs/afs/file.c
fs/bad_inode.c
fs/bfs/file.c
fs/bio.c
fs/block_dev.c
fs/cifs/cifsfs.c
fs/coda/file.c
fs/ecryptfs/file.c
fs/ext2/file.c
fs/ext3/file.c
fs/ext4/file.c
fs/fat/file.c
fs/fuse/file.c
fs/gfs2/ops_file.c
fs/hfs/inode.c
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/jffs2/file.c
fs/jfs/endian24.h
fs/jfs/file.c
fs/jfs/jfs_debug.c
fs/jfs/jfs_debug.h
fs/jfs/jfs_dinode.h
fs/jfs/jfs_dmap.c
fs/jfs/jfs_dmap.h
fs/jfs/jfs_dtree.c
fs/jfs/jfs_dtree.h
fs/jfs/jfs_extent.c
fs/jfs/jfs_filsys.h
fs/jfs/jfs_imap.c
fs/jfs/jfs_imap.h
fs/jfs/jfs_incore.h
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_logmgr.h
fs/jfs/jfs_metapage.c
fs/jfs/jfs_mount.c
fs/jfs/jfs_txnmgr.c
fs/jfs/jfs_txnmgr.h
fs/jfs/jfs_types.h
fs/jfs/jfs_umount.c
fs/jfs/jfs_xtree.c
fs/jfs/jfs_xtree.h
fs/jfs/namei.c
fs/jfs/resize.c
fs/jfs/xattr.c
fs/minix/file.c
fs/nfs/file.c
fs/nfsd/vfs.c
fs/ntfs/file.c
fs/ocfs2/file.c
fs/pipe.c
fs/proc/array.c
fs/proc/base.c
fs/qnx4/file.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/read_write.c
fs/reiserfs/file.c
fs/smbfs/file.c
fs/splice.c
fs/sysv/file.c
fs/udf/file.c
fs/ufs/file.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_lrw.c
fs/xfs/linux-2.6/xfs_lrw.h
fs/xfs/linux-2.6/xfs_vnode.h
fs/xfs/xfs_vnodeops.c
include/asm-generic/bitops/sched.h
include/asm-mips/mach-au1x00/au1xxx_ide.h
include/linux/blkdev.h
include/linux/eeprom_93cx6.h [new file with mode: 0644]
include/linux/firewire-cdev.h
include/linux/fs.h
include/linux/gpio_mouse.h [new file with mode: 0644]
include/linux/hardirq.h
include/linux/hid.h
include/linux/ide.h
include/linux/input.h
include/linux/ioprio.h
include/linux/pipe_fs_i.h
include/linux/sched.h
include/linux/splice.h [new file with mode: 0644]
include/linux/sunrpc/svc.h
include/linux/topology.h
include/linux/usb.h
include/linux/wait.h
include/pcmcia/ciscode.h
init/Kconfig
init/main.c
kernel/delayacct.c
kernel/exit.c
kernel/fork.c
kernel/posix-cpu-timers.c
kernel/relay.c
kernel/sched.c
kernel/sched_debug.c [new file with mode: 0644]
kernel/sched_fair.c [new file with mode: 0644]
kernel/sched_idletask.c [new file with mode: 0644]
kernel/sched_rt.c [new file with mode: 0644]
kernel/sched_stats.h [new file with mode: 0644]
kernel/softirq.c
kernel/sysctl.c
lib/Kconfig.debug
mm/filemap.c
mm/filemap_xip.c
mm/shmem.c
net/ieee80211/softmac/ieee80211softmac_module.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svc.c
sound/ppc/beep.c

diff --git a/Documentation/ABI/removed/raw1394_legacy_isochronous b/Documentation/ABI/removed/raw1394_legacy_isochronous
new file mode 100644 (file)
index 0000000..1b62962
--- /dev/null
@@ -0,0 +1,16 @@
+What:          legacy isochronous ABI of raw1394 (1st generation iso ABI)
+Date:          June 2007 (scheduled), removed in kernel v2.6.23
+Contact:       linux1394-devel@lists.sourceforge.net
+Description:
+       The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
+       been deprecated for quite some time.  They are very inefficient as they
+       come with high interrupt load and several layers of callbacks for each
+       packet.  Because of these deficiencies, the video1394 and dv1394 drivers
+       and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
+
+Users:
+       libraw1394 users via the long deprecated API raw1394_iso_write,
+       raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
+
+       libdc1394, which optionally uses these old libraw1394 calls
+       alternatively to the more efficient video1394 ABI
index 38f88b6ae405a16606134db8aedf7a89ccf8e643..8c5698a8c2e1e071060511353ce457da215f0e5e 100644 (file)
@@ -643,4 +643,15 @@ X!Idrivers/video/console/fonts.c
 !Edrivers/spi/spi.c
   </chapter>
 
+  <chapter id="splice">
+      <title>splice API</title>
+  <para>)
+       splice is a method for moving blocks of data around inside the
+       kernel, without continually transferring it between the kernel
+       and user space.
+  </para>
+!Iinclude/linux/splice.h
+!Ffs/splice.c
+  </chapter>
+
 </book>
index a272c3db80940bd5821e8b2f28068e3fe5d5a65b..7d279f2f5bb26b2b4b54d65f86ee165c65d97b3b 100644 (file)
@@ -82,23 +82,12 @@ including draining and flushing.
 typedef void (prepare_flush_fn)(request_queue_t *q, struct request *rq);
 
 int blk_queue_ordered(request_queue_t *q, unsigned ordered,
-                     prepare_flush_fn *prepare_flush_fn,
-                     unsigned gfp_mask);
-
-int blk_queue_ordered_locked(request_queue_t *q, unsigned ordered,
-                            prepare_flush_fn *prepare_flush_fn,
-                            unsigned gfp_mask);
-
-The only difference between the two functions is whether or not the
-caller is holding q->queue_lock on entry.  The latter expects the
-caller is holding the lock.
+                     prepare_flush_fn *prepare_flush_fn);
 
 @q                     : the queue in question
 @ordered               : the ordered mode the driver/device supports
 @prepare_flush_fn      : this function should prepare @rq such that it
                          flushes cache to physical medium when executed
-@gfp_mask              : gfp_mask used when allocating data structures
-                         for ordered processing
 
 For example, SCSI disk driver's prepare_flush_fn looks like the
 following.
@@ -106,9 +95,10 @@ following.
 static void sd_prepare_flush(request_queue_t *q, struct request *rq)
 {
        memset(rq->cmd, 0, sizeof(rq->cmd));
-       rq->flags |= REQ_BLOCK_PC;
+       rq->cmd_type = REQ_TYPE_BLOCK_PC;
        rq->timeout = SD_TIMEOUT;
        rq->cmd[0] = SYNCHRONIZE_CACHE;
+       rq->cmd_len = 10;
 }
 
 The following seven ordered modes are supported.  The following table
index 7d3f205b0ba50fddc8da631ba9fad29063239256..51b369e7fc702939a8cb882bd7884355bb3518c1 100644 (file)
@@ -49,16 +49,6 @@ Who: Adrian Bunk <bunk@stusta.de>
 
 ---------------------------
 
-What:  raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
-When:  June 2007
-Why:   Deprecated in favour of the more efficient and robust rawiso interface.
-       Affected are applications which use the deprecated part of libraw1394
-       (raw1394_iso_write, raw1394_start_iso_write, raw1394_start_iso_rcv,
-       raw1394_stop_iso_rcv) or bypass libraw1394.
-Who:   Dan Dennedy <dan@dennedy.org>, Stefan Richter <stefanr@s5r6.in-berlin.de>
-
----------------------------
-
 What:  old NCR53C9x driver
 When:  October 2007
 Why:   Replaced by the much better esp_scsi driver.  Actual low-level
index af50f9bbe68edda370017ef127d842d3d1ec97b4..4d880b3d1f35548083613a18d695d68029382c81 100644 (file)
@@ -1014,49 +1014,6 @@ and is between 256 and 4096 characters. It is defined in the file
 
        mga=            [HW,DRM]
 
-       migration_cost=
-                       [KNL,SMP] debug: override scheduler migration costs
-                       Format: <level-1-usecs>,<level-2-usecs>,...
-                       This debugging option can be used to override the
-                       default scheduler migration cost matrix. The numbers
-                       are indexed by 'CPU domain distance'.
-                       E.g. migration_cost=1000,2000,3000 on an SMT NUMA
-                       box will set up an intra-core migration cost of
-                       1 msec, an inter-core migration cost of 2 msecs,
-                       and an inter-node migration cost of 3 msecs.
-
-                       WARNING: using the wrong values here can break
-                       scheduler performance, so it's only for scheduler
-                       development purposes, not production environments.
-
-       migration_debug=
-                       [KNL,SMP] migration cost auto-detect verbosity
-                       Format=<0|1|2>
-                       If a system's migration matrix reported at bootup
-                       seems erroneous then this option can be used to
-                       increase verbosity of the detection process.
-                       We default to 0 (no extra messages), 1 will print
-                       some more information, and 2 will be really
-                       verbose (probably only useful if you also have a
-                       serial console attached to the system).
-
-       migration_factor=
-                       [KNL,SMP] multiply/divide migration costs by a factor
-                       Format=<percent>
-                       This debug option can be used to proportionally
-                       increase or decrease the auto-detected migration
-                       costs for all entries of the migration matrix.
-                       E.g. migration_factor=150 will increase migration
-                       costs by 50%. (and thus the scheduler will be less
-                       eager migrating cache-hot tasks)
-                       migration_factor=80 will decrease migration costs
-                       by 20%. (thus the scheduler will be more eager to
-                       migrate tasks)
-
-                       WARNING: using the wrong values here can break
-                       scheduler performance, so it's only for scheduler
-                       development purposes, not production environments.
-
        mousedev.tap_time=
                        [MOUSE] Maximum time between finger touching and
                        leaving touchpad surface for touch to be considered
diff --git a/Documentation/networking/spider_net.txt b/Documentation/networking/spider_net.txt
new file mode 100644 (file)
index 0000000..4b4adb8
--- /dev/null
@@ -0,0 +1,204 @@
+
+            The Spidernet Device Driver
+            ===========================
+
+Written by Linas Vepstas <linas@austin.ibm.com>
+
+Version of 7 June 2007
+
+Abstract
+========
+This document sketches the structure of portions of the spidernet
+device driver in the Linux kernel tree. The spidernet is a gigabit
+ethernet device built into the Toshiba southbridge commonly used
+in the SONY Playstation 3 and the IBM QS20 Cell blade.
+
+The Structure of the RX Ring.
+=============================
+The receive (RX) ring is a circular linked list of RX descriptors,
+together with three pointers into the ring that are used to manage its
+contents.
+
+The elements of the ring are called "descriptors" or "descrs"; they
+describe the received data. This includes a pointer to a buffer
+containing the received data, the buffer size, and various status bits.
+
+There are three primary states that a descriptor can be in: "empty",
+"full" and "not-in-use".  An "empty" or "ready" descriptor is ready
+to receive data from the hardware. A "full" descriptor has data in it,
+and is waiting to be emptied and processed by the OS. A "not-in-use"
+descriptor is neither empty or full; it is simply not ready. It may
+not even have a data buffer in it, or is otherwise unusable.
+
+During normal operation, on device startup, the OS (specifically, the
+spidernet device driver) allocates a set of RX descriptors and RX
+buffers. These are all marked "empty", ready to receive data. This
+ring is handed off to the hardware, which sequentially fills in the
+buffers, and marks them "full". The OS follows up, taking the full
+buffers, processing them, and re-marking them empty.
+
+This filling and emptying is managed by three pointers, the "head"
+and "tail" pointers, managed by the OS, and a hardware current
+descriptor pointer (GDACTDPA). The GDACTDPA points at the descr
+currently being filled. When this descr is filled, the hardware
+marks it full, and advances the GDACTDPA by one.  Thus, when there is
+flowing RX traffic, every descr behind it should be marked "full",
+and everything in front of it should be "empty".  If the hardware
+discovers that the current descr is not empty, it will signal an
+interrupt, and halt processing.
+
+The tail pointer tails or trails the hardware pointer. When the
+hardware is ahead, the tail pointer will be pointing at a "full"
+descr. The OS will process this descr, and then mark it "not-in-use",
+and advance the tail pointer.  Thus, when there is flowing RX traffic,
+all of the descrs in front of the tail pointer should be "full", and
+all of those behind it should be "not-in-use". When RX traffic is not
+flowing, then the tail pointer can catch up to the hardware pointer.
+The OS will then note that the current tail is "empty", and halt
+processing.
+
+The head pointer (somewhat mis-named) follows after the tail pointer.
+When traffic is flowing, then the head pointer will be pointing at
+a "not-in-use" descr. The OS will perform various housekeeping duties
+on this descr. This includes allocating a new data buffer and
+dma-mapping it so as to make it visible to the hardware. The OS will
+then mark the descr as "empty", ready to receive data. Thus, when there
+is flowing RX traffic, everything in front of the head pointer should
+be "not-in-use", and everything behind it should be "empty". If no
+RX traffic is flowing, then the head pointer can catch up to the tail
+pointer, at which point the OS will notice that the head descr is
+"empty", and it will halt processing.
+
+Thus, in an idle system, the GDACTDPA, tail and head pointers will
+all be pointing at the same descr, which should be "empty". All of the
+other descrs in the ring should be "empty" as well.
+
+The show_rx_chain() routine will print out the the locations of the
+GDACTDPA, tail and head pointers. It will also summarize the contents
+of the ring, starting at the tail pointer, and listing the status
+of the descrs that follow.
+
+A typical example of the output, for a nearly idle system, might be
+
+net eth1: Total number of descrs=256
+net eth1: Chain tail located at descr=20
+net eth1: Chain head is at 20
+net eth1: HW curr desc (GDACTDPA) is at 21
+net eth1: Have 1 descrs with stat=x40800101
+net eth1: HW next desc (GDACNEXTDA) is at 22
+net eth1: Last 255 descrs with stat=xa0800000
+
+In the above, the hardware has filled in one descr, number 20. Both
+head and tail are pointing at 20, because it has not yet been emptied.
+Meanwhile, hw is pointing at 21, which is free.
+
+The "Have nnn decrs" refers to the descr starting at the tail: in this
+case, nnn=1 descr, starting at descr 20. The "Last nnn descrs" refers
+to all of the rest of the descrs, from the last status change. The "nnn"
+is a count of how many descrs have exactly the same status.
+
+The status x4... corresponds to "full" and status xa... corresponds
+to "empty". The actual value printed is RXCOMST_A.
+
+In the device driver source code, a different set of names are
+used for these same concepts, so that
+
+"empty" == SPIDER_NET_DESCR_CARDOWNED == 0xa
+"full"  == SPIDER_NET_DESCR_FRAME_END == 0x4
+"not in use" == SPIDER_NET_DESCR_NOT_IN_USE == 0xf
+
+
+The RX RAM full bug/feature
+===========================
+
+As long as the OS can empty out the RX buffers at a rate faster than
+the hardware can fill them, there is no problem. If, for some reason,
+the OS fails to empty the RX ring fast enough, the hardware GDACTDPA
+pointer will catch up to the head, notice the not-empty condition,
+ad stop. However, RX packets may still continue arriving on the wire.
+The spidernet chip can save some limited number of these in local RAM.
+When this local ram fills up, the spider chip will issue an interrupt
+indicating this (GHIINT0STS will show ERRINT, and the GRMFLLINT bit
+will be set in GHIINT1STS).  When the RX ram full condition occurs,
+a certain bug/feature is triggered that has to be specially handled.
+This section describes the special handling for this condition.
+
+When the OS finally has a chance to run, it will empty out the RX ring.
+In particular, it will clear the descriptor on which the hardware had
+stopped. However, once the hardware has decided that a certain
+descriptor is invalid, it will not restart at that descriptor; instead
+it will restart at the next descr. This potentially will lead to a
+deadlock condition, as the tail pointer will be pointing at this descr,
+which, from the OS point of view, is empty; the OS will be waiting for
+this descr to be filled. However, the hardware has skipped this descr,
+and is filling the next descrs. Since the OS doesn't see this, there
+is a potential deadlock, with the OS waiting for one descr to fill,
+while the hardware is waiting for a different set of descrs to become
+empty.
+
+A call to show_rx_chain() at this point indicates the nature of the
+problem. A typical print when the network is hung shows the following:
+
+net eth1: Spider RX RAM full, incoming packets might be discarded!
+net eth1: Total number of descrs=256
+net eth1: Chain tail located at descr=255
+net eth1: Chain head is at 255
+net eth1: HW curr desc (GDACTDPA) is at 0
+net eth1: Have 1 descrs with stat=xa0800000
+net eth1: HW next desc (GDACNEXTDA) is at 1
+net eth1: Have 127 descrs with stat=x40800101
+net eth1: Have 1 descrs with stat=x40800001
+net eth1: Have 126 descrs with stat=x40800101
+net eth1: Last 1 descrs with stat=xa0800000
+
+Both the tail and head pointers are pointing at descr 255, which is
+marked xa... which is "empty". Thus, from the OS point of view, there
+is nothing to be done. In particular, there is the implicit assumption
+that everything in front of the "empty" descr must surely also be empty,
+as explained in the last section. The OS is waiting for descr 255 to
+become non-empty, which, in this case, will never happen.
+
+The HW pointer is at descr 0. This descr is marked 0x4.. or "full".
+Since its already full, the hardware can do nothing more, and thus has
+halted processing. Notice that descrs 0 through 254 are all marked
+"full", while descr 254 and 255 are empty. (The "Last 1 descrs" is
+descr 254, since tail was at 255.) Thus, the system is deadlocked,
+and there can be no forward progress; the OS thinks there's nothing
+to do, and the hardware has nowhere to put incoming data.
+
+This bug/feature is worked around with the spider_net_resync_head_ptr()
+routine. When the driver receives RX interrupts, but an examination
+of the RX chain seems to show it is empty, then it is probable that
+the hardware has skipped a descr or two (sometimes dozens under heavy
+network conditions). The spider_net_resync_head_ptr() subroutine will
+search the ring for the next full descr, and the driver will resume
+operations there.  Since this will leave "holes" in the ring, there
+is also a spider_net_resync_tail_ptr() that will skip over such holes.
+
+As of this writing, the spider_net_resync() strategy seems to work very
+well, even under heavy network loads.
+
+
+The TX ring
+===========
+The TX ring uses a low-watermark interrupt scheme to make sure that
+the TX queue is appropriately serviced for large packet sizes.
+
+For packet sizes greater than about 1KBytes, the kernel can fill
+the TX ring quicker than the device can drain it. Once the ring
+is full, the netdev is stopped. When there is room in the ring,
+the netdev needs to be reawakened, so that more TX packets are placed
+in the ring. The hardware can empty the ring about four times per jiffy,
+so its not appropriate to wait for the poll routine to refill, since
+the poll routine runs only once per jiffy.  The low-watermark mechanism
+marks a descr about 1/4th of the way from the bottom of the queue, so
+that an interrupt is generated when the descr is processed. This
+interrupt wakes up the netdev, which can then refill the queue.
+For large packets, this mechanism generates a relatively small number
+of interrupts, about 1K/sec. For smaller packets, this will drop to zero
+interrupts, as the hardware can empty the queue faster than the kernel
+can fill it.
+
+
+ ======= END OF DOCUMENT ========
+
diff --git a/Documentation/sched-design-CFS.txt b/Documentation/sched-design-CFS.txt
new file mode 100644 (file)
index 0000000..16feebb
--- /dev/null
@@ -0,0 +1,119 @@
+
+This is the CFS scheduler.
+
+80% of CFS's design can be summed up in a single sentence: CFS basically
+models an "ideal, precise multi-tasking CPU" on real hardware.
+
+"Ideal multi-tasking CPU" is a (non-existent  :-))  CPU that has 100%
+physical power and which can run each task at precise equal speed, in
+parallel, each at 1/nr_running speed. For example: if there are 2 tasks
+running then it runs each at 50% physical power - totally in parallel.
+
+On real hardware, we can run only a single task at once, so while that
+one task runs, the other tasks that are waiting for the CPU are at a
+disadvantage - the current task gets an unfair amount of CPU time. In
+CFS this fairness imbalance is expressed and tracked via the per-task
+p->wait_runtime (nanosec-unit) value. "wait_runtime" is the amount of
+time the task should now run on the CPU for it to become completely fair
+and balanced.
+
+( small detail: on 'ideal' hardware, the p->wait_runtime value would
+  always be zero - no task would ever get 'out of balance' from the
+  'ideal' share of CPU time. )
+
+CFS's task picking logic is based on this p->wait_runtime value and it
+is thus very simple: it always tries to run the task with the largest
+p->wait_runtime value. In other words, CFS tries to run the task with
+the 'gravest need' for more CPU time. So CFS always tries to split up
+CPU time between runnable tasks as close to 'ideal multitasking
+hardware' as possible.
+
+Most of the rest of CFS's design just falls out of this really simple
+concept, with a few add-on embellishments like nice levels,
+multiprocessing and various algorithm variants to recognize sleepers.
+
+In practice it works like this: the system runs a task a bit, and when
+the task schedules (or a scheduler tick happens) the task's CPU usage is
+'accounted for': the (small) time it just spent using the physical CPU
+is deducted from p->wait_runtime. [minus the 'fair share' it would have
+gotten anyway]. Once p->wait_runtime gets low enough so that another
+task becomes the 'leftmost task' of the time-ordered rbtree it maintains
+(plus a small amount of 'granularity' distance relative to the leftmost
+task so that we do not over-schedule tasks and trash the cache) then the
+new leftmost task is picked and the current task is preempted.
+
+The rq->fair_clock value tracks the 'CPU time a runnable task would have
+fairly gotten, had it been runnable during that time'. So by using
+rq->fair_clock values we can accurately timestamp and measure the
+'expected CPU time' a task should have gotten. All runnable tasks are
+sorted in the rbtree by the "rq->fair_clock - p->wait_runtime" key, and
+CFS picks the 'leftmost' task and sticks to it. As the system progresses
+forwards, newly woken tasks are put into the tree more and more to the
+right - slowly but surely giving a chance for every task to become the
+'leftmost task' and thus get on the CPU within a deterministic amount of
+time.
+
+Some implementation details:
+
+ - the introduction of Scheduling Classes: an extensible hierarchy of
+   scheduler modules. These modules encapsulate scheduling policy
+   details and are handled by the scheduler core without the core
+   code assuming about them too much.
+
+ - sched_fair.c implements the 'CFS desktop scheduler': it is a
+   replacement for the vanilla scheduler's SCHED_OTHER interactivity
+   code.
+
+   I'd like to give credit to Con Kolivas for the general approach here:
+   he has proven via RSDL/SD that 'fair scheduling' is possible and that
+   it results in better desktop scheduling. Kudos Con!
+
+   The CFS patch uses a completely different approach and implementation
+   from RSDL/SD. My goal was to make CFS's interactivity quality exceed
+   that of RSDL/SD, which is a high standard to meet :-) Testing
+   feedback is welcome to decide this one way or another. [ and, in any
+   case, all of SD's logic could be added via a kernel/sched_sd.c module
+   as well, if Con is interested in such an approach. ]
+
+   CFS's design is quite radical: it does not use runqueues, it uses a
+   time-ordered rbtree to build a 'timeline' of future task execution,
+   and thus has no 'array switch' artifacts (by which both the vanilla
+   scheduler and RSDL/SD are affected).
+
+   CFS uses nanosecond granularity accounting and does not rely on any
+   jiffies or other HZ detail. Thus the CFS scheduler has no notion of
+   'timeslices' and has no heuristics whatsoever. There is only one
+   central tunable:
+
+         /proc/sys/kernel/sched_granularity_ns
+
+   which can be used to tune the scheduler from 'desktop' (low
+   latencies) to 'server' (good batching) workloads. It defaults to a
+   setting suitable for desktop workloads. SCHED_BATCH is handled by the
+   CFS scheduler module too.
+
+   Due to its design, the CFS scheduler is not prone to any of the
+   'attacks' that exist today against the heuristics of the stock
+   scheduler: fiftyp.c, thud.c, chew.c, ring-test.c, massive_intr.c all
+   work fine and do not impact interactivity and produce the expected
+   behavior.
+
+   the CFS scheduler has a much stronger handling of nice levels and
+   SCHED_BATCH: both types of workloads should be isolated much more
+   agressively than under the vanilla scheduler.
+
+   ( another detail: due to nanosec accounting and timeline sorting,
+     sched_yield() support is very simple under CFS, and in fact under
+     CFS sched_yield() behaves much better than under any other
+     scheduler i have tested so far. )
+
+ - sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler
+   way than the vanilla scheduler does. It uses 100 runqueues (for all
+   100 RT priority levels, instead of 140 in the vanilla scheduler)
+   and it needs no expired array.
+
+ - reworked/sanitized SMP load-balancing: the runqueue-walking
+   assumptions are gone from the load-balancing code now, and
+   iterators of the scheduling modules are used. The balancing code got
+   quite a bit simpler as a result.
+
index df40a4ec87fbff098d79b52caa98f531b5b5a8f3..bc272bf0ff9732c139b0af7aa93781e88d999128 100644 (file)
@@ -1856,7 +1856,7 @@ W:        http://www.openib.org/
 T:     git kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
 S:     Supported
 
-INPUT (KEYBOARD, MOUSE, JOYSTICK) DRIVERS
+INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
 P:     Dmitry Torokhov
 M:     dmitry.torokhov@gmail.com
 M:     dtor@mail.ru
@@ -3049,6 +3049,16 @@ S:       Maintained
 RISCOM8 DRIVER
 S:     Orphan
 
+RTL818X WIRELESS DRIVER
+P:     Michael Wu
+M:     flamingice@sourmilk.net
+P:     Andrea Merello
+M:     andreamrl@tiscali.it
+L:     linux-wireless@vger.kernel.org
+W:     http://linuxwireless.org/
+T:     git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+S:     Maintained
+
 S3 SAVAGE FRAMEBUFFER DRIVER
 P:     Antonino Daplas
 M:     adaplas@gmail.com
index 88baed1e7e83a1469ecc33f1ed5e6e1c17a00af4..0b2954534b8e71f3216f23a7ae8c933e0bc48d7c 100644 (file)
@@ -941,17 +941,6 @@ exit:
 }
 #endif
 
-static void smp_tune_scheduling(void)
-{
-       if (cpu_khz) {
-               /* cache size in kB */
-               long cachesize = boot_cpu_data.x86_cache_size;
-
-               if (cachesize > 0)
-                       max_cache_size = cachesize * 1024;
-       }
-}
-
 /*
  * Cycle through the processors sending APIC IPIs to boot each.
  */
@@ -980,7 +969,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
        x86_cpu_to_apicid[0] = boot_cpu_physical_apicid;
 
        current_thread_info()->cpu = 0;
-       smp_tune_scheduling();
 
        set_cpu_sibling_map(0);
 
index f64b81f3033bcba88ff47d268e8819b93d938e47..ea63a30ca3e88daa1bca2975f3c9f98812d7dffc 100644 (file)
@@ -4,6 +4,7 @@
  * See comments there for proper credits.
  */
 
+#include <linux/sched.h>
 #include <linux/clocksource.h>
 #include <linux/workqueue.h>
 #include <linux/cpufreq.h>
@@ -106,8 +107,13 @@ unsigned long long sched_clock(void)
 
        /*
         * Fall back to jiffies if there's no TSC available:
+        * ( But note that we still use it if the TSC is marked
+        *   unstable. We do this because unlike Time Of Day,
+        *   the scheduler clock tolerates small errors and it's
+        *   very important for it to be as fast as the platform
+        *   can achive it. )
         */
-       if (unlikely(!tsc_enabled))
+       if (unlikely(!tsc_enabled && !tsc_unstable))
                /* No locking but a rare wrong value is not a big deal: */
                return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
 
@@ -277,6 +283,7 @@ static struct clocksource clocksource_tsc = {
 
 void mark_tsc_unstable(char *reason)
 {
+       sched_clock_unstable_event();
        if (!tsc_unstable) {
                tsc_unstable = 1;
                tsc_enabled = 0;
index eaa6a24bc0b6e61b284d38aef67fa2db6e31f1c2..188fb73c68456e3e2f1bd70e8f947b1b0754f869 100644 (file)
@@ -805,7 +805,6 @@ static void __cpuinit
 get_max_cacheline_size (void)
 {
        unsigned long line_size, max = 1;
-       unsigned int cache_size = 0;
        u64 l, levels, unique_caches;
         pal_cache_config_info_t cci;
         s64 status;
@@ -835,8 +834,6 @@ get_max_cacheline_size (void)
                line_size = 1 << cci.pcci_line_size;
                if (line_size > max)
                        max = line_size;
-               if (cache_size < cci.pcci_cache_size)
-                       cache_size = cci.pcci_cache_size;
                if (!cci.pcci_unified) {
                        status = ia64_pal_cache_config_info(l,
                                                    /* cache_type (instruction)= */ 1,
@@ -853,9 +850,6 @@ get_max_cacheline_size (void)
                        ia64_i_cache_stride_shift = cci.pcci_stride;
        }
   out:
-#ifdef CONFIG_SMP
-       max_cache_size = max(max_cache_size, cache_size);
-#endif
        if (max > ia64_max_cacheline_size)
                ia64_max_cacheline_size = max;
 }
index 67edfa7ed93a643d4a59af04d9a6c98a8d1ca12f..a1b017f2dbb3a834706d44d2ff42e34bf65b8a9e 100644 (file)
@@ -51,16 +51,6 @@ int __cpu_logical_map[NR_CPUS];              /* Map logical to physical */
 EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(cpu_online_map);
 
-/* This happens early in bootup, can't really do it better */
-static void smp_tune_scheduling (void)
-{
-       struct cache_desc *cd = &current_cpu_data.scache;
-       unsigned long cachesize = cd->linesz * cd->sets * cd->ways;
-
-       if (cachesize > max_cache_size)
-               max_cache_size = cachesize;
-}
-
 extern void __init calibrate_delay(void);
 extern ATTRIB_NORET void cpu_idle(void);
 
@@ -228,7 +218,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        init_new_context(current, &init_mm);
        current_thread_info()->cpu = 0;
-       smp_tune_scheduling();
        plat_prepare_cpus(max_cpus);
 #ifndef CONFIG_HOTPLUG_CPU
        cpu_present_map = cpu_possible_map;
index 4d9ad59031bb244f3df459338f9e5b9d6c9a6235..4fea3ac7bff08d1b13cd4e54f2d2be6b08198d1a 100644 (file)
@@ -68,16 +68,6 @@ void __cpuinit smp_store_cpu_info(int id)
        cpu_data(id).prom_node = cpu_node;
        cpu_data(id).mid = cpu_get_hwmid(cpu_node);
 
-       /* this is required to tune the scheduler correctly */
-       /* is it possible to have CPUs with different cache sizes? */
-       if (id == boot_cpu_id) {
-               int cache_line,cache_nlines;
-               cache_line = 0x20;
-               cache_line = prom_getintdefault(cpu_node, "ecache-line-size", cache_line);
-               cache_nlines = 0x8000;
-               cache_nlines = prom_getintdefault(cpu_node, "ecache-nlines", cache_nlines);
-               max_cache_size = cache_line * cache_nlines;
-       }
        if (cpu_data(id).mid < 0)
                panic("No MID found for CPU%d at node 0x%08d", id, cpu_node);
 }
index 4dcd7d0b60f2d8abb8e8ad7630df207cfc39ad21..40e40f968d61abd9ef8192aeb1a6f2a9b318c7e7 100644 (file)
@@ -1163,32 +1163,6 @@ int setup_profiling_timer(unsigned int multiplier)
        return -EINVAL;
 }
 
-static void __init smp_tune_scheduling(void)
-{
-       unsigned int smallest = ~0U;
-       int i;
-
-       for (i = 0; i < NR_CPUS; i++) {
-               unsigned int val = cpu_data(i).ecache_size;
-
-               if (val && val < smallest)
-                       smallest = val;
-       }
-
-       /* Any value less than 256K is nonsense.  */
-       if (smallest < (256U * 1024U))
-               smallest = 256 * 1024;
-
-       max_cache_size = smallest;
-
-       if (smallest < 1U * 1024U * 1024U)
-               printk(KERN_INFO "Using max_cache_size of %uKB\n",
-                      smallest / 1024U);
-       else
-               printk(KERN_INFO "Using max_cache_size of %uMB\n",
-                      smallest / 1024U / 1024U);
-}
-
 /* Constrain the number of cpus to max_cpus.  */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
@@ -1206,7 +1180,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        }
 
        cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
-       smp_tune_scheduling();
 }
 
 void __devinit smp_prepare_boot_cpu(void)
index a50f481116477e9552c82db45f728bc067dbbbbd..285935134bcd02cedf51cd1330ea1460aca4ca14 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Block layer core configuration
 #
-config BLOCK
+menuconfig BLOCK
        bool "Enable the block layer" if EMBEDDED
        default y
        help
@@ -49,6 +49,6 @@ config LSF
 
          If unsure, say Y.
 
-endif
+endif # BLOCK
 
 source block/Kconfig.iosched
index baef5fc7cff8b5ca3d184e3d48efdd4be7376203..e0aa4dad67424ae45bfa93150f14c1856f75140e 100644 (file)
@@ -92,6 +92,8 @@ struct cfq_data {
        struct cfq_queue *active_queue;
        struct cfq_io_context *active_cic;
 
+       struct cfq_queue *async_cfqq[IOPRIO_BE_NR];
+
        struct timer_list idle_class_timer;
 
        sector_t last_position;
@@ -1351,8 +1353,8 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
 }
 
 static struct cfq_queue *
-cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
-             gfp_t gfp_mask)
+cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync,
+                    struct task_struct *tsk, gfp_t gfp_mask)
 {
        struct cfq_queue *cfqq, *new_cfqq = NULL;
        struct cfq_io_context *cic;
@@ -1405,12 +1407,35 @@ retry:
        if (new_cfqq)
                kmem_cache_free(cfq_pool, new_cfqq);
 
-       atomic_inc(&cfqq->ref);
 out:
        WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
        return cfqq;
 }
 
+static struct cfq_queue *
+cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
+             gfp_t gfp_mask)
+{
+       const int ioprio = task_ioprio(tsk);
+       struct cfq_queue *cfqq = NULL;
+
+       if (!is_sync)
+               cfqq = cfqd->async_cfqq[ioprio];
+       if (!cfqq)
+               cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);
+
+       /*
+        * pin the queue now that it's allocated, scheduler exit will prune it
+        */
+       if (!is_sync && !cfqd->async_cfqq[ioprio]) {
+               atomic_inc(&cfqq->ref);
+               cfqd->async_cfqq[ioprio] = cfqq;
+       }
+
+       atomic_inc(&cfqq->ref);
+       return cfqq;
+}
+
 /*
  * We drop cfq io contexts lazily, so we may find a dead one.
  */
@@ -2019,6 +2044,7 @@ static void cfq_exit_queue(elevator_t *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
        request_queue_t *q = cfqd->queue;
+       int i;
 
        cfq_shutdown_timer_wq(cfqd);
 
@@ -2035,6 +2061,13 @@ static void cfq_exit_queue(elevator_t *e)
                __cfq_exit_single_io_context(cfqd, cic);
        }
 
+       /*
+        * Put the async queues
+        */
+       for (i = 0; i < IOPRIO_BE_NR; i++)
+               if (cfqd->async_cfqq[i])        
+                       cfq_put_queue(cfqd->async_cfqq[i]);
+
        spin_unlock_irq(q->queue_lock);
 
        cfq_shutdown_timer_wq(cfqd);
index ce866eb75f6a997692cf4874dfe1ee8ceda216e8..4769a25d7037a555c4f700d34a9b6d5411391959 100644 (file)
@@ -112,12 +112,8 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio)
 static struct elevator_type *elevator_find(const char *name)
 {
        struct elevator_type *e;
-       struct list_head *entry;
-
-       list_for_each(entry, &elv_list) {
-
-               e = list_entry(entry, struct elevator_type, list);
 
+       list_for_each_entry(e, &elv_list, list) {
                if (!strcmp(e->elevator_name, name))
                        return e;
        }
@@ -1116,14 +1112,11 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
 {
        elevator_t *e = q->elevator;
        struct elevator_type *elv = e->elevator_type;
-       struct list_head *entry;
+       struct elevator_type *__e;
        int len = 0;
 
        spin_lock(&elv_list_lock);
-       list_for_each(entry, &elv_list) {
-               struct elevator_type *__e;
-
-               __e = list_entry(entry, struct elevator_type, list);
+       list_for_each_entry(__e, &elv_list, list) {
                if (!strcmp(elv->elevator_name, __e->elevator_name))
                        len += sprintf(name+len, "[%s] ", elv->elevator_name);
                else
index c99b463548592239044f6e71aea571abd99a7307..ef42bb2b12b6dd89b0edc1734485e66147920759 100644 (file)
@@ -527,8 +527,6 @@ int blk_do_ordered(request_queue_t *q, struct request **rqp)
 static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error)
 {
        request_queue_t *q = bio->bi_private;
-       struct bio_vec *bvec;
-       int i;
 
        /*
         * This is dry run, restore bio_sector and size.  We'll finish
@@ -540,13 +538,6 @@ static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error)
        if (bio->bi_size)
                return 1;
 
-       /* Rewind bvec's */
-       bio->bi_idx = 0;
-       bio_for_each_segment(bvec, bio, i) {
-               bvec->bv_len += bvec->bv_offset;
-               bvec->bv_offset = 0;
-       }
-
        /* Reset bio */
        set_bit(BIO_UPTODATE, &bio->bi_flags);
        bio->bi_size = q->bi_size;
@@ -1304,9 +1295,9 @@ static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
        if (unlikely(!bio_flagged(nxt, BIO_SEG_VALID)))
                blk_recount_segments(q, nxt);
        if (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) ||
-           BIOVEC_VIRT_OVERSIZE(bio->bi_hw_front_size + bio->bi_hw_back_size))
+           BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size))
                return 0;
-       if (bio->bi_size + nxt->bi_size > q->max_segment_size)
+       if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size)
                return 0;
 
        return 1;
index 050323fd79e9ae78f4f528ce260e08a8ec89f38b..4e6487d461f39f6dfa3c1bcbfb4e6570ec836231 100644 (file)
@@ -24,8 +24,6 @@ source "drivers/scsi/Kconfig"
 
 source "drivers/ata/Kconfig"
 
-source "drivers/cdrom/Kconfig"
-
 source "drivers/md/Kconfig"
 
 source "drivers/message/fusion/Kconfig"
index 674bf81c6e660040ab8d0136ecebd4e9f84aad66..423ed08fb6f74b8c8ac7c9c9c3d9fbcf22d380c0 100644 (file)
@@ -1246,7 +1246,7 @@ repeat:
        del_timer(&motor_off_timer);
 
        ReqCnt = 0;
-       ReqCmd = CURRENT->cmd;
+       ReqCmd = rq_data_dir(CURRENT);
        ReqBlock = CURRENT->sector;
        ReqBuffer = CURRENT->buffer;
        setup_req_params(drive);
index 689a4c3542babc00e385699fe1caf4b02c0f9103..d85520f78e68bcd7ce4c9df214493643cf171bf5 100644 (file)
@@ -439,7 +439,7 @@ static void mfm_rw_intr(void)
           a choice of command end or some data which is ready to be collected */
        /* I think we have to transfer data while the interrupt line is on and its
           not any other type of interrupt */
-       if (CURRENT->cmd == WRITE) {
+       if (rq_data_dir(CURRENT) == WRITE) {
                extern void hdc63463_writedma(void);
                if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
                        printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
@@ -799,7 +799,7 @@ static void issue_request(unsigned int block, unsigned int nsect,
        raw_cmd.head = start_head;
        raw_cmd.cylinder = track / p->heads;
        raw_cmd.cmdtype = CURRENT->cmd;
-       raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
+       raw_cmd.cmdcode = rq_data_dir(CURRENT) == WRITE ? CMD_WD : CMD_RD;
        raw_cmd.cmddata[0] = dev + 1;   /* DAG: +1 to get US */
        raw_cmd.cmddata[1] = raw_cmd.head;
        raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
@@ -830,7 +830,7 @@ static void issue_request(unsigned int block, unsigned int nsect,
        hdc63463_dataleft = nsect * 256;        /* Better way? */
 
        DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
-            raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
+            raw_cmd.dev + 'a', rq_data_dir(CURRENT) == READ ? "read" : "writ",
                       raw_cmd.cylinder,
                       raw_cmd.head,
            raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
@@ -917,13 +917,6 @@ static void mfm_request(void)
 
                DBG("mfm_request: block after offset=%d\n", block);
 
-               if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
-                       printk("unknown mfm-command %d\n", CURRENT->cmd);
-                       end_request(CURRENT, 0);
-                       Busy = 0;
-                       printk("mfm: continue 4\n");
-                       continue;
-               }
                issue_request(block, nsect, CURRENT);
 
                break;
index b4c8319138b29fbd762941ae74b4cbcc7d441cd3..6e23af1ecbdb3fca4600bf3fafecce4126ba7f3a 100644 (file)
@@ -2,9 +2,12 @@
 # Block device driver configuration
 #
 
-if BLOCK
+menuconfig BLK_DEV
+       bool "Block devices"
+       depends on BLOCK
+       default y
 
-menu "Block devices"
+if BLK_DEV
 
 config BLK_DEV_FD
        tristate "Normal floppy disk support"
@@ -56,40 +59,9 @@ config AMIGA_Z2RAM
          To compile this driver as a module, choose M here: the
          module will be called z2ram.
 
-config ATARI_ACSI
-       tristate "Atari ACSI support"
-       depends on ATARI && BROKEN
-       ---help---
-         This enables support for the Atari ACSI interface. The driver
-         supports hard disks and CD-ROMs, which have 512-byte sectors, or can
-         be switched to that mode. Due to the ACSI command format, only disks
-         up to 1 GB are supported. Special support for certain ACSI to SCSI
-         adapters, which could relax that, isn't included yet. The ACSI
-         driver is also the basis for certain other drivers for devices
-         attached to the ACSI bus: Atari SLM laser printer, BioNet-100
-         Ethernet, and PAMsNet Ethernet. If you want to use one of these
-         devices, you need ACSI support, too.
-
-         To compile this driver as a module, choose M here: the
-         module will be called acsi.
-
-comment "Some devices (e.g. CD jukebox) support multiple LUNs"
-       depends on ATARI && ATARI_ACSI
-
-config ACSI_MULTI_LUN
-       bool "Probe all LUNs on each ACSI device"
-       depends on ATARI_ACSI
-       help
-         If you have a ACSI device that supports more than one LUN (Logical
-         Unit Number), e.g. a CD jukebox, you should say Y here so that all
-         will be found by the ACSI driver. An ACSI device with multiple LUNs
-         acts logically like multiple ACSI devices. The vast majority of ACSI
-         devices have only one LUN, and so most people can say N here and
-         should in fact do so, because it is safer.
-
 config ATARI_SLM
        tristate "Atari SLM laser printer support"
-       depends on ATARI && ATARI_ACSI!=n
+       depends on ATARI
        help
          If you have an Atari SLM laser printer, say Y to include support for
          it in the kernel. Otherwise, say N. This driver is also available as
@@ -453,6 +425,4 @@ config ATA_OVER_ETH
 
 source "drivers/s390/block/Kconfig"
 
-endmenu
-
-endif
+endif # BLK_DEV
index dd88e33c1eb108ccd6d56a24dcb75eea8bca41f7..e5f98acc5d523ec622724bae6da15ac3be37912f 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY)        += swim3.o
 obj-$(CONFIG_BLK_DEV_FD)       += floppy.o
 obj-$(CONFIG_AMIGA_FLOPPY)     += amiflop.o
 obj-$(CONFIG_ATARI_FLOPPY)     += ataflop.o
-obj-$(CONFIG_ATARI_ACSI)       += acsi.o
 obj-$(CONFIG_ATARI_SLM)                += acsi_slm.o
 obj-$(CONFIG_AMIGA_Z2RAM)      += z2ram.o
 obj-$(CONFIG_BLK_DEV_RAM)      += rd.o
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
deleted file mode 100644 (file)
index e3d9152..0000000
+++ /dev/null
@@ -1,1825 +0,0 @@
-/*
- * acsi.c -- Device driver for Atari ACSI hard disks
- *
- * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
- *
- * Some parts are based on hd.c by Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive for
- * more details.
- *
- */
-
-/*
- * Still to in this file:
- *  - If a command ends with an error status (!= 0), the following
- *    REQUEST SENSE commands (4 to fill the ST-DMA FIFO) are done by
- *    polling the _IRQ signal (not interrupt-driven). This should be
- *    avoided in future because it takes up a non-neglectible time in
- *    the interrupt service routine while interrupts are disabled.
- *    Maybe a timer interrupt will get lost :-(
- */
-
-/*
- * General notes:
- *
- *  - All ACSI devices (disks, CD-ROMs, ...) use major number 28.
- *    Minors are organized like it is with SCSI: The upper 4 bits
- *    identify the device, the lower 4 bits the partition.
- *    The device numbers (the upper 4 bits) are given in the same
- *    order as the devices are found on the bus.
- *  - Up to 8 LUNs are supported for each target (if CONFIG_ACSI_MULTI_LUN
- *    is defined), but only a total of 16 devices (due to minor
- *    numbers...). Note that Atari allows only a maximum of 4 targets
- *    (i.e. controllers, not devices) on the ACSI bus!
- *  - A optimizing scheme similar to SCSI scatter-gather is implemented.
- *  - Removable media are supported. After a medium change to device
- *    is reinitialized (partition check etc.). Also, if the device
- *    knows the PREVENT/ALLOW MEDIUM REMOVAL command, the door should
- *    be locked and unlocked when mounting the first or unmounting the
- *    last filesystem on the device. The code is untested, because I
- *    don't have a removable hard disk.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/genhd.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <scsi/scsi.h> /* for SCSI_IOCTL_GET_IDLUN */
-#include <scsi/scsi_ioctl.h>
-#include <linux/hdreg.h> /* for HDIO_GETGEO */
-#include <linux/blkpg.h>
-#include <linux/buffer_head.h>
-#include <linux/blkdev.h>
-
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_acsi.h>
-#include <asm/atari_stdma.h>
-#include <asm/atari_stram.h>
-
-static void (*do_acsi)(void) = NULL;
-static struct request_queue *acsi_queue;
-#define QUEUE (acsi_queue)
-#define CURRENT elv_next_request(acsi_queue)
-
-#define DEBUG
-#undef DEBUG_DETECT
-#undef NO_WRITE
-
-#define MAX_ERRORS                     8       /* Max read/write errors/sector */
-#define MAX_LUN                                8       /* Max LUNs per target */
-#define MAX_DEV                                16
-
-#define ACSI_BUFFER_SIZE                       (16*1024) /* "normal" ACSI buffer size */
-#define ACSI_BUFFER_MINSIZE                    (2048)    /* min. buf size if ext. DMA */
-#define ACSI_BUFFER_SIZE_ORDER         2                 /* order size for above */
-#define ACSI_BUFFER_MINSIZE_ORDER      0                 /* order size for above */
-#define ACSI_BUFFER_SECTORS    (ACSI_BUFFER_SIZE/512)
-
-#define ACSI_BUFFER_ORDER \
-       (ATARIHW_PRESENT(EXTD_DMA) ? \
-        ACSI_BUFFER_MINSIZE_ORDER : \
-        ACSI_BUFFER_SIZE_ORDER)
-
-#define ACSI_TIMEOUT           (4*HZ)
-
-/* minimum delay between two commands */
-
-#define COMMAND_DELAY 500
-
-typedef enum {
-       NONE, HARDDISK, CDROM
-} ACSI_TYPE;
-
-struct acsi_info_struct {
-       ACSI_TYPE               type;                   /* type of device */
-       unsigned                target;                 /* target number */
-       unsigned                lun;                    /* LUN in target controller */
-       unsigned                removable : 1;  /* Flag for removable media */
-       unsigned                read_only : 1;  /* Flag for read only devices */
-       unsigned                old_atari_disk : 1; /* Is an old Atari disk       */
-       unsigned                changed : 1;    /* Medium has been changed */
-       unsigned long   size;                   /* #blocks */
-       int access_count;
-} acsi_info[MAX_DEV];
-
-/*
- *     SENSE KEYS
- */
-
-#define NO_SENSE               0x00
-#define RECOVERED_ERROR        0x01
-#define NOT_READY              0x02
-#define MEDIUM_ERROR           0x03
-#define HARDWARE_ERROR         0x04
-#define ILLEGAL_REQUEST        0x05
-#define UNIT_ATTENTION         0x06
-#define DATA_PROTECT           0x07
-#define BLANK_CHECK            0x08
-#define COPY_ABORTED           0x0a
-#define ABORTED_COMMAND        0x0b
-#define VOLUME_OVERFLOW        0x0d
-#define MISCOMPARE             0x0e
-
-
-/*
- *     DEVICE TYPES
- */
-
-#define TYPE_DISK      0x00
-#define TYPE_TAPE      0x01
-#define TYPE_WORM      0x04
-#define TYPE_ROM       0x05
-#define TYPE_MOD       0x07
-#define TYPE_NO_LUN    0x7f
-
-/* The data returned by MODE SENSE differ between the old Atari
- * hard disks and SCSI disks connected to ACSI. In the following, both
- * formats are defined and some macros to operate on them potably.
- */
-
-typedef struct {
-       unsigned long   dummy[2];
-       unsigned long   sector_size;
-       unsigned char   format_code;
-#define ATARI_SENSE_FORMAT_FIX 1       
-#define ATARI_SENSE_FORMAT_CHNG        2
-       unsigned char   cylinders_h;
-       unsigned char   cylinders_l;
-       unsigned char   heads;
-       unsigned char   reduced_h;
-       unsigned char   reduced_l;
-       unsigned char   precomp_h;
-       unsigned char   precomp_l;
-       unsigned char   landing_zone;
-       unsigned char   steprate;
-       unsigned char   type;
-#define ATARI_SENSE_TYPE_FIXCHNG_MASK          4
-#define ATARI_SENSE_TYPE_SOFTHARD_MASK         8
-#define ATARI_SENSE_TYPE_FIX                           4
-#define ATARI_SENSE_TYPE_CHNG                          0
-#define ATARI_SENSE_TYPE_SOFT                          0
-#define ATARI_SENSE_TYPE_HARD                          8
-       unsigned char   sectors;
-} ATARI_SENSE_DATA;
-
-#define ATARI_CAPACITY(sd) \
-       (((int)((sd).cylinders_h<<8)|(sd).cylinders_l) * \
-        (sd).heads * (sd).sectors)
-
-
-typedef struct {
-       unsigned char   dummy1;
-       unsigned char   medium_type;
-       unsigned char   dummy2;
-       unsigned char   descriptor_size;
-       unsigned long   block_count;
-       unsigned long   sector_size;
-       /* Page 0 data */
-       unsigned char   page_code;
-       unsigned char   page_size;
-       unsigned char   page_flags;
-       unsigned char   qualifier;
-} SCSI_SENSE_DATA;
-
-#define SCSI_CAPACITY(sd)      ((sd).block_count & 0xffffff)
-
-
-typedef union {
-       ATARI_SENSE_DATA        atari;
-       SCSI_SENSE_DATA         scsi;
-} SENSE_DATA;
-
-#define SENSE_TYPE_UNKNOWN     0
-#define SENSE_TYPE_ATARI       1
-#define SENSE_TYPE_SCSI                2
-
-#define SENSE_TYPE(sd)                                                                         \
-       (((sd).atari.dummy[0] == 8 &&                                                   \
-         ((sd).atari.format_code == 1 ||                                               \
-          (sd).atari.format_code == 2)) ? SENSE_TYPE_ATARI :   \
-        ((sd).scsi.dummy1 >= 11) ? SENSE_TYPE_SCSI :                   \
-        SENSE_TYPE_UNKNOWN)
-        
-#define CAPACITY(sd)                                                   \
-       (SENSE_TYPE(sd) == SENSE_TYPE_ATARI ?           \
-        ATARI_CAPACITY((sd).atari) :                           \
-        SCSI_CAPACITY((sd).scsi))
-
-#define SECTOR_SIZE(sd)                                                        \
-       (SENSE_TYPE(sd) == SENSE_TYPE_ATARI ?           \
-        (sd).atari.sector_size :                                       \
-        (sd).scsi.sector_size & 0xffffff)
-
-/* Default size if capacity cannot be determined (1 GByte) */
-#define        DEFAULT_SIZE    0x1fffff
-
-#define CARTRCH_STAT(aip,buf)                                          \
-       (aip->old_atari_disk ?                                          \
-        (((buf)[0] & 0x7f) == 0x28) :                                  \
-        ((((buf)[0] & 0x70) == 0x70) ?                                 \
-         (((buf)[2] & 0x0f) == 0x06) :                                 \
-         (((buf)[0] & 0x0f) == 0x06)))                                 \
-
-/* These two are also exported to other drivers that work on the ACSI bus and
- * need an ST-RAM buffer. */
-char                   *acsi_buffer;
-unsigned long  phys_acsi_buffer;
-
-static int NDevices;
-
-static int                             CurrentNReq;
-static int                             CurrentNSect;
-static char                            *CurrentBuffer;
-
-static DEFINE_SPINLOCK(acsi_lock);
-
-
-#define SET_TIMER()    mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT)
-#define CLEAR_TIMER()  del_timer(&acsi_timer)
-
-static unsigned long   STramMask;
-#define STRAM_ADDR(a)  (((a) & STramMask) == 0)
-
-
-
-/* ACSI commands */
-
-static char tur_cmd[6]        = { 0x00, 0, 0, 0, 0, 0 };
-static char modesense_cmd[6]  = { 0x1a, 0, 0, 0, 24, 0 };
-static char modeselect_cmd[6] = { 0x15, 0, 0, 0, 12, 0 };
-static char inquiry_cmd[6]    = { 0x12, 0, 0, 0,255, 0 };
-static char reqsense_cmd[6]   = { 0x03, 0, 0, 0, 4, 0 };
-static char read_cmd[6]       = { 0x08, 0, 0, 0, 0, 0 };
-static char write_cmd[6]      = { 0x0a, 0, 0, 0, 0, 0 };
-static char pa_med_rem_cmd[6] = { 0x1e, 0, 0, 0, 0, 0 };
-
-#define CMDSET_TARG_LUN(cmd,targ,lun)                  \
-    do {                                               \
-               cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5;  \
-               cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5;   \
-       } while(0)
-
-#define CMDSET_BLOCK(cmd,blk)                                          \
-    do {                                                                                       \
-               unsigned long __blk = (blk);                            \
-               cmd[3] = __blk; __blk >>= 8;                            \
-               cmd[2] = __blk; __blk >>= 8;                            \
-               cmd[1] = (cmd[1] & 0xe0) | (__blk & 0x1f);      \
-       } while(0)
-
-#define CMDSET_LEN(cmd,len)                                            \
-       do {                                                                            \
-               cmd[4] = (len);                                                 \
-       } while(0)
-
-/* ACSI errors (from REQUEST SENSE); There are two tables, one for the
- * old Atari disks and one for SCSI on ACSI disks.
- */
-
-struct acsi_error {
-       unsigned char   code;
-       const char              *text;
-} atari_acsi_errors[] = {
-       { 0x00, "No error (??)" },
-       { 0x01, "No index pulses" },
-       { 0x02, "Seek not complete" },
-       { 0x03, "Write fault" },
-       { 0x04, "Drive not ready" },
-       { 0x06, "No Track 00 signal" },
-       { 0x10, "ECC error in ID field" },
-       { 0x11, "Uncorrectable data error" },
-       { 0x12, "ID field address mark not found" },
-       { 0x13, "Data field address mark not found" },
-       { 0x14, "Record not found" },
-       { 0x15, "Seek error" },
-       { 0x18, "Data check in no retry mode" },
-       { 0x19, "ECC error during verify" },
-       { 0x1a, "Access to bad block" },
-       { 0x1c, "Unformatted or bad format" },
-       { 0x20, "Invalid command" },
-       { 0x21, "Invalid block address" },
-       { 0x23, "Volume overflow" },
-       { 0x24, "Invalid argument" },
-       { 0x25, "Invalid drive number" },
-       { 0x26, "Byte zero parity check" },
-       { 0x28, "Cartride changed" },
-       { 0x2c, "Error count overflow" },
-       { 0x30, "Controller selftest failed" }
-},
-
-       scsi_acsi_errors[] = {
-       { 0x00, "No error (??)" },
-       { 0x01, "Recovered error" },
-       { 0x02, "Drive not ready" },
-       { 0x03, "Uncorrectable medium error" },
-       { 0x04, "Hardware error" },
-       { 0x05, "Illegal request" },
-       { 0x06, "Unit attention (Reset or cartridge changed)" },
-       { 0x07, "Data protection" },
-       { 0x08, "Blank check" },
-       { 0x0b, "Aborted Command" },
-       { 0x0d, "Volume overflow" }
-};
-
-
-
-/***************************** Prototypes *****************************/
-
-static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int
-                        rwflag, int enable);
-static int acsi_reqsense( char *buffer, int targ, int lun);
-static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip);
-static irqreturn_t acsi_interrupt (int irq, void *data);
-static void unexpected_acsi_interrupt( void );
-static void bad_rw_intr( void );
-static void read_intr( void );
-static void write_intr( void);
-static void acsi_times_out( unsigned long dummy );
-static void copy_to_acsibuffer( void );
-static void copy_from_acsibuffer( void );
-static void do_end_requests( void );
-static void do_acsi_request( request_queue_t * );
-static void redo_acsi_request( void );
-static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
-                       cmd, unsigned long arg );
-static int acsi_open( struct inode * inode, struct file * filp );
-static int acsi_release( struct inode * inode, struct file * file );
-static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag );
-static int acsi_change_blk_size( int target, int lun);
-static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
-static int acsi_revalidate (struct gendisk *disk);
-
-/************************* End of Prototypes **************************/
-
-
-DEFINE_TIMER(acsi_timer, acsi_times_out, 0, 0);
-
-
-#ifdef CONFIG_ATARI_SLM
-
-extern int attach_slm( int target, int lun );
-extern int slm_init( void );
-
-#endif
-
-
-\f
-/***********************************************************************
- *
- *   ACSI primitives
- *
- **********************************************************************/
-
-
-/*
- * The following two functions wait for _IRQ to become Low or High,
- * resp., with a timeout. The 'timeout' parameter is in jiffies
- * (10ms).
- * If the functions are called with timer interrupts on (int level <
- * 6), the timeout is based on the 'jiffies' variable to provide exact
- * timeouts for device probing etc.
- * If interrupts are disabled, the number of tries is based on the
- * 'loops_per_jiffy' variable. A rough estimation is sufficient here...
- */
-
-#define INT_LEVEL                                                                                                      \
-       ({      unsigned __sr;                                                                                          \
-               __asm__ __volatile__ ( "movew   %/sr,%0" : "=dm" (__sr) );      \
-               (__sr >> 8) & 7;                                                                                        \
-       })
-
-int acsi_wait_for_IRQ( unsigned timeout )
-
-{
-       if (INT_LEVEL < 6) {
-               unsigned long maxjif = jiffies + timeout;
-               while (time_before(jiffies, maxjif))
-                       if (!(mfp.par_dt_reg & 0x20)) return( 1 );
-       }
-       else {
-               long tries = loops_per_jiffy / 8 * timeout;
-               while( --tries >= 0 )
-                       if (!(mfp.par_dt_reg & 0x20)) return( 1 );
-       }               
-       return( 0 ); /* timeout! */
-}
-
-
-int acsi_wait_for_noIRQ( unsigned timeout )
-
-{
-       if (INT_LEVEL < 6) {
-               unsigned long maxjif = jiffies + timeout;
-               while (time_before(jiffies, maxjif))
-                       if (mfp.par_dt_reg & 0x20) return( 1 );
-       }
-       else {
-               long tries = loops_per_jiffy * timeout / 8;
-               while( tries-- >= 0 )
-                       if (mfp.par_dt_reg & 0x20) return( 1 );
-       }               
-       return( 0 ); /* timeout! */
-}
-
-static struct timeval start_time;
-
-void
-acsi_delay_start(void)
-{
-       do_gettimeofday(&start_time);
-}
-
-/* wait from acsi_delay_start to now usec (<1E6) usec */
-
-void
-acsi_delay_end(long usec)
-{
-       struct timeval end_time;
-       long deltau,deltas;
-       do_gettimeofday(&end_time);
-       deltau=end_time.tv_usec - start_time.tv_usec;
-       deltas=end_time.tv_sec - start_time.tv_sec;
-       if (deltas > 1 || deltas < 0)
-               return;
-       if (deltas > 0)
-               deltau += 1000*1000;
-       if (deltau >= usec)
-               return;
-       udelay(usec-deltau);
-}
-
-/* acsicmd_dma() sends an ACSI command and sets up the DMA to transfer
- * 'blocks' blocks of 512 bytes from/to 'buffer'.
- * Because the _IRQ signal is used for handshaking the command bytes,
- * the ACSI interrupt has to be disabled in this function. If the end
- * of the operation should be signalled by a real interrupt, it has to be
- * reenabled afterwards.
- */
-
-static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable)
-
-{      unsigned long   flags, paddr;
-       int                             i;
-
-#ifdef NO_WRITE
-       if (rwflag || *cmd == 0x0a) {
-               printk( "ACSI: Write commands disabled!\n" );
-               return( 0 );
-       }
-#endif
-       
-       rwflag = rwflag ? 0x100 : 0;
-       paddr = virt_to_phys( buffer );
-
-       acsi_delay_end(COMMAND_DELAY);
-       DISABLE_IRQ();
-
-       local_irq_save(flags);
-       /* Low on A1 */
-       dma_wd.dma_mode_status = 0x88 | rwflag;
-       MFPDELAY();
-
-       /* set DMA address */
-       dma_wd.dma_lo = (unsigned char)paddr;
-       paddr >>= 8;
-       MFPDELAY();
-       dma_wd.dma_md = (unsigned char)paddr;
-       paddr >>= 8;
-       MFPDELAY();
-       if (ATARIHW_PRESENT(EXTD_DMA))
-               st_dma_ext_dmahi = (unsigned short)paddr;
-       else
-               dma_wd.dma_hi = (unsigned char)paddr;
-       MFPDELAY();
-       local_irq_restore(flags);
-
-       /* send the command bytes except the last */
-       for( i = 0; i < 5; ++i ) {
-               DMA_LONG_WRITE( *cmd++, 0x8a | rwflag );
-               udelay(20);
-               if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
-       }
-
-       /* Clear FIFO and switch DMA to correct direction */  
-       dma_wd.dma_mode_status = 0x92 | (rwflag ^ 0x100);  
-       MFPDELAY();
-       dma_wd.dma_mode_status = 0x92 | rwflag;
-       MFPDELAY();
-
-       /* How many sectors for DMA */
-       dma_wd.fdc_acces_seccount = blocks;
-       MFPDELAY();
-       
-       /* send last command byte */
-       dma_wd.dma_mode_status = 0x8a | rwflag;
-       MFPDELAY();
-       DMA_LONG_WRITE( *cmd++, 0x0a | rwflag );
-       if (enable)
-               ENABLE_IRQ();
-       udelay(80);
-
-       return( 1 );
-}
-
-
-/*
- * acsicmd_nodma() sends an ACSI command that requires no DMA.
- */
-
-int acsicmd_nodma( const char *cmd, int enable)
-
-{      int     i;
-
-       acsi_delay_end(COMMAND_DELAY);
-       DISABLE_IRQ();
-
-       /* send first command byte */
-       dma_wd.dma_mode_status = 0x88;
-       MFPDELAY();
-       DMA_LONG_WRITE( *cmd++, 0x8a );
-       udelay(20);
-       if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
-
-       /* send the intermediate command bytes */
-       for( i = 0; i < 4; ++i ) {
-               DMA_LONG_WRITE( *cmd++, 0x8a );
-               udelay(20);
-               if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
-       }
-
-       /* send last command byte */
-       DMA_LONG_WRITE( *cmd++, 0x0a );
-       if (enable)
-               ENABLE_IRQ();
-       udelay(80);
-       
-       return( 1 );
-       /* Note that the ACSI interrupt is still disabled after this
-        * function. If you want to get the IRQ delivered, enable it manually!
-        */
-}
-
-
-static int acsi_reqsense( char *buffer, int targ, int lun)
-
-{
-       CMDSET_TARG_LUN( reqsense_cmd, targ, lun);
-       if (!acsicmd_dma( reqsense_cmd, buffer, 1, 0, 0 )) return( 0 );
-       if (!acsi_wait_for_IRQ( 10 )) return( 0 );
-       acsi_getstatus();
-       if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );
-       if (!acsi_wait_for_IRQ( 10 )) return( 0 );
-       acsi_getstatus();
-       if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );
-       if (!acsi_wait_for_IRQ( 10 )) return( 0 );
-       acsi_getstatus();
-       if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );
-       if (!acsi_wait_for_IRQ( 10 )) return( 0 );
-       acsi_getstatus();
-       dma_cache_maintenance( virt_to_phys(buffer), 16, 0 );
-       
-       return( 1 );
-}      
-
-
-/*
- * ACSI status phase: get the status byte from the bus
- *
- * I've seen several times that a 0xff status is read, propably due to
- * a timing error. In this case, the procedure is repeated after the
- * next _IRQ edge.
- */
-
-int acsi_getstatus( void )
-
-{      int     status;
-
-       DISABLE_IRQ();
-       for(;;) {
-               if (!acsi_wait_for_IRQ( 100 )) {
-                       acsi_delay_start();
-                       return( -1 );
-               }
-               dma_wd.dma_mode_status = 0x8a;
-               MFPDELAY();
-               status = dma_wd.fdc_acces_seccount;
-               if (status != 0xff) break;
-#ifdef DEBUG
-               printk("ACSI: skipping 0xff status byte\n" );
-#endif
-               udelay(40);
-               acsi_wait_for_noIRQ( 20 );
-       }
-       dma_wd.dma_mode_status = 0x80;
-       udelay(40);
-       acsi_wait_for_noIRQ( 20 );
-
-       acsi_delay_start();
-       return( status & 0x1f ); /* mask of the device# */
-}
-
-
-#if (defined(CONFIG_ATARI_SLM) || defined(CONFIG_ATARI_SLM_MODULE))
-
-/* Receive data in an extended status phase. Needed by SLM printer. */
-
-int acsi_extstatus( char *buffer, int cnt )
-
-{      int     status;
-
-       DISABLE_IRQ();
-       udelay(80);
-       while( cnt-- > 0 ) {
-               if (!acsi_wait_for_IRQ( 40 )) return( 0 );
-               dma_wd.dma_mode_status = 0x8a;
-               MFPDELAY();
-               status = dma_wd.fdc_acces_seccount;
-               MFPDELAY();
-               *buffer++ = status & 0xff;
-               udelay(40);
-       }
-       return( 1 );
-}
-
-
-/* Finish an extended status phase */
-
-void acsi_end_extstatus( void )
-
-{
-       dma_wd.dma_mode_status = 0x80;
-       udelay(40);
-       acsi_wait_for_noIRQ( 20 );
-       acsi_delay_start();
-}
-
-
-/* Send data in an extended command phase */
-
-int acsi_extcmd( unsigned char *buffer, int cnt )
-
-{
-       while( cnt-- > 0 ) {
-               DMA_LONG_WRITE( *buffer++, 0x8a );
-               udelay(20);
-               if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
-       }
-       return( 1 );
-}
-
-#endif
-
-
-static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip)
-
-{      int atari_err, i, errcode;
-       struct acsi_error *arr;
-
-       atari_err = aip->old_atari_disk;
-       if (atari_err)
-               errcode = errblk[0] & 0x7f;
-       else
-               if ((errblk[0] & 0x70) == 0x70)
-                       errcode = errblk[2] & 0x0f;
-               else
-                       errcode = errblk[0] & 0x0f;
-       
-       printk( KERN_ERR "ACSI error 0x%02x", errcode );
-
-       if (errblk[0] & 0x80)
-               printk( " for sector %d",
-                               ((errblk[1] & 0x1f) << 16) |
-                               (errblk[2] << 8) | errblk[0] );
-
-       arr = atari_err ? atari_acsi_errors : scsi_acsi_errors;
-       i = atari_err ? sizeof(atari_acsi_errors)/sizeof(*atari_acsi_errors) :
-                           sizeof(scsi_acsi_errors)/sizeof(*scsi_acsi_errors);
-       
-       for( --i; i >= 0; --i )
-               if (arr[i].code == errcode) break;
-       if (i >= 0)
-               printk( ": %s\n", arr[i].text );
-}
-
-/*******************************************************************
- *
- * ACSI interrupt routine
- *   Test, if this is a ACSI interrupt and call the irq handler
- *   Otherwise ignore this interrupt.
- *
- *******************************************************************/
-
-static irqreturn_t acsi_interrupt(int irq, void *data )
-
-{      void (*acsi_irq_handler)(void) = do_acsi;
-
-       do_acsi = NULL;
-       CLEAR_TIMER();
-
-       if (!acsi_irq_handler)
-               acsi_irq_handler = unexpected_acsi_interrupt;
-       acsi_irq_handler();
-       return IRQ_HANDLED;
-}
-
-
-/******************************************************************
- *
- * The Interrupt handlers
- *
- *******************************************************************/
-
-
-static void unexpected_acsi_interrupt( void )
-
-{
-       printk( KERN_WARNING "Unexpected ACSI interrupt\n" );
-}
-
-
-/* This function is called in case of errors. Because we cannot reset
- * the ACSI bus or a single device, there is no other choice than
- * retrying several times :-(
- */
-
-static void bad_rw_intr( void )
-
-{
-       if (!CURRENT)
-               return;
-
-       if (++CURRENT->errors >= MAX_ERRORS)
-               end_request(CURRENT, 0);
-       /* Otherwise just retry */
-}
-
-
-static void read_intr( void )
-
-{      int             status;
-       
-       status = acsi_getstatus();
-       if (status != 0) {
-               struct gendisk *disk = CURRENT->rq_disk;
-               struct acsi_info_struct *aip = disk->private_data;
-               printk(KERN_ERR "%s: ", disk->disk_name);
-               if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun))
-                       printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status );
-               else {
-                       acsi_print_error(acsi_buffer, aip);
-                       if (CARTRCH_STAT(aip, acsi_buffer))
-                               aip->changed = 1;
-               }
-               ENABLE_IRQ();
-               bad_rw_intr();
-               redo_acsi_request();
-               return;
-       }
-
-       dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 );
-       if (CurrentBuffer == acsi_buffer)
-               copy_from_acsibuffer();
-
-       do_end_requests();
-       redo_acsi_request();
-}
-
-
-static void write_intr(void)
-
-{      int     status;
-
-       status = acsi_getstatus();
-       if (status != 0) {
-               struct gendisk *disk = CURRENT->rq_disk;
-               struct acsi_info_struct *aip = disk->private_data;
-               printk( KERN_ERR "%s: ", disk->disk_name);
-               if (!acsi_reqsense( acsi_buffer, aip->target, aip->lun))
-                       printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status );
-               else {
-                       acsi_print_error(acsi_buffer, aip);
-                       if (CARTRCH_STAT(aip, acsi_buffer))
-                               aip->changed = 1;
-               }
-               bad_rw_intr();
-               redo_acsi_request();
-               return;
-       }
-
-       do_end_requests();
-       redo_acsi_request();
-}
-
-
-static void acsi_times_out( unsigned long dummy )
-
-{
-       DISABLE_IRQ();
-       if (!do_acsi) return;
-
-       do_acsi = NULL;
-       printk( KERN_ERR "ACSI timeout\n" );
-       if (!CURRENT)
-           return;
-       if (++CURRENT->errors >= MAX_ERRORS) {
-#ifdef DEBUG
-               printk( KERN_ERR "ACSI: too many errors.\n" );
-#endif
-               end_request(CURRENT, 0);
-       }
-
-       redo_acsi_request();
-}
-
-
-\f
-/***********************************************************************
- *
- *  Scatter-gather utility functions
- *
- ***********************************************************************/
-
-
-static void copy_to_acsibuffer( void )
-
-{      int                                     i;
-       char                            *src, *dst;
-       struct buffer_head      *bh;
-       
-       src = CURRENT->buffer;
-       dst = acsi_buffer;
-       bh = CURRENT->bh;
-
-       if (!bh)
-               memcpy( dst, src, CurrentNSect*512 );
-       else
-               for( i = 0; i < CurrentNReq; ++i ) {
-                       memcpy( dst, src, bh->b_size );
-                       dst += bh->b_size;
-                       if ((bh = bh->b_reqnext))
-                               src = bh->b_data;
-               }
-}
-
-
-static void copy_from_acsibuffer( void )
-
-{      int                                     i;
-       char                            *src, *dst;
-       struct buffer_head      *bh;
-       
-       dst = CURRENT->buffer;
-       src = acsi_buffer;
-       bh = CURRENT->bh;
-
-       if (!bh)
-               memcpy( dst, src, CurrentNSect*512 );
-       else
-               for( i = 0; i < CurrentNReq; ++i ) {
-                       memcpy( dst, src, bh->b_size );
-                       src += bh->b_size;
-                       if ((bh = bh->b_reqnext))
-                               dst = bh->b_data;
-               }
-}
-
-
-static void do_end_requests( void )
-
-{      int             i, n;
-
-       if (!CURRENT->bh) {
-               CURRENT->nr_sectors -= CurrentNSect;
-               CURRENT->current_nr_sectors -= CurrentNSect;
-               CURRENT->sector += CurrentNSect;
-               if (CURRENT->nr_sectors == 0)
-                       end_request(CURRENT, 1);
-       }
-       else {
-               for( i = 0; i < CurrentNReq; ++i ) {
-                       n = CURRENT->bh->b_size >> 9;
-                       CURRENT->nr_sectors -= n;
-                       CURRENT->current_nr_sectors -= n;
-                       CURRENT->sector += n;
-                       end_request(CURRENT, 1);
-               }
-       }
-}
-
-
-
-\f
-/***********************************************************************
- *
- *  do_acsi_request and friends
- *
- ***********************************************************************/
-
-static void do_acsi_request( request_queue_t * q )
-
-{
-       stdma_lock( acsi_interrupt, NULL );
-       redo_acsi_request();
-}
-
-
-static void redo_acsi_request( void )
-{
-       unsigned                        block, target, lun, nsect;
-       char                            *buffer;
-       unsigned long           pbuffer;
-       struct buffer_head      *bh;
-       struct gendisk *disk;
-       struct acsi_info_struct *aip;
-
-  repeat:
-       CLEAR_TIMER();
-
-       if (do_acsi)
-               return;
-
-       if (!CURRENT) {
-               do_acsi = NULL;
-               ENABLE_IRQ();
-               stdma_release();
-               return;
-       }
-
-       disk = CURRENT->rq_disk;
-       aip = disk->private_data;
-       if (CURRENT->bh) {
-               if (!CURRENT->bh && !buffer_locked(CURRENT->bh))
-                       panic("ACSI: block not locked");
-       }
-
-       block = CURRENT->sector;
-       if (block+CURRENT->nr_sectors >= get_capacity(disk)) {
-#ifdef DEBUG
-               printk( "%s: attempted access for blocks %d...%ld past end of device at block %ld.\n",
-                      disk->disk_name,
-                      block, block + CURRENT->nr_sectors - 1,
-                      get_capacity(disk));
-#endif
-               end_request(CURRENT, 0);
-               goto repeat;
-       }
-       if (aip->changed) {
-               printk( KERN_NOTICE "%s: request denied because cartridge has "
-                               "been changed.\n", disk->disk_name);
-               end_request(CURRENT, 0);
-               goto repeat;
-       }
-       
-       target = aip->target;
-       lun    = aip->lun;
-
-       /* Find out how many sectors should be transferred from/to
-        * consecutive buffers and thus can be done with a single command.
-        */
-       buffer      = CURRENT->buffer;
-       pbuffer     = virt_to_phys(buffer);
-       nsect       = CURRENT->current_nr_sectors;
-       CurrentNReq = 1;
-
-       if ((bh = CURRENT->bh) && bh != CURRENT->bhtail) {
-               if (!STRAM_ADDR(pbuffer)) {
-                       /* If transfer is done via the ACSI buffer anyway, we can
-                        * assemble as much bh's as fit in the buffer.
-                        */
-                       while( (bh = bh->b_reqnext) ) {
-                               if (nsect + (bh->b_size>>9) > ACSI_BUFFER_SECTORS) break;
-                               nsect += bh->b_size >> 9;
-                               ++CurrentNReq;
-                               if (bh == CURRENT->bhtail) break;
-                       }
-                       buffer = acsi_buffer;
-                       pbuffer = phys_acsi_buffer;
-               }
-               else {
-                       unsigned long pendadr, pnewadr;
-                       pendadr = pbuffer + nsect*512;
-                       while( (bh = bh->b_reqnext) ) {
-                               pnewadr = virt_to_phys(bh->b_data);
-                               if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break;
-                               nsect += bh->b_size >> 9;
-                               pendadr = pnewadr + bh->b_size;
-                               ++CurrentNReq;
-                               if (bh == CURRENT->bhtail) break;
-                       }
-               }
-       }
-       else {
-               if (!STRAM_ADDR(pbuffer)) {
-                       buffer = acsi_buffer;
-                       pbuffer = phys_acsi_buffer;
-                       if (nsect > ACSI_BUFFER_SECTORS)
-                               nsect = ACSI_BUFFER_SECTORS;
-               }
-       }
-       CurrentBuffer = buffer;
-       CurrentNSect  = nsect;
-
-       if (rq_data_dir(CURRENT) == WRITE) {
-               CMDSET_TARG_LUN( write_cmd, target, lun );
-               CMDSET_BLOCK( write_cmd, block );
-               CMDSET_LEN( write_cmd, nsect );
-               if (buffer == acsi_buffer)
-                       copy_to_acsibuffer();
-               dma_cache_maintenance( pbuffer, nsect*512, 1 );
-               do_acsi = write_intr;
-               if (!acsicmd_dma( write_cmd, buffer, nsect, 1, 1)) {
-                       do_acsi = NULL;
-                       printk( KERN_ERR "ACSI (write): Timeout in command block\n" );
-                       bad_rw_intr();
-                       goto repeat;
-               }
-               SET_TIMER();
-               return;
-       }
-       if (rq_data_dir(CURRENT) == READ) {
-               CMDSET_TARG_LUN( read_cmd, target, lun );
-               CMDSET_BLOCK( read_cmd, block );
-               CMDSET_LEN( read_cmd, nsect );
-               do_acsi = read_intr;
-               if (!acsicmd_dma( read_cmd, buffer, nsect, 0, 1)) {
-                       do_acsi = NULL;
-                       printk( KERN_ERR "ACSI (read): Timeout in command block\n" );
-                       bad_rw_intr();
-                       goto repeat;
-               }
-               SET_TIMER();
-               return;
-       }
-       panic("unknown ACSI command");
-}
-
-
-\f
-/***********************************************************************
- *
- *  Misc functions: ioctl, open, release, check_change, ...
- *
- ***********************************************************************/
-
-static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-       struct acsi_info_struct *aip = bdev->bd_disk->private_data;
-
-       /*
-        * Just fake some geometry here, it's nonsense anyway
-        * To make it easy, use Adaptec's usual 64/32 mapping
-        */
-       geo->heads = 64;
-       geo->sectors = 32;
-       geo->cylinders = aip->size >> 11;
-       return 0;
-}
-
-static int acsi_ioctl( struct inode *inode, struct file *file,
-                                          unsigned int cmd, unsigned long arg )
-{
-       struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct acsi_info_struct *aip = disk->private_data;
-       switch (cmd) {
-         case SCSI_IOCTL_GET_IDLUN:
-               /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */
-               put_user( aip->target | (aip->lun << 8),
-                                 &((Scsi_Idlun *) arg)->dev_id );
-               put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id );
-               return 0;
-         default:
-               return -EINVAL;
-       }
-}
-
-
-/*
- * Open a device, check for read-only and lock the medium if it is
- * removable.
- *
- * Changes by Martin Rogge, 9th Aug 1995:
- * Check whether check_disk_change (and therefore revalidate_acsidisk)
- * was successful. They fail when there is no medium in the drive.
- *
- * The problem of media being changed during an operation can be 
- * ignored because of the prevent_removal code.
- *
- * Added check for the validity of the device number.
- *
- */
-
-static int acsi_open( struct inode * inode, struct file * filp )
-{
-       struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct acsi_info_struct *aip = disk->private_data;
-
-       if (aip->access_count == 0 && aip->removable) {
-#if 0
-               aip->changed = 1;       /* safety first */
-#endif
-               check_disk_change( inode->i_bdev );
-               if (aip->changed)       /* revalidate was not successful (no medium) */
-                       return -ENXIO;
-               acsi_prevent_removal(aip, 1);
-       }
-       aip->access_count++;
-
-       if (filp && filp->f_mode) {
-               check_disk_change( inode->i_bdev );
-               if (filp->f_mode & 2) {
-                       if (aip->read_only) {
-                               acsi_release( inode, filp );
-                               return -EROFS;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-
-static int acsi_release( struct inode * inode, struct file * file )
-{
-       struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct acsi_info_struct *aip = disk->private_data;
-       if (--aip->access_count == 0 && aip->removable)
-               acsi_prevent_removal(aip, 0);
-       return( 0 );
-}
-
-/*
- * Prevent or allow a media change for removable devices.
- */
-
-static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag)
-{
-       stdma_lock( NULL, NULL );
-       
-       CMDSET_TARG_LUN(pa_med_rem_cmd, aip->target, aip->lun);
-       CMDSET_LEN( pa_med_rem_cmd, flag );
-       
-       if (acsicmd_nodma(pa_med_rem_cmd, 0) && acsi_wait_for_IRQ(3*HZ))
-               acsi_getstatus();
-       /* Do not report errors -- some devices may not know this command. */
-
-       ENABLE_IRQ();
-       stdma_release();
-}
-
-static int acsi_media_change(struct gendisk *disk)
-{
-       struct acsi_info_struct *aip = disk->private_data;
-
-       if (!aip->removable) 
-               return 0;
-
-       if (aip->changed)
-               /* We can be sure that the medium has been changed -- REQUEST
-                * SENSE has reported this earlier.
-                */
-               return 1;
-
-       /* If the flag isn't set, make a test by reading block 0.
-        * If errors happen, it seems to be better to say "changed"...
-        */
-       stdma_lock( NULL, NULL );
-       CMDSET_TARG_LUN(read_cmd, aip->target, aip->lun);
-       CMDSET_BLOCK( read_cmd, 0 );
-       CMDSET_LEN( read_cmd, 1 );
-       if (acsicmd_dma(read_cmd, acsi_buffer, 1, 0, 0) &&
-           acsi_wait_for_IRQ(3*HZ)) {
-               if (acsi_getstatus()) {
-                       if (acsi_reqsense(acsi_buffer, aip->target, aip->lun)) {
-                               if (CARTRCH_STAT(aip, acsi_buffer))
-                                       aip->changed = 1;
-                       }
-                       else {
-                               printk( KERN_ERR "%s: REQUEST SENSE failed in test for "
-                                      "medium change; assuming a change\n", disk->disk_name );
-                               aip->changed = 1;
-                       }
-               }
-       }
-       else {
-               printk( KERN_ERR "%s: Test for medium changed timed out; "
-                               "assuming a change\n", disk->disk_name);
-               aip->changed = 1;
-       }
-       ENABLE_IRQ();
-       stdma_release();
-
-       /* Now, after reading a block, the changed status is surely valid. */
-       return aip->changed;
-}
-
-
-static int acsi_change_blk_size( int target, int lun)
-
-{      int i;
-
-       for (i=0; i<12; i++)
-               acsi_buffer[i] = 0;
-
-       acsi_buffer[3] = 8;
-       acsi_buffer[10] = 2;
-       CMDSET_TARG_LUN( modeselect_cmd, target, lun);
-
-       if (!acsicmd_dma( modeselect_cmd, acsi_buffer, 1,1,0) ||
-               !acsi_wait_for_IRQ( 3*HZ ) ||
-               acsi_getstatus() != 0 ) {
-               return(0);
-       }
-       return(1);
-}
-
-
-static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd )
-
-{
-       int page;
-
-       CMDSET_TARG_LUN( modesense_cmd, target, lun );
-       for (page=0; page<4; page++) {
-               modesense_cmd[2] = page;
-               if (!acsicmd_dma( modesense_cmd, acsi_buffer, 1, 0, 0 ) ||
-                   !acsi_wait_for_IRQ( 3*HZ ) ||
-                   acsi_getstatus())
-                       continue;
-
-               /* read twice to jump over the second 16-byte border! */
-               udelay(300);
-               if (acsi_wait_for_noIRQ( 20 ) &&
-                   acsicmd_nodma( modesense_cmd, 0 ) &&
-                   acsi_wait_for_IRQ( 3*HZ ) &&
-                   acsi_getstatus() == 0)
-                       break;
-       }
-       if (page == 4) {
-               return(0);
-       }
-
-       dma_cache_maintenance( phys_acsi_buffer, sizeof(SENSE_DATA), 0 );
-       *sd = *(SENSE_DATA *)acsi_buffer;
-
-       /* Validity check, depending on type of data */
-       
-       switch( SENSE_TYPE(*sd) ) {
-
-         case SENSE_TYPE_ATARI:
-               if (CAPACITY(*sd) == 0)
-                       goto invalid_sense;
-               break;
-
-         case SENSE_TYPE_SCSI:
-               if (sd->scsi.descriptor_size != 8)
-                       goto invalid_sense;
-               break;
-
-         case SENSE_TYPE_UNKNOWN:
-
-               printk( KERN_ERR "ACSI target %d, lun %d: Cannot interpret "
-                               "sense data\n", target, lun ); 
-               
-         invalid_sense:
-
-#ifdef DEBUG
-               {       int i;
-               printk( "Mode sense data for ACSI target %d, lun %d seem not valid:",
-                               target, lun );
-               for( i = 0; i < sizeof(SENSE_DATA); ++i )
-                       printk( "%02x ", (unsigned char)acsi_buffer[i] );
-               printk( "\n" );
-               }
-#endif
-               return( 0 );
-       }
-               
-       return( 1 );
-}
-
-
-
-/*******************************************************************
- *
- *  Initialization
- *
- ********************************************************************/
-
-
-extern struct block_device_operations acsi_fops;
-
-static struct gendisk *acsi_gendisk[MAX_DEV];
-
-#define MAX_SCSI_DEVICE_CODE 10
-
-static const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
-{
- "Direct-Access    ",
- "Sequential-Access",
- "Printer          ",
- "Processor        ",
- "WORM             ",
- "CD-ROM           ",
- "Scanner          ",
- "Optical Device   ",
- "Medium Changer   ",
- "Communications   "
-};
-
-static void print_inquiry(unsigned char *data)
-{
-       int i;
-
-       printk(KERN_INFO "  Vendor: ");
-       for (i = 8; i < 16; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
-
-       printk("  Model: ");
-       for (i = 16; i < 32; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
-
-       printk("  Rev: ");
-       for (i = 32; i < 36; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
-
-       printk("\n");
-
-       i = data[0] & 0x1f;
-
-       printk(KERN_INFO "  Type:   %s ", (i < MAX_SCSI_DEVICE_CODE
-                                                                          ? scsi_device_types[i]
-                                                                          : "Unknown          "));
-       printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
-       if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
-         printk(" CCS\n");
-       else
-         printk("\n");
-}
-
-
-/* 
- * Changes by Martin Rogge, 9th Aug 1995: 
- * acsi_devinit has been taken out of acsi_geninit, because it needs 
- * to be called from revalidate_acsidisk. The result of request sense 
- * is now checked for DRIVE NOT READY.
- *
- * The structure *aip is only valid when acsi_devinit returns 
- * DEV_SUPPORTED. 
- *
- */
-       
-#define DEV_NONE       0
-#define DEV_UNKNOWN    1
-#define DEV_SUPPORTED  2
-#define DEV_SLM                3
-
-static int acsi_devinit(struct acsi_info_struct *aip)
-{
-       int status, got_inquiry;
-       SENSE_DATA sense;
-       unsigned char reqsense, extsense;
-
-       /*****************************************************************/
-       /* Do a TEST UNIT READY command to test the presence of a device */
-       /*****************************************************************/
-
-       CMDSET_TARG_LUN(tur_cmd, aip->target, aip->lun);
-       if (!acsicmd_nodma(tur_cmd, 0)) {
-               /* timed out -> no device here */
-#ifdef DEBUG_DETECT
-               printk("target %d lun %d: timeout\n", aip->target, aip->lun);
-#endif
-               return DEV_NONE;
-       }
-               
-       /*************************/
-       /* Read the ACSI status. */
-       /*************************/
-
-       status = acsi_getstatus();
-       if (status) {
-               if (status == 0x12) {
-                       /* The SLM printer should be the only device that
-                        * responds with the error code in the status byte. In
-                        * correct status bytes, bit 4 is never set.
-                        */
-                       printk( KERN_INFO "Detected SLM printer at id %d lun %d\n",
-                              aip->target, aip->lun);
-                       return DEV_SLM;
-               }
-               /* ignore CHECK CONDITION, since some devices send a
-                  UNIT ATTENTION */
-               if ((status & 0x1e) != 0x2) {
-#ifdef DEBUG_DETECT
-                       printk("target %d lun %d: status %d\n",
-                              aip->target, aip->lun, status);
-#endif
-                       return DEV_UNKNOWN;
-               }
-       }
-
-       /*******************************/
-       /* Do a REQUEST SENSE command. */
-       /*******************************/
-
-       if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) {
-               printk( KERN_WARNING "acsi_reqsense failed\n");
-               acsi_buffer[0] = 0;
-               acsi_buffer[2] = UNIT_ATTENTION;
-       }
-       reqsense = acsi_buffer[0];
-       extsense = acsi_buffer[2] & 0xf;
-       if (status) {
-               if ((reqsense & 0x70) == 0x70) {        /* extended sense */
-                       if (extsense != UNIT_ATTENTION &&
-                           extsense != NOT_READY) {
-#ifdef DEBUG_DETECT
-                               printk("target %d lun %d: extended sense %d\n",
-                                      aip->target, aip->lun, extsense);
-#endif
-                               return DEV_UNKNOWN;
-                       }
-               }
-               else {
-                       if (reqsense & 0x7f) {
-#ifdef DEBUG_DETECT
-                               printk("target %d lun %d: sense %d\n",
-                                      aip->target, aip->lun, reqsense);
-#endif
-                               return DEV_UNKNOWN;
-                       }
-               }
-       }
-       else 
-               if (reqsense == 0x4) {  /* SH204 Bug workaround */
-#ifdef DEBUG_DETECT
-                       printk("target %d lun %d status=0 sense=4\n",
-                              aip->target, aip->lun);
-#endif
-                       return DEV_UNKNOWN;
-               }
-
-       /***********************************************************/
-       /* Do an INQUIRY command to get more infos on this device. */
-       /***********************************************************/
-
-       /* Assume default values */
-       aip->removable = 1;
-       aip->read_only = 0;
-       aip->old_atari_disk = 0;
-       aip->changed = (extsense == NOT_READY); /* medium inserted? */
-       aip->size = DEFAULT_SIZE;
-       got_inquiry = 0;
-       /* Fake inquiry result for old atari disks */
-       memcpy(acsi_buffer, "\000\000\001\000    Adaptec 40xx"
-              "                    ", 40);
-       CMDSET_TARG_LUN(inquiry_cmd, aip->target, aip->lun);
-       if (acsicmd_dma(inquiry_cmd, acsi_buffer, 1, 0, 0) &&
-           acsi_getstatus() == 0) {
-               acsicmd_nodma(inquiry_cmd, 0);
-               acsi_getstatus();
-               dma_cache_maintenance( phys_acsi_buffer, 256, 0 );
-               got_inquiry = 1;
-               aip->removable = !!(acsi_buffer[1] & 0x80);
-       }
-       if (aip->type == NONE)  /* only at boot time */
-               print_inquiry(acsi_buffer);
-       switch(acsi_buffer[0]) {
-         case TYPE_DISK:
-               aip->type = HARDDISK;
-               break;
-         case TYPE_ROM:
-               aip->type = CDROM;
-               aip->read_only = 1;
-               break;
-         default:
-               return DEV_UNKNOWN;
-       }
-       /****************************/
-       /* Do a MODE SENSE command. */
-       /****************************/
-
-       if (!acsi_mode_sense(aip->target, aip->lun, &sense)) {
-               printk( KERN_WARNING "No mode sense data.\n" );
-               return DEV_UNKNOWN;
-       }
-       if ((SECTOR_SIZE(sense) != 512) &&
-           ((aip->type != CDROM) ||
-            !acsi_change_blk_size(aip->target, aip->lun) ||
-            !acsi_mode_sense(aip->target, aip->lun, &sense) ||
-            (SECTOR_SIZE(sense) != 512))) {
-               printk( KERN_WARNING "Sector size != 512 not supported.\n" );
-               return DEV_UNKNOWN;
-       }
-       /* There are disks out there that claim to have 0 sectors... */
-       if (CAPACITY(sense))
-               aip->size = CAPACITY(sense);    /* else keep DEFAULT_SIZE */
-       if (!got_inquiry && SENSE_TYPE(sense) == SENSE_TYPE_ATARI) {
-               /* If INQUIRY failed and the sense data suggest an old
-                * Atari disk (SH20x, Megafile), the disk is not removable
-                */
-               aip->removable = 0;
-               aip->old_atari_disk = 1;
-       }
-       
-       /******************/
-       /* We've done it. */
-       /******************/
-       
-       return DEV_SUPPORTED;
-}
-
-EXPORT_SYMBOL(acsi_delay_start);
-EXPORT_SYMBOL(acsi_delay_end);
-EXPORT_SYMBOL(acsi_wait_for_IRQ);
-EXPORT_SYMBOL(acsi_wait_for_noIRQ);
-EXPORT_SYMBOL(acsicmd_nodma);
-EXPORT_SYMBOL(acsi_getstatus);
-EXPORT_SYMBOL(acsi_buffer);
-EXPORT_SYMBOL(phys_acsi_buffer);
-
-#ifdef CONFIG_ATARI_SLM_MODULE
-void acsi_attach_SLMs( int (*attach_func)( int, int ) );
-
-EXPORT_SYMBOL(acsi_extstatus);
-EXPORT_SYMBOL(acsi_end_extstatus);
-EXPORT_SYMBOL(acsi_extcmd);
-EXPORT_SYMBOL(acsi_attach_SLMs);
-
-/* to remember IDs of SLM devices, SLM module is loaded later
- * (index is target#, contents is lun#, -1 means "no SLM") */
-int SLM_devices[8];
-#endif
-
-static struct block_device_operations acsi_fops = {
-       .owner          = THIS_MODULE,
-       .open           = acsi_open,
-       .release        = acsi_release,
-       .ioctl          = acsi_ioctl,
-       .getgeo         = acsi_getgeo,
-       .media_changed  = acsi_media_change,
-       .revalidate_disk= acsi_revalidate,
-};
-
-#ifdef CONFIG_ATARI_SLM_MODULE
-/* call attach_slm() for each device that is a printer; needed for init of SLM
- * driver as a module, since it's not yet present if acsi.c is inited and thus
- * the bus gets scanned. */
-void acsi_attach_SLMs( int (*attach_func)( int, int ) )
-{
-       int i, n = 0;
-
-       for( i = 0; i < 8; ++i )
-               if (SLM_devices[i] >= 0)
-                       n += (*attach_func)( i, SLM_devices[i] );
-       printk( KERN_INFO "Found %d SLM printer(s) total.\n", n );
-}
-#endif /* CONFIG_ATARI_SLM_MODULE */
-
-
-int acsi_init( void )
-{
-       int err = 0;
-       int i, target, lun;
-       struct acsi_info_struct *aip;
-#ifdef CONFIG_ATARI_SLM
-       int n_slm = 0;
-#endif
-       if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI))
-               return 0;
-       if (register_blkdev(ACSI_MAJOR, "ad")) {
-               err = -EBUSY;
-               goto out1;
-       }
-       if (!(acsi_buffer =
-                 (char *)atari_stram_alloc(ACSI_BUFFER_SIZE, "acsi"))) {
-               err = -ENOMEM;
-               printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" );
-               goto out2;
-       }
-       phys_acsi_buffer = virt_to_phys( acsi_buffer );
-       STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000;
-       
-       acsi_queue = blk_init_queue(do_acsi_request, &acsi_lock);
-       if (!acsi_queue) {
-               err = -ENOMEM;
-               goto out2a;
-       }
-#ifdef CONFIG_ATARI_SLM
-       err = slm_init();
-#endif
-       if (err)
-               goto out3;
-
-       printk( KERN_INFO "Probing ACSI devices:\n" );
-       NDevices = 0;
-#ifdef CONFIG_ATARI_SLM_MODULE
-       for( i = 0; i < 8; ++i )
-               SLM_devices[i] = -1;
-#endif
-       stdma_lock(NULL, NULL);
-
-       for (target = 0; target < 8 && NDevices < MAX_DEV; ++target) {
-               lun = 0;
-               do {
-                       aip = &acsi_info[NDevices];
-                       aip->type = NONE;
-                       aip->target = target;
-                       aip->lun = lun;
-                       i = acsi_devinit(aip);
-                       switch (i) {
-                         case DEV_SUPPORTED:
-                               printk( KERN_INFO "Detected ");
-                               switch (aip->type) {
-                                 case HARDDISK:
-                                       printk("disk");
-                                       break;
-                                 case CDROM:
-                                       printk("cdrom");
-                                       break;
-                                 default:
-                               }
-                               printk(" ad%c at id %d lun %d ",
-                                      'a' + NDevices, target, lun);
-                               if (aip->removable) 
-                                       printk("(removable) ");
-                               if (aip->read_only) 
-                                       printk("(read-only) ");
-                               if (aip->size == DEFAULT_SIZE)
-                                       printk(" unkown size, using default ");
-                               printk("%ld MByte\n",
-                                      (aip->size*512+1024*1024/2)/(1024*1024));
-                               NDevices++;
-                               break;
-                         case DEV_SLM:
-#ifdef CONFIG_ATARI_SLM
-                               n_slm += attach_slm( target, lun );
-                               break;
-#endif
-#ifdef CONFIG_ATARI_SLM_MODULE
-                               SLM_devices[target] = lun;
-                               break;
-#endif
-                               /* neither of the above: fall through to unknown device */
-                         case DEV_UNKNOWN:
-                               printk( KERN_INFO "Detected unsupported device at "
-                                               "id %d lun %d\n", target, lun);
-                               break;
-                       }
-               }
-#ifdef CONFIG_ACSI_MULTI_LUN
-               while (i != DEV_NONE && ++lun < MAX_LUN);
-#else
-               while (0);
-#endif
-       }
-
-       /* reenable interrupt */
-       ENABLE_IRQ();
-       stdma_release();
-
-#ifndef CONFIG_ATARI_SLM
-       printk( KERN_INFO "Found %d ACSI device(s) total.\n", NDevices );
-#else
-       printk( KERN_INFO "Found %d ACSI device(s) and %d SLM printer(s) total.\n",
-                       NDevices, n_slm );
-#endif
-       err = -ENOMEM;
-       for( i = 0; i < NDevices; ++i ) {
-               acsi_gendisk[i] = alloc_disk(16);
-               if (!acsi_gendisk[i])
-                       goto out4;
-       }
-
-       for( i = 0; i < NDevices; ++i ) {
-               struct gendisk *disk = acsi_gendisk[i];
-               sprintf(disk->disk_name, "ad%c", 'a'+i);
-               aip = &acsi_info[NDevices];
-               disk->major = ACSI_MAJOR;
-               disk->first_minor = i << 4;
-               if (acsi_info[i].type != HARDDISK)
-                       disk->minors = 1;
-               disk->fops = &acsi_fops;
-               disk->private_data = &acsi_info[i];
-               set_capacity(disk, acsi_info[i].size);
-               disk->queue = acsi_queue;
-               add_disk(disk);
-       }
-       return 0;
-out4:
-       while (i--)
-               put_disk(acsi_gendisk[i]);
-out3:
-       blk_cleanup_queue(acsi_queue);
-out2a:
-       atari_stram_free( acsi_buffer );
-out2:
-       unregister_blkdev( ACSI_MAJOR, "ad" );
-out1:
-       return err;
-}
-
-
-#ifdef MODULE
-
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-       int err;
-
-       if ((err = acsi_init()))
-               return( err );
-       printk( KERN_INFO "ACSI driver loaded as module.\n");
-       return( 0 );
-}
-
-void cleanup_module(void)
-{
-       int i;
-       del_timer( &acsi_timer );
-       blk_cleanup_queue(acsi_queue);
-       atari_stram_free( acsi_buffer );
-
-       if (unregister_blkdev( ACSI_MAJOR, "ad" ) != 0)
-               printk( KERN_ERR "acsi: cleanup_module failed\n");
-
-       for (i = 0; i < NDevices; i++) {
-               del_gendisk(acsi_gendisk[i]);
-               put_disk(acsi_gendisk[i]);
-       }
-}
-#endif
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed scsi disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- *
- * Changes by Martin Rogge, 9th Aug 1995: 
- * got cd-roms to work by calling acsi_devinit. There are only two problems:
- * First, if there is no medium inserted, the status will remain "changed".
- * That is no problem at all, but our design of three-valued logic (medium
- * changed, medium not changed, no medium inserted).
- * Secondly the check could fail completely and the drive could deliver
- * nonsensical data, which could mess up the acsi_info[] structure. In
- * that case we try to make the entry safe.
- *
- */
-
-static int acsi_revalidate(struct gendisk *disk)
-{
-       struct acsi_info_struct *aip = disk->private_data;
-       stdma_lock( NULL, NULL );
-       if (acsi_devinit(aip) != DEV_SUPPORTED) {
-               printk( KERN_ERR "ACSI: revalidate failed for target %d lun %d\n",
-                      aip->target, aip->lun);
-               aip->size = 0;
-               aip->read_only = 1;
-               aip->removable = 1;
-               aip->changed = 1; /* next acsi_open will try again... */
-       }
-
-       ENABLE_IRQ();
-       stdma_release();
-       set_capacity(disk, aip->size);
-       return 0;
-}
index 27a139025cedaf677124a67d21a54447b621f500..6ce8b897e2623f025de20994a8f02a11eee2e8f2 100644 (file)
@@ -1363,7 +1363,7 @@ static void redo_fd_request(void)
 #ifdef DEBUG
                printk("fd: sector %ld + %d requested for %s\n",
                       CURRENT->sector,cnt,
-                      (CURRENT->cmd==READ)?"read":"write");
+                      (rq_data_dir(CURRENT) == READ) ? "read" : "write");
 #endif
                block = CURRENT->sector + cnt;
                if ((int)block > floppy->blocks) {
index 5acc6c44aeadd1a57908ad3d63001df665496561..0fcad430474ecaf0700e760f6acd0a0de2628093 100644 (file)
@@ -87,6 +87,7 @@ static const struct pci_device_id cciss_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3214},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3237},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
        {PCI_VENDOR_ID_HP,     PCI_ANY_ID,      PCI_ANY_ID, PCI_ANY_ID,
                PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
        {0,}
@@ -119,6 +120,7 @@ static struct board_type products[] = {
        {0x3214103C, "Smart Array E200i", &SA5_access, 120},
        {0x3215103C, "Smart Array E200i", &SA5_access, 120},
        {0x3237103C, "Smart Array E500", &SA5_access, 512},
+       {0x323D103C, "Smart Array P700m", &SA5_access, 512},
        {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
 };
 
index 0ed5470d25339674a5c449feab66f5505db5f3c2..4503290da4078c2916bafdc8af301fac333f5349 100644 (file)
@@ -74,6 +74,7 @@
 #include <linux/highmem.h>
 #include <linux/gfp.h>
 #include <linux/kthread.h>
+#include <linux/splice.h>
 
 #include <asm/uaccess.h>
 
@@ -401,50 +402,73 @@ struct lo_read_data {
 };
 
 static int
-lo_read_actor(read_descriptor_t *desc, struct page *page,
-             unsigned long offset, unsigned long size)
+lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+               struct splice_desc *sd)
 {
-       unsigned long count = desc->count;
-       struct lo_read_data *p = desc->arg.data;
+       struct lo_read_data *p = sd->u.data;
        struct loop_device *lo = p->lo;
+       struct page *page = buf->page;
        sector_t IV;
+       size_t size;
+       int ret;
 
-       IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9);
+       ret = buf->ops->confirm(pipe, buf);
+       if (unlikely(ret))
+               return ret;
 
-       if (size > count)
-               size = count;
+       IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) +
+                                                       (buf->offset >> 9);
+       size = sd->len;
+       if (size > p->bsize)
+               size = p->bsize;
 
-       if (lo_do_transfer(lo, READ, page, offset, p->page, p->offset, size, IV)) {
-               size = 0;
+       if (lo_do_transfer(lo, READ, page, buf->offset, p->page, p->offset, size, IV)) {
                printk(KERN_ERR "loop: transfer error block %ld\n",
                       page->index);
-               desc->error = -EINVAL;
+               size = -EINVAL;
        }
 
        flush_dcache_page(p->page);
 
-       desc->count = count - size;
-       desc->written += size;
-       p->offset += size;
+       if (size > 0)
+               p->offset += size;
+
        return size;
 }
 
+static int
+lo_direct_splice_actor(struct pipe_inode_info *pipe, struct splice_desc *sd)
+{
+       return __splice_from_pipe(pipe, sd, lo_splice_actor);
+}
+
 static int
 do_lo_receive(struct loop_device *lo,
              struct bio_vec *bvec, int bsize, loff_t pos)
 {
        struct lo_read_data cookie;
+       struct splice_desc sd;
        struct file *file;
-       int retval;
+       long retval;
 
        cookie.lo = lo;
        cookie.page = bvec->bv_page;
        cookie.offset = bvec->bv_offset;
        cookie.bsize = bsize;
+
+       sd.len = 0;
+       sd.total_len = bvec->bv_len;
+       sd.flags = 0;
+       sd.pos = pos;
+       sd.u.data = &cookie;
+
        file = lo->lo_backing_file;
-       retval = file->f_op->sendfile(file, &pos, bvec->bv_len,
-                       lo_read_actor, &cookie);
-       return (retval < 0)? retval: 0;
+       retval = splice_direct_to_actor(file, &sd, lo_direct_splice_actor);
+
+       if (retval < 0)
+               return retval;
+
+       return 0;
 }
 
 static int
@@ -679,8 +703,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
        if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
                goto out_putf;
 
-       /* new backing store needs to support loop (eg sendfile) */
-       if (!inode->i_fop->sendfile)
+       /* new backing store needs to support loop (eg splice_read) */
+       if (!inode->i_fop->splice_read)
                goto out_putf;
 
        /* size of the new backing store needs to be the same */
@@ -760,7 +784,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
                 * If we can't read - sorry. If we only can't write - well,
                 * it's going to be read-only.
                 */
-               if (!file->f_op->sendfile)
+               if (!file->f_op->splice_read)
                        goto out_putf;
                if (aops->prepare_write && aops->commit_write)
                        lo_flags |= LO_FLAGS_USE_AOPS;
index 069ae39a9cd9023eb62d9115f2885383c2df86ef..c575fb1d585f1131714a6658cc1b823404140cfd 100644 (file)
@@ -416,7 +416,7 @@ static void nbd_clear_que(struct nbd_device *lo)
 /*
  * We always wait for result of write, for now. It would be nice to make it optional
  * in future
- * if ((req->cmd == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) 
+ * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK))
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig
deleted file mode 100644 (file)
index 4b12e90..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-#
-# CDROM driver configuration
-#
-
-menu "Old CD-ROM drivers (not SCSI, not IDE)"
-       depends on ISA && BLOCK
-
-config CD_NO_IDESCSI
-       bool "Support non-SCSI/IDE/ATAPI CDROM drives"
-       ---help---
-         If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
-         here, otherwise N. Read the CD-ROM-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about these CD-ROM drives. If you are unsure what you
-         have, say Y and find out whether you have one of the following
-         drives.
-
-         For each of these drivers, a <file:Documentation/cdrom/{driver_name}>
-         exists. Especially in cases where you do not know exactly which kind
-         of drive you have you should read there. Most of these drivers use a
-         file drivers/cdrom/{driver_name}.h where you can define your
-         interface parameters and switch some internal goodies.
-
-         To compile these CD-ROM drivers as a module, choose M instead of Y.
-
-         If you want to use any of these CD-ROM drivers, you also have to
-         answer Y or M to "ISO 9660 CD-ROM file system support" below (this
-         answer will get "defaulted" for you if you enable any of the Linux
-         CD-ROM drivers).
-
-config AZTCD
-       tristate "Aztech/Orchid/Okano/Wearnes/TXC/CyDROM  CDROM support"
-       depends on CD_NO_IDESCSI
-       ---help---
-         This is your driver if you have an Aztech CDA268-01A, Orchid
-         CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or
-         CR540 CD-ROM drive.  This driver -- just like all these CD-ROM
-         drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such
-         as Aztech CDA269-031SE. Please read the file
-         <file:Documentation/cdrom/aztcd>.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called aztcd.
-
-config GSCD
-       tristate "Goldstar R420 CDROM support"
-       depends on CD_NO_IDESCSI
-       ---help---
-         If this is your CD-ROM drive, say Y here.  As described in the file
-         <file:Documentation/cdrom/gscd>, you might have to change a setting
-         in the file <file:drivers/cdrom/gscd.h> before compiling the
-         kernel.  Please read the file <file:Documentation/cdrom/gscd>.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called gscd.
-
-config SBPCD
-       tristate "Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support"
-       depends on CD_NO_IDESCSI && BROKEN_ON_SMP
-       ---help---
-         This driver supports most of the drives which use the Panasonic or
-         Sound Blaster interface.  Please read the file
-         <file:Documentation/cdrom/sbpcd>.
-
-         The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives
-         (sometimes labeled "Creative"), the Creative Labs CD200, the
-         Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x
-         model), the TEAC CD-55A fall under this category.  Some other
-         "electrically compatible" drives (Vertos, Genoa, some Funai models)
-         are currently not supported; for the Sanyo H94A drive currently a
-         separate driver (asked later) is responsible.  Most drives have a
-         uniquely shaped faceplate, with a caddyless motorized drawer, but
-         without external brand markings.  The older CR-52x drives have a
-         caddy and manual loading/eject, but still no external markings.  The
-         driver is able to do an extended auto-probing for interface
-         addresses and drive types; this can help to find facts in cases you
-         are not sure, but can consume some time during the boot process if
-         none of the supported drives gets found.  Once your drive got found,
-         you should enter the reported parameters into
-         <file:drivers/cdrom/sbpcd.h> and set "DISTRIBUTION 0" there.
-
-         This driver can support up to four CD-ROM controller cards, and each
-         card can support up to four CD-ROM drives; if you say Y here, you
-         will be asked how many controller cards you have.  If compiled as a
-         module, only one controller card (but with up to four drives) is
-         usable.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called sbpcd.
-
-config MCDX
-       tristate "Mitsumi CDROM support"
-       depends on CD_NO_IDESCSI
-       ---help---
-         Use this driver if you want to be able to use your Mitsumi LU-005,
-         FX-001 or FX-001D CD-ROM drive.
-
-         Please read the file <file:Documentation/cdrom/mcdx>.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called mcdx.
-
-config OPTCD
-       tristate "Optics Storage DOLPHIN 8000AT CDROM support"
-       depends on CD_NO_IDESCSI
-       ---help---
-         This is the driver for the 'DOLPHIN' drive with a 34-pin Sony
-         compatible interface. It also works with the Lasermate CR328A. If
-         you have one of those, say Y. This driver does not work for the
-         Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that
-         one. Please read the file <file:Documentation/cdrom/optcd>.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called optcd.
-
-config CM206
-       tristate "Philips/LMS CM206 CDROM support"
-       depends on CD_NO_IDESCSI && BROKEN_ON_SMP
-       ---help---
-         If you have a Philips/LMS CD-ROM drive cm206 in combination with a
-         cm260 host adapter card, say Y here. Please also read the file
-         <file:Documentation/cdrom/cm206>.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called cm206.
-
-config SJCD
-       tristate "Sanyo CDR-H94A CDROM support"
-       depends on CD_NO_IDESCSI
-       help
-         If this is your CD-ROM drive, say Y here and read the file
-         <file:Documentation/cdrom/sjcd>. You should then also say Y or M to
-         "ISO 9660 CD-ROM file system support" below, because that's the
-         file system used on CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called sjcd.
-
-config ISP16_CDI
-       tristate "ISP16/MAD16/Mozart soft configurable cdrom interface support"
-       depends on CD_NO_IDESCSI
-       ---help---
-         These are sound cards with built-in cdrom interfaces using the OPTi
-         82C928 or 82C929 chips. Say Y here to have them detected and
-         possibly configured at boot time. In addition, You'll have to say Y
-         to a driver for the particular cdrom drive you have attached to the
-         card. Read <file:Documentation/cdrom/isp16> for details.
-
-         To compile this driver as a module, choose M here: the
-         module will be called isp16.
-
-config CDU31A
-       tristate "Sony CDU31A/CDU33A CDROM support"
-       depends on CD_NO_IDESCSI && BROKEN_ON_SMP
-       ---help---
-         These CD-ROM drives have a spring-pop-out caddyless drawer, and a
-         rectangular green LED centered beneath it.  NOTE: these CD-ROM
-         drives will not be auto detected by the kernel at boot time; you
-         have to provide the interface address as an option to the kernel at
-         boot time as described in <file:Documentation/cdrom/cdu31a> or fill
-         in your parameters into <file:drivers/cdrom/cdu31a.c>.  Try "man
-         bootparam" or see the documentation of your boot loader (lilo or
-         loadlin) about how to pass options to the kernel.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called cdu31a.
-
-config CDU535
-       tristate "Sony CDU535 CDROM support"
-       depends on CD_NO_IDESCSI
-       ---help---
-         This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM
-         drives. Please read the file <file:Documentation/cdrom/sonycd535>.
-
-         If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-         file system support" below, because that's the file system used on
-         CD-ROMs.
-
-         To compile this driver as a module, choose M here: the
-         module will be called sonycd535.
-
-endmenu
index d1d1e5a4be73b846dc9df2a5efde9fcf1928405c..774c180a4e11c66fedb272218d591b859a219ee0 100644 (file)
@@ -10,14 +10,4 @@ obj-$(CONFIG_BLK_DEV_SR)     +=              cdrom.o
 obj-$(CONFIG_PARIDE_PCD)       +=              cdrom.o
 obj-$(CONFIG_CDROM_PKTCDVD)    +=              cdrom.o
 
-obj-$(CONFIG_AZTCD)            += aztcd.o
-obj-$(CONFIG_CDU31A)           += cdu31a.o     cdrom.o
-obj-$(CONFIG_CM206)            += cm206.o      cdrom.o
-obj-$(CONFIG_GSCD)             += gscd.o
-obj-$(CONFIG_ISP16_CDI)                += isp16.o
-obj-$(CONFIG_MCDX)             += mcdx.o       cdrom.o
-obj-$(CONFIG_OPTCD)            += optcd.o
-obj-$(CONFIG_SBPCD)            += sbpcd.o      cdrom.o
-obj-$(CONFIG_SJCD)             += sjcd.o
-obj-$(CONFIG_CDU535)           += sonycd535.o
 obj-$(CONFIG_VIOCD)            += viocd.o      cdrom.o
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
deleted file mode 100644 (file)
index 1f9fb7a..0000000
+++ /dev/null
@@ -1,2492 +0,0 @@
-#define AZT_VERSION "2.60"
-
-/*      $Id: aztcd.c,v 2.60 1997/11/29 09:51:19 root Exp root $
-       linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver
-
-       Copyright (C) 1994-98 Werner Zimmermann(Werner.Zimmermann@fht-esslingen.de)
-
-       based on Mitsumi CDROM driver by  Martin Hariss and preworks by
-       Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby 
-       Schirmer.
-
-       This program is free software; you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation; either version 2, or (at your option)
-       any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU General Public License for more details.
-
-       You should have received a copy of the GNU General Public License
-       along with this program; if not, write to the Free Software
-       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-       HISTORY
-       V0.0    Adaption to Aztech CD268-01A Version 1.3
-               Version is PRE_ALPHA, unresolved points:
-               1. I use busy wait instead of timer wait in STEN_LOW,DTEN_LOW
-                  thus driver causes CPU overhead and is very slow 
-               2. could not find a way to stop the drive, when it is
-                  in data read mode, therefore I had to set
-                  msf.end.min/sec/frame to 0:0:1 (in azt_poll); so only one
-                  frame can be read in sequence, this is also the reason for
-               3. getting 'timeout in state 4' messages, but nevertheless
-                  it works
-               W.Zimmermann, Oct. 31, 1994
-       V0.1    Version is ALPHA, problems #2 and #3 resolved.  
-               W.Zimmermann, Nov. 3, 1994
-       V0.2    Modification to some comments, debugging aids for partial test
-               with Borland C under DOS eliminated. Timer interrupt wait 
-               STEN_LOW_WAIT additionally to busy wait for STEN_LOW implemented; 
-               use it only for the 'slow' commands (ACMD_GET_Q_CHANNEL, ACMD_
-               SEEK_TO_LEAD_IN), all other commands are so 'fast', that busy 
-               waiting seems better to me than interrupt rescheduling.
-               Besides that, when used in the wrong place, STEN_LOW_WAIT causes
-               kernel panic.
-               In function aztPlay command ACMD_PLAY_AUDIO added, should make
-               audio functions work. The Aztech drive needs different commands
-               to read data tracks and play audio tracks.
-               W.Zimmermann, Nov. 8, 1994
-       V0.3    Recognition of missing drive during boot up improved (speeded up).
-               W.Zimmermann, Nov. 13, 1994
-       V0.35   Rewrote the control mechanism in azt_poll (formerly mcd_poll) 
-               including removal of all 'goto' commands. :-); 
-               J. Nardone, Nov. 14, 1994
-       V0.4    Renamed variables and constants to 'azt' instead of 'mcd'; had
-               to make some "compatibility" defines in azt.h; please note,
-               that the source file was renamed to azt.c, the include file to
-               azt.h                
-               Speeded up drive recognition during init (will be a little bit 
-               slower than before if no drive is installed!); suggested by
-               Robby Schirmer.
-               read_count declared volatile and set to AZT_BUF_SIZ to make
-               drive faster (now 300kB/sec, was 60kB/sec before, measured
-               by 'time dd if=/dev/cdrom of=/dev/null bs=2048 count=4096';
-               different AZT_BUF_SIZes were test, above 16 no further im-
-               provement seems to be possible; suggested by E.Moenkeberg.
-               W.Zimmermann, Nov. 18, 1994
-       V0.42   Included getAztStatus command in GetQChannelInfo() to allow
-               reading Q-channel info on audio disks, if drive is stopped, 
-               and some other bug fixes in the audio stuff, suggested by 
-               Robby Schirmer.
-               Added more ioctls (reading data in mode 1 and mode 2).
-               Completely removed the old azt_poll() routine.
-               Detection of ORCHID CDS-3110 in aztcd_init implemented.
-               Additional debugging aids (see the readme file).
-               W.Zimmermann, Dec. 9, 1994  
-       V0.50   Autodetection of drives implemented.
-               W.Zimmermann, Dec. 12, 1994
-       V0.52   Prepared for including in the standard kernel, renamed most
-               variables to contain 'azt', included autoconf.h
-               W.Zimmermann, Dec. 16, 1994        
-       V0.6    Version for being included in the standard Linux kernel.
-               Renamed source and header file to aztcd.c and aztcd.h
-               W.Zimmermann, Dec. 24, 1994
-       V0.7    Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case
-               CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl,
-               which causes kernel crashes when playing audio, changed 
-               include-files (config.h instead of autoconf.h, removed
-               delay.h)
-               W.Zimmermann, Jan. 8, 1995
-       V0.72   Some more modifications for adaption to the standard kernel.
-               W.Zimmermann, Jan. 16, 1995
-        V0.80   aztcd is now part of the standard kernel since version 1.1.83.
-                Modified the SET_TIMER and CLEAR_TIMER macros to comply with
-                the new timer scheme.
-                W.Zimmermann, Jan. 21, 1995
-        V0.90   Included CDROMVOLCTRL, but with my Aztech drive I can only turn
-                the channels on and off. If it works better with your drive, 
-                please mail me. Also implemented ACMD_CLOSE for CDROMSTART.
-                W.Zimmermann, Jan. 24, 1995
-        V1.00   Implemented close and lock tray commands. Patches supplied by
-               Frank Racis        
-                Added support for loadable MODULEs, so aztcd can now also be
-                loaded by insmod and removed by rmmod during run time
-                Werner Zimmermann, Mar. 24, 95
-        V1.10   Implemented soundcard configuration for Orchid CDS-3110 drives
-                connected to Soundwave32 cards. Release for LST 2.1.
-                (still experimental)
-                Werner Zimmermann, May 8, 95
-        V1.20   Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but
-                sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver-
-                sion needs an update of Dosemu0.60's cdrom.c, which will come with the 
-                next revision of Dosemu.
-                Also Soundwave32 support now works.
-                Werner Zimmermann, May 22, 95
-       V1.30   Auto-eject feature. Inspired by Franc Racis (racis@psu.edu)
-               Werner Zimmermann, July 4, 95
-       V1.40   Started multisession support. Implementation copied from mcdx.c
-               by Heiko Schlittermann. Not tested yet.
-               Werner Zimmermann, July 15, 95
-        V1.50   Implementation of ioctl CDROMRESET, continued multisession, began
-                XA, but still untested. Heavy modifications to drive status de-
-                tection.
-                Werner Zimmermann, July 25, 95
-        V1.60   XA support now should work. Speeded up drive recognition in cases, 
-                where no drive is installed.
-                Werner Zimmermann, August 8, 1995
-        V1.70   Multisession support now is completed, but there is still not 
-                enough testing done. If you can test it, please contact me. For
-                details please read Documentation/cdrom/aztcd
-                Werner Zimmermann, August 19, 1995
-        V1.80   Modification to suit the new kernel boot procedure introduced
-                with kernel 1.3.33. Will definitely not work with older kernels.
-                Programming done by Linus himself.
-                Werner Zimmermann, October 11, 1995
-       V1.90   Support for Conrad TXC drives, thank's to Jochen Kunz and Olaf Kaluza.
-               Werner Zimmermann, October 21, 1995
-        V2.00   Changed #include "blk.h" to <linux/blk.h> as the directory
-                structure was changed. README.aztcd is now /usr/src/docu-
-                mentation/cdrom/aztcd
-                Werner Zimmermann, November 10, 95
-        V2.10   Started to modify azt_poll to prevent reading beyond end of
-                tracks.
-                Werner Zimmermann, December 3, 95
-        V2.20   Changed some comments
-                Werner Zimmermann, April 1, 96
-        V2.30   Implemented support for CyCDROM CR520, CR940, Code for CR520 
-               delivered by H.Berger with preworks by E.Moenkeberg.
-                Werner Zimmermann, April 29, 96
-        V2.40   Reorganized the placement of functions in the source code file
-                to reflect the layered approach; did not actually change code
-                Werner Zimmermann, May 1, 96
-        V2.50   Heiko Eissfeldt suggested to remove some VERIFY_READs in 
-                aztcd_ioctl; check_aztcd_media_change modified 
-                Werner Zimmermann, May 16, 96       
-       V2.60   Implemented Auto-Probing; made changes for kernel's 2.1.xx blocksize
-                Adaption to linux kernel > 2.1.0
-               Werner Zimmermann, Nov 29, 97
-               
-        November 1999 -- Make kernel-parameter implementation work with 2.3.x 
-                        Removed init_module & cleanup_module in favor of 
-                        module_init & module_exit.
-                        Torben Mathiasen <tmm@image.dk>
-*/
-
-#include <linux/blkdev.h>
-#include "aztcd.h"
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/major.h>
-
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include <asm/uaccess.h>
-
-/*###########################################################################
-  Defines
-  ###########################################################################
-*/
-
-#define MAJOR_NR AZTECH_CDROM_MAJOR
-#define QUEUE (azt_queue)
-#define CURRENT elv_next_request(azt_queue)
-#define SET_TIMER(func, jifs)   delay_timer.expires = jiffies + (jifs); \
-                                delay_timer.function = (void *) (func); \
-                                add_timer(&delay_timer);
-
-#define CLEAR_TIMER             del_timer(&delay_timer);
-
-#define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\
-                                return value;}
-#define RETURN(message)        {printk("aztcd: Warning: %s failed\n",message);\
-                                return;}
-
-/* Macros to switch the IDE-interface to the slave device and back to the master*/
-#define SWITCH_IDE_SLAVE  outb_p(0xa0,azt_port+6); \
-                         outb_p(0x10,azt_port+6); \
-                         outb_p(0x00,azt_port+7); \
-                         outb_p(0x10,azt_port+6);
-#define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6);
-
-
-#if 0
-#define AZT_TEST
-#define AZT_TEST1              /* <int-..> */
-#define AZT_TEST2              /* do_aztcd_request */
-#define AZT_TEST3              /* AZT_S_state */
-#define AZT_TEST4              /* QUICK_LOOP-counter */
-#define AZT_TEST5              /* port(1) state */
-#define AZT_DEBUG
-#define AZT_DEBUG_MULTISESSION
-#endif
-
-static struct request_queue *azt_queue;
-
-static int current_valid(void)
-{
-        return CURRENT &&
-               CURRENT->cmd == READ &&
-               CURRENT->sector != -1;
-}
-
-#define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
-#define AZT_BUF_SIZ 16
-
-#define READ_TIMEOUT 3000
-
-#define azt_port aztcd         /*needed for the modutils */
-
-/*##########################################################################
-  Type Definitions
-  ##########################################################################
-*/
-enum azt_state_e { AZT_S_IDLE, /* 0 */
-       AZT_S_START,            /* 1 */
-       AZT_S_MODE,             /* 2 */
-       AZT_S_READ,             /* 3 */
-       AZT_S_DATA,             /* 4 */
-       AZT_S_STOP,             /* 5 */
-       AZT_S_STOPPING          /* 6 */
-};
-enum azt_read_modes { AZT_MODE_0,      /*read mode for audio disks, not supported by Aztech firmware */
-       AZT_MODE_1,             /*read mode for normal CD-ROMs */
-       AZT_MODE_2              /*read mode for XA CD-ROMs */
-};
-
-/*##########################################################################
-  Global Variables
-  ##########################################################################
-*/
-static int aztPresent = 0;
-
-static volatile int azt_transfer_is_active = 0;
-
-static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ];   /*buffer for block size conversion */
-#if AZT_PRIVATE_IOCTLS
-static char buf[CD_FRAMESIZE_RAW];     /*separate buffer for the ioctls */
-#endif
-
-static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
-static volatile int azt_buf_in, azt_buf_out = -1;
-static volatile int azt_error = 0;
-static int azt_open_count = 0;
-static volatile enum azt_state_e azt_state = AZT_S_IDLE;
-#ifdef AZT_TEST3
-static volatile enum azt_state_e azt_state_old = AZT_S_STOP;
-static volatile int azt_st_old = 0;
-#endif
-static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
-
-static int azt_mode = -1;
-static volatile int azt_read_count = 1;
-
-static int azt_port = AZT_BASE_ADDR;
-
-module_param(azt_port, int, 0);
-
-static int azt_port_auto[16] = AZT_BASE_AUTO;
-
-static char azt_cont = 0;
-static char azt_init_end = 0;
-static char azt_auto_eject = AZT_AUTO_EJECT;
-
-static int AztTimeout, AztTries;
-static DECLARE_WAIT_QUEUE_HEAD(azt_waitq);
-static DEFINE_TIMER(delay_timer, NULL, 0, 0);
-
-static struct azt_DiskInfo DiskInfo;
-static struct azt_Toc Toc[MAX_TRACKS];
-static struct azt_Play_msf azt_Play;
-
-static int aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-static char aztDiskChanged = 1;
-static char aztTocUpToDate = 0;
-
-static unsigned char aztIndatum;
-static unsigned long aztTimeOutCount;
-static int aztCmd = 0;
-
-static DEFINE_SPINLOCK(aztSpin);
-
-/*###########################################################################
-   Function Prototypes
-  ###########################################################################
-*/
-/* CDROM Drive Low Level I/O Functions */
-static void aztStatTimer(void);
-
-/* CDROM Drive Command Functions */
-static int aztGetDiskInfo(void);
-#if AZT_MULTISESSION
-static int aztGetMultiDiskInfo(void);
-#endif
-static int aztGetToc(int multi);
-
-/* Kernel Interface Functions */
-static int check_aztcd_media_change(struct gendisk *disk);
-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
-                      unsigned long arg);
-static int aztcd_open(struct inode *ip, struct file *fp);
-static int aztcd_release(struct inode *inode, struct file *file);
-
-static struct block_device_operations azt_fops = {
-       .owner          = THIS_MODULE,
-       .open           = aztcd_open,
-       .release        = aztcd_release,
-       .ioctl          = aztcd_ioctl,
-       .media_changed  = check_aztcd_media_change,
-};
-
-/* Aztcd State Machine: Controls Drive Operating State */
-static void azt_poll(void);
-
-/* Miscellaneous support functions */
-static void azt_hsg2msf(long hsg, struct msf *msf);
-static long azt_msf2hsg(struct msf *mp);
-static void azt_bin2bcd(unsigned char *p);
-static int azt_bcd2bin(unsigned char bcd);
-
-/*##########################################################################
-  CDROM Drive Low Level I/O Functions
-  ##########################################################################
-*/
-/* Macros for the drive hardware interface handshake, these macros use
-   busy waiting */
-/* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
-# define OP_OK op_ok()
-static void op_ok(void)
-{
-       aztTimeOutCount = 0;
-       do {
-               aztIndatum = inb(DATA_PORT);
-               aztTimeOutCount++;
-               if (aztTimeOutCount >= AZT_TIMEOUT) {
-                       printk("aztcd: Error Wait OP_OK\n");
-                       break;
-               }
-       } while (aztIndatum != AFL_OP_OK);
-}
-
-/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/
-#if 0
-# define PA_OK pa_ok()
-static void pa_ok(void)
-{
-       aztTimeOutCount = 0;
-       do {
-               aztIndatum = inb(DATA_PORT);
-               aztTimeOutCount++;
-               if (aztTimeOutCount >= AZT_TIMEOUT) {
-                       printk("aztcd: Error Wait PA_OK\n");
-                       break;
-               }
-       } while (aztIndatum != AFL_PA_OK);
-}
-#endif
-
-/* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/
-# define STEN_LOW  sten_low()
-static void sten_low(void)
-{
-       aztTimeOutCount = 0;
-       do {
-               aztIndatum = inb(STATUS_PORT);
-               aztTimeOutCount++;
-               if (aztTimeOutCount >= AZT_TIMEOUT) {
-                       if (azt_init_end)
-                               printk
-                                   ("aztcd: Error Wait STEN_LOW commands:%x\n",
-                                    aztCmd);
-                       break;
-               }
-       } while (aztIndatum & AFL_STATUS);
-}
-
-/* Wait for DTEN=Low = handshake signal 'Data available'*/
-# define DTEN_LOW dten_low()
-static void dten_low(void)
-{
-       aztTimeOutCount = 0;
-       do {
-               aztIndatum = inb(STATUS_PORT);
-               aztTimeOutCount++;
-               if (aztTimeOutCount >= AZT_TIMEOUT) {
-                       printk("aztcd: Error Wait DTEN_OK\n");
-                       break;
-               }
-       } while (aztIndatum & AFL_DATA);
-}
-
-/* 
- * Macro for timer wait on STEN=Low, should only be used for 'slow' commands;
- * may cause kernel panic when used in the wrong place
-*/
-#define STEN_LOW_WAIT   statusAzt()
-static void statusAzt(void)
-{
-       AztTimeout = AZT_STATUS_DELAY;
-       SET_TIMER(aztStatTimer, HZ / 100);
-       sleep_on(&azt_waitq);
-       if (AztTimeout <= 0)
-               printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",
-                      aztCmd);
-       return;
-}
-
-static void aztStatTimer(void)
-{
-       if (!(inb(STATUS_PORT) & AFL_STATUS)) {
-               wake_up(&azt_waitq);
-               return;
-       }
-       AztTimeout--;
-       if (AztTimeout <= 0) {
-               wake_up(&azt_waitq);
-               printk("aztcd: Error aztStatTimer: Timeout\n");
-               return;
-       }
-       SET_TIMER(aztStatTimer, HZ / 100);
-}
-
-/*##########################################################################
-  CDROM Drive Command Functions
-  ##########################################################################
-*/
-/* 
- * Send a single command, return -1 on error, else 0
-*/
-static int aztSendCmd(int cmd)
-{
-       unsigned char data;
-       int retry;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: Executing command %x\n", cmd);
-#endif
-
-       if ((azt_port == 0x1f0) || (azt_port == 0x170))
-               SWITCH_IDE_SLAVE;       /*switch IDE interface to slave configuration */
-
-       aztCmd = cmd;
-       outb(POLLED, MODE_PORT);
-       do {
-               if (inb(STATUS_PORT) & AFL_STATUS)
-                       break;
-               inb(DATA_PORT); /* if status left from last command, read and */
-       } while (1);            /* discard it */
-       do {
-               if (inb(STATUS_PORT) & AFL_DATA)
-                       break;
-               inb(DATA_PORT); /* if data left from last command, read and */
-       } while (1);            /* discard it */
-       for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
-               outb((unsigned char) cmd, CMD_PORT);
-               STEN_LOW;
-               data = inb(DATA_PORT);
-               if (data == AFL_OP_OK) {
-                       return 0;
-               }               /*OP_OK? */
-               if (data == AFL_OP_ERR) {
-                       STEN_LOW;
-                       data = inb(DATA_PORT);
-                       printk
-                           ("### Error 1 aztcd: aztSendCmd %x  Error Code %x\n",
-                            cmd, data);
-               }
-       }
-       if (retry >= AZT_RETRY_ATTEMPTS) {
-               printk("### Error 2 aztcd: aztSendCmd %x \n", cmd);
-               azt_error = 0xA5;
-       }
-       RETURNM("aztSendCmd", -1);
-}
-
-/*
- * Send a play or read command to the drive, return -1 on error, else 0
-*/
-static int sendAztCmd(int cmd, struct azt_Play_msf *params)
-{
-       unsigned char data;
-       int retry;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: play start=%02x:%02x:%02x  end=%02x:%02x:%02x\n",
-              params->start.min, params->start.sec, params->start.frame,
-              params->end.min, params->end.sec, params->end.frame);
-#endif
-       for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
-               aztSendCmd(cmd);
-               outb(params->start.min, CMD_PORT);
-               outb(params->start.sec, CMD_PORT);
-               outb(params->start.frame, CMD_PORT);
-               outb(params->end.min, CMD_PORT);
-               outb(params->end.sec, CMD_PORT);
-               outb(params->end.frame, CMD_PORT);
-               STEN_LOW;
-               data = inb(DATA_PORT);
-               if (data == AFL_PA_OK) {
-                       return 0;
-               }               /*PA_OK ? */
-               if (data == AFL_PA_ERR) {
-                       STEN_LOW;
-                       data = inb(DATA_PORT);
-                       printk
-                           ("### Error 1 aztcd: sendAztCmd %x  Error Code %x\n",
-                            cmd, data);
-               }
-       }
-       if (retry >= AZT_RETRY_ATTEMPTS) {
-               printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd);
-               azt_error = 0xA5;
-       }
-       RETURNM("sendAztCmd", -1);
-}
-
-/*
- * Send a seek command to the drive, return -1 on error, else 0
-*/
-static int aztSeek(struct azt_Play_msf *params)
-{
-       unsigned char data;
-       int retry;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: aztSeek %02x:%02x:%02x\n",
-              params->start.min, params->start.sec, params->start.frame);
-#endif
-       for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
-               aztSendCmd(ACMD_SEEK);
-               outb(params->start.min, CMD_PORT);
-               outb(params->start.sec, CMD_PORT);
-               outb(params->start.frame, CMD_PORT);
-               STEN_LOW;
-               data = inb(DATA_PORT);
-               if (data == AFL_PA_OK) {
-                       return 0;
-               }               /*PA_OK ? */
-               if (data == AFL_PA_ERR) {
-                       STEN_LOW;
-                       data = inb(DATA_PORT);
-                       printk("### Error 1 aztcd: aztSeek\n");
-               }
-       }
-       if (retry >= AZT_RETRY_ATTEMPTS) {
-               printk("### Error 2 aztcd: aztSeek\n ");
-               azt_error = 0xA5;
-       }
-       RETURNM("aztSeek", -1);
-}
-
-/* Send a Set Disk Type command
-   does not seem to work with Aztech drives, behavior is completely indepen-
-   dent on which mode is set ???
-*/
-static int aztSetDiskType(int type)
-{
-       unsigned char data;
-       int retry;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: set disk type command: type= %i\n", type);
-#endif
-       for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
-               aztSendCmd(ACMD_SET_DISK_TYPE);
-               outb(type, CMD_PORT);
-               STEN_LOW;
-               data = inb(DATA_PORT);
-               if (data == AFL_PA_OK) {        /*PA_OK ? */
-                       azt_read_mode = type;
-                       return 0;
-               }
-               if (data == AFL_PA_ERR) {
-                       STEN_LOW;
-                       data = inb(DATA_PORT);
-                       printk
-                           ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",
-                            type, data);
-               }
-       }
-       if (retry >= AZT_RETRY_ATTEMPTS) {
-               printk("### Error 2 aztcd: aztSetDiskType %x\n ", type);
-               azt_error = 0xA5;
-       }
-       RETURNM("aztSetDiskType", -1);
-}
-
-
-/* used in azt_poll to poll the status, expects another program to issue a 
- * ACMD_GET_STATUS directly before 
- */
-static int aztStatus(void)
-{
-       int st;
-/*     int i;
-
-       i = inb(STATUS_PORT) & AFL_STATUS;    is STEN=0?    ???
-       if (!i)
-*/ STEN_LOW;
-       if (aztTimeOutCount < AZT_TIMEOUT) {
-               st = inb(DATA_PORT) & 0xFF;
-               return st;
-       } else
-               RETURNM("aztStatus", -1);
-}
-
-/*
- * Get the drive status
- */
-static int getAztStatus(void)
-{
-       int st;
-
-       if (aztSendCmd(ACMD_GET_STATUS))
-               RETURNM("getAztStatus 1", -1);
-       STEN_LOW;
-       st = inb(DATA_PORT) & 0xFF;
-#ifdef AZT_DEBUG
-       printk("aztcd: Status = %x\n", st);
-#endif
-       if ((st == 0xFF) || (st & AST_CMD_CHECK)) {
-               printk
-                   ("aztcd: AST_CMD_CHECK error or no status available\n");
-               return -1;
-       }
-
-       if (((st & AST_MODE_BITS) != AST_BUSY)
-           && (aztAudioStatus == CDROM_AUDIO_PLAY))
-               /* XXX might be an error? look at q-channel? */
-               aztAudioStatus = CDROM_AUDIO_COMPLETED;
-
-       if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) {
-               aztDiskChanged = 1;
-               aztTocUpToDate = 0;
-               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-       }
-       return st;
-}
-
-
-/*
- * Send a 'Play' command and get the status.  Use only from the top half.
- */
-static int aztPlay(struct azt_Play_msf *arg)
-{
-       if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0)
-               RETURNM("aztPlay", -1);
-       return 0;
-}
-
-/*
- * Subroutines to automatically close the door (tray) and 
- * lock it closed when the cd is mounted.  Leave the tray
- * locking as an option
- */
-static void aztCloseDoor(void)
-{
-       aztSendCmd(ACMD_CLOSE);
-       STEN_LOW;
-       return;
-}
-
-static void aztLockDoor(void)
-{
-#if AZT_ALLOW_TRAY_LOCK
-       aztSendCmd(ACMD_LOCK);
-       STEN_LOW;
-#endif
-       return;
-}
-
-static void aztUnlockDoor(void)
-{
-#if AZT_ALLOW_TRAY_LOCK
-       aztSendCmd(ACMD_UNLOCK);
-       STEN_LOW;
-#endif
-       return;
-}
-
-/*
- * Read a value from the drive.  Should return quickly, so a busy wait
- * is used to avoid excessive rescheduling. The read command itself must
- * be issued with aztSendCmd() directly before
- */
-static int aztGetValue(unsigned char *result)
-{
-       int s;
-
-       STEN_LOW;
-       if (aztTimeOutCount >= AZT_TIMEOUT) {
-               printk("aztcd: aztGetValue timeout\n");
-               return -1;
-       }
-       s = inb(DATA_PORT) & 0xFF;
-       *result = (unsigned char) s;
-       return 0;
-}
-
-/*
- * Read the current Q-channel info.  Also used for reading the
- * table of contents.
- */
-static int aztGetQChannelInfo(struct azt_Toc *qp)
-{
-       unsigned char notUsed;
-       int st;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztGetQChannelInfo  Time:%li\n", jiffies);
-#endif
-       if ((st = getAztStatus()) == -1)
-               RETURNM("aztGetQChannelInfo 1", -1);
-       if (aztSendCmd(ACMD_GET_Q_CHANNEL))
-               RETURNM("aztGetQChannelInfo 2", -1);
-       /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */
-       if (aztGetValue(&notUsed))
-               RETURNM("aztGetQChannelInfo 3", -1);    /*??? Nullbyte einlesen */
-       if ((st & AST_MODE_BITS) == AST_INITIAL) {
-               qp->ctrl_addr = 0;      /* when audio stop ACMD_GET_Q_CHANNEL returns */
-               qp->track = 0;  /* only one byte with Aztech drives */
-               qp->pointIndex = 0;
-               qp->trackTime.min = 0;
-               qp->trackTime.sec = 0;
-               qp->trackTime.frame = 0;
-               qp->diskTime.min = 0;
-               qp->diskTime.sec = 0;
-               qp->diskTime.frame = 0;
-               return 0;
-       } else {
-               if (aztGetValue(&qp->ctrl_addr) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->track) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->pointIndex) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->trackTime.min) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->trackTime.sec) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->trackTime.frame) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&notUsed) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->diskTime.min) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->diskTime.sec) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-               if (aztGetValue(&qp->diskTime.frame) < 0)
-                       RETURNM("aztGetQChannelInfo 4", -1);
-       }
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztGetQChannelInfo  Time:%li\n", jiffies);
-#endif
-       return 0;
-}
-
-/*
- * Read the table of contents (TOC) and TOC header if necessary
- */
-static int aztUpdateToc(void)
-{
-       int st;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztUpdateToc  Time:%li\n", jiffies);
-#endif
-       if (aztTocUpToDate)
-               return 0;
-
-       if (aztGetDiskInfo() < 0)
-               return -EIO;
-
-       if (aztGetToc(0) < 0)
-               return -EIO;
-
-       /*audio disk detection
-          with my Aztech drive there is no audio status bit, so I use the copy
-          protection bit of the first track. If this track is copy protected 
-          (copy bit = 0), I assume, it's an audio  disk. Strange, but works ??? */
-       if (!(Toc[DiskInfo.first].ctrl_addr & 0x40))
-               DiskInfo.audio = 1;
-       else
-               DiskInfo.audio = 0;
-
-       /* XA detection */
-       if (!DiskInfo.audio) {
-               azt_Play.start.min = 0; /*XA detection only seems to work */
-               azt_Play.start.sec = 2; /*when we play a track */
-               azt_Play.start.frame = 0;
-               azt_Play.end.min = 0;
-               azt_Play.end.sec = 0;
-               azt_Play.end.frame = 1;
-               if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
-                       return -1;
-               DTEN_LOW;
-               for (st = 0; st < CD_FRAMESIZE; st++)
-                       inb(DATA_PORT);
-       }
-       DiskInfo.xa = getAztStatus() & AST_MODE;
-       if (DiskInfo.xa) {
-               printk
-                   ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n");
-       }
-
-       /*multisession detection
-          support for multisession CDs is done automatically with Aztech drives,
-          we don't have to take care about TOC redirection; if we want the isofs
-          to take care about redirection, we have to set AZT_MULTISESSION to 1 */
-       DiskInfo.multi = 0;
-#if AZT_MULTISESSION
-       if (DiskInfo.xa) {
-               aztGetMultiDiskInfo();  /*here Disk.Info.multi is set */
-       }
-#endif
-       if (DiskInfo.multi) {
-               DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min;
-               DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec;
-               DiskInfo.lastSession.frame =
-                   Toc[DiskInfo.next].diskTime.frame;
-               printk("aztcd: Multisession support experimental\n");
-       } else {
-               DiskInfo.lastSession.min =
-                   Toc[DiskInfo.first].diskTime.min;
-               DiskInfo.lastSession.sec =
-                   Toc[DiskInfo.first].diskTime.sec;
-               DiskInfo.lastSession.frame =
-                   Toc[DiskInfo.first].diskTime.frame;
-       }
-
-       aztTocUpToDate = 1;
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztUpdateToc  Time:%li\n", jiffies);
-#endif
-       return 0;
-}
-
-
-/* Read the table of contents header, i.e. no. of tracks and start of first 
- * track
- */
-static int aztGetDiskInfo(void)
-{
-       int limit;
-       unsigned char test;
-       struct azt_Toc qInfo;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztGetDiskInfo  Time:%li\n", jiffies);
-#endif
-       if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
-               RETURNM("aztGetDiskInfo 1", -1);
-       STEN_LOW_WAIT;
-       test = 0;
-       for (limit = 300; limit > 0; limit--) {
-               if (aztGetQChannelInfo(&qInfo) < 0)
-                       RETURNM("aztGetDiskInfo 2", -1);
-               if (qInfo.pointIndex == 0xA0) { /*Number of FirstTrack */
-                       DiskInfo.first = qInfo.diskTime.min;
-                       DiskInfo.first = azt_bcd2bin(DiskInfo.first);
-                       test = test | 0x01;
-               }
-               if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */
-                       DiskInfo.last = qInfo.diskTime.min;
-                       DiskInfo.last = azt_bcd2bin(DiskInfo.last);
-                       test = test | 0x02;
-               }
-               if (qInfo.pointIndex == 0xA2) { /*DiskLength */
-                       DiskInfo.diskLength.min = qInfo.diskTime.min;
-                       DiskInfo.diskLength.sec = qInfo.diskTime.sec;
-                       DiskInfo.diskLength.frame = qInfo.diskTime.frame;
-                       test = test | 0x04;
-               }
-               if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) {    /*StartTime of First Track */
-                       DiskInfo.firstTrack.min = qInfo.diskTime.min;
-                       DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
-                       DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
-                       test = test | 0x08;
-               }
-               if (test == 0x0F)
-                       break;
-       }
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztGetDiskInfo  Time:%li\n", jiffies);
-       printk
-           ("Disk Info: first %d last %d length %02X:%02X.%02X dez  first %02X:%02X.%02X dez\n",
-            DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
-            DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
-            DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
-            DiskInfo.firstTrack.frame);
-#endif
-       if (test != 0x0F)
-               return -1;
-       return 0;
-}
-
-#if AZT_MULTISESSION
-/*
- * Get Multisession Disk Info
- */
-static int aztGetMultiDiskInfo(void)
-{
-       int limit, k = 5;
-       unsigned char test;
-       struct azt_Toc qInfo;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztGetMultiDiskInfo\n");
-#endif
-
-       do {
-               azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min;
-               azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec;
-               azt_Play.start.frame =
-                   Toc[DiskInfo.last + 1].diskTime.frame;
-               test = 0;
-
-               for (limit = 30; limit > 0; limit--) {  /*Seek for LeadIn of next session */
-                       if (aztSeek(&azt_Play))
-                               RETURNM("aztGetMultiDiskInfo 1", -1);
-                       if (aztGetQChannelInfo(&qInfo) < 0)
-                               RETURNM("aztGetMultiDiskInfo 2", -1);
-                       if ((qInfo.track == 0) && (qInfo.pointIndex))
-                               break;  /*LeadIn found */
-                       if ((azt_Play.start.sec += 10) > 59) {
-                               azt_Play.start.sec = 0;
-                               azt_Play.start.min++;
-                       }
-               }
-               if (!limit)
-                       break;  /*Check, if a leadin track was found, if not we're
-                                  at the end of the disk */
-#ifdef AZT_DEBUG_MULTISESSION
-               printk("leadin found track %d  pointIndex %x  limit %d\n",
-                      qInfo.track, qInfo.pointIndex, limit);
-#endif
-               for (limit = 300; limit > 0; limit--) {
-                       if (++azt_Play.start.frame > 74) {
-                               azt_Play.start.frame = 0;
-                               if (azt_Play.start.sec > 59) {
-                                       azt_Play.start.sec = 0;
-                                       azt_Play.start.min++;
-                               }
-                       }
-                       if (aztSeek(&azt_Play))
-                               RETURNM("aztGetMultiDiskInfo 3", -1);
-                       if (aztGetQChannelInfo(&qInfo) < 0)
-                               RETURNM("aztGetMultiDiskInfo 4", -1);
-                       if (qInfo.pointIndex == 0xA0) { /*Number of NextTrack */
-                               DiskInfo.next = qInfo.diskTime.min;
-                               DiskInfo.next = azt_bcd2bin(DiskInfo.next);
-                               test = test | 0x01;
-                       }
-                       if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */
-                               DiskInfo.last = qInfo.diskTime.min;
-                               DiskInfo.last = azt_bcd2bin(DiskInfo.last);
-                               test = test | 0x02;
-                       }
-                       if (qInfo.pointIndex == 0xA2) { /*DiskLength */
-                               DiskInfo.diskLength.min =
-                                   qInfo.diskTime.min;
-                               DiskInfo.diskLength.sec =
-                                   qInfo.diskTime.sec;
-                               DiskInfo.diskLength.frame =
-                                   qInfo.diskTime.frame;
-                               test = test | 0x04;
-                       }
-                       if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) {     /*StartTime of Next Track */
-                               DiskInfo.nextSession.min =
-                                   qInfo.diskTime.min;
-                               DiskInfo.nextSession.sec =
-                                   qInfo.diskTime.sec;
-                               DiskInfo.nextSession.frame =
-                                   qInfo.diskTime.frame;
-                               test = test | 0x08;
-                       }
-                       if (test == 0x0F)
-                               break;
-               }
-#ifdef AZT_DEBUG_MULTISESSION
-               printk
-                   ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez  first %02x:%02x.%02x dez  next %02x:%02x.%02x dez\n",
-                    DiskInfo.first, DiskInfo.next, DiskInfo.last,
-                    DiskInfo.diskLength.min, DiskInfo.diskLength.sec,
-                    DiskInfo.diskLength.frame, DiskInfo.firstTrack.min,
-                    DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame,
-                    DiskInfo.nextSession.min, DiskInfo.nextSession.sec,
-                    DiskInfo.nextSession.frame);
-#endif
-               if (test != 0x0F)
-                       break;
-               else
-                       DiskInfo.multi = 1;     /*found TOC of more than one session */
-               aztGetToc(1);
-       } while (--k);
-
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztGetMultiDiskInfo  Time:%li\n", jiffies);
-#endif
-       return 0;
-}
-#endif
-
-/*
- * Read the table of contents (TOC)
- */
-static int aztGetToc(int multi)
-{
-       int i, px;
-       int limit;
-       struct azt_Toc qInfo;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztGetToc  Time:%li\n", jiffies);
-#endif
-       if (!multi) {
-               for (i = 0; i < MAX_TRACKS; i++)
-                       Toc[i].pointIndex = 0;
-               i = DiskInfo.last + 3;
-       } else {
-               for (i = DiskInfo.next; i < MAX_TRACKS; i++)
-                       Toc[i].pointIndex = 0;
-               i = DiskInfo.last + 4 - DiskInfo.next;
-       }
-
-/*Is there a good reason to stop motor before TOC read?
-  if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
-      STEN_LOW_WAIT;
-*/
-
-       if (!multi) {
-               azt_mode = 0x05;
-               if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
-                       RETURNM("aztGetToc 2", -1);
-               STEN_LOW_WAIT;
-       }
-       for (limit = 300; limit > 0; limit--) {
-               if (multi) {
-                       if (++azt_Play.start.sec > 59) {
-                               azt_Play.start.sec = 0;
-                               azt_Play.start.min++;
-                       }
-                       if (aztSeek(&azt_Play))
-                               RETURNM("aztGetToc 3", -1);
-               }
-               if (aztGetQChannelInfo(&qInfo) < 0)
-                       break;
-
-               px = azt_bcd2bin(qInfo.pointIndex);
-
-               if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
-                       if (Toc[px].pointIndex == 0) {
-                               Toc[px] = qInfo;
-                               i--;
-                       }
-
-               if (i <= 0)
-                       break;
-       }
-
-       Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
-       Toc[DiskInfo.last].trackTime = DiskInfo.diskLength;
-
-#ifdef AZT_DEBUG_MULTISESSION
-       printk("aztcd: exiting aztGetToc\n");
-       for (i = 1; i <= DiskInfo.last + 1; i++)
-               printk
-                   ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
-                    i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
-                    Toc[i].trackTime.min, Toc[i].trackTime.sec,
-                    Toc[i].trackTime.frame, Toc[i].diskTime.min,
-                    Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-       for (i = 100; i < 103; i++)
-               printk
-                   ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
-                    i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
-                    Toc[i].trackTime.min, Toc[i].trackTime.sec,
-                    Toc[i].trackTime.frame, Toc[i].diskTime.min,
-                    Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-#endif
-
-       return limit > 0 ? 0 : -1;
-}
-
-
-/*##########################################################################
-  Kernel Interface Functions
-  ##########################################################################
-*/
-
-#ifndef MODULE
-static int __init aztcd_setup(char *str)
-{
-       int ints[4];
-
-       (void) get_options(str, ARRAY_SIZE(ints), ints);
-
-       if (ints[0] > 0)
-               azt_port = ints[1];
-       if (ints[1] > 1)
-               azt_cont = ints[2];
-       return 1;
-}
-
-__setup("aztcd=", aztcd_setup);
-
-#endif                         /* !MODULE */
-
-/* 
- * Checking if the media has been changed
-*/
-static int check_aztcd_media_change(struct gendisk *disk)
-{
-       if (aztDiskChanged) {   /* disk changed */
-               aztDiskChanged = 0;
-               return 1;
-       } else
-               return 0;       /* no change */
-}
-
-/*
- * Kernel IO-controls
-*/
-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
-                      unsigned long arg)
-{
-       int i;
-       struct azt_Toc qInfo;
-       struct cdrom_ti ti;
-       struct cdrom_tochdr tocHdr;
-       struct cdrom_msf msf;
-       struct cdrom_tocentry entry;
-       struct azt_Toc *tocPtr;
-       struct cdrom_subchnl subchnl;
-       struct cdrom_volctrl volctrl;
-       void __user *argp = (void __user *)arg;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",
-              cmd, jiffies);
-       printk("aztcd Status %x\n", getAztStatus());
-#endif
-       if (!ip)
-               RETURNM("aztcd_ioctl 1", -EINVAL);
-       if (getAztStatus() < 0)
-               RETURNM("aztcd_ioctl 2", -EIO);
-       if ((!aztTocUpToDate) || (aztDiskChanged)) {
-               if ((i = aztUpdateToc()) < 0)
-                       RETURNM("aztcd_ioctl 3", i);    /* error reading TOC */
-       }
-
-       switch (cmd) {
-       case CDROMSTART:        /* Spin up the drive. Don't know, what to do,
-                                  at least close the tray */
-#if AZT_PRIVATE_IOCTLS
-               if (aztSendCmd(ACMD_CLOSE))
-                       RETURNM("aztcd_ioctl 4", -1);
-               STEN_LOW_WAIT;
-#endif
-               break;
-       case CDROMSTOP: /* Spin down the drive */
-               if (aztSendCmd(ACMD_STOP))
-                       RETURNM("aztcd_ioctl 5", -1);
-               STEN_LOW_WAIT;
-               /* should we do anything if it fails? */
-               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-               break;
-       case CDROMPAUSE:        /* Pause the drive */
-               if (aztAudioStatus != CDROM_AUDIO_PLAY)
-                       return -EINVAL;
-
-               if (aztGetQChannelInfo(&qInfo) < 0) {   /* didn't get q channel info */
-                       aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-                       RETURNM("aztcd_ioctl 7", 0);
-               }
-               azt_Play.start = qInfo.diskTime;        /* remember restart point */
-
-               if (aztSendCmd(ACMD_PAUSE))
-                       RETURNM("aztcd_ioctl 8", -1);
-               STEN_LOW_WAIT;
-               aztAudioStatus = CDROM_AUDIO_PAUSED;
-               break;
-       case CDROMRESUME:       /* Play it again, Sam */
-               if (aztAudioStatus != CDROM_AUDIO_PAUSED)
-                       return -EINVAL;
-               /* restart the drive at the saved position. */
-               i = aztPlay(&azt_Play);
-               if (i < 0) {
-                       aztAudioStatus = CDROM_AUDIO_ERROR;
-                       return -EIO;
-               }
-               aztAudioStatus = CDROM_AUDIO_PLAY;
-               break;
-       case CDROMMULTISESSION: /*multisession support -- experimental */
-               {
-                       struct cdrom_multisession ms;
-#ifdef AZT_DEBUG
-                       printk("aztcd ioctl MULTISESSION\n");
-#endif
-                       if (copy_from_user(&ms, argp,
-                            sizeof(struct cdrom_multisession)))
-                               return -EFAULT;
-                       if (ms.addr_format == CDROM_MSF) {
-                               ms.addr.msf.minute =
-                                   azt_bcd2bin(DiskInfo.lastSession.min);
-                               ms.addr.msf.second =
-                                   azt_bcd2bin(DiskInfo.lastSession.sec);
-                               ms.addr.msf.frame =
-                                   azt_bcd2bin(DiskInfo.lastSession.
-                                               frame);
-                       } else if (ms.addr_format == CDROM_LBA)
-                               ms.addr.lba =
-                                   azt_msf2hsg(&DiskInfo.lastSession);
-                       else
-                               return -EINVAL;
-                       ms.xa_flag = DiskInfo.xa;
-                       if (copy_to_user(argp, &ms,
-                            sizeof(struct cdrom_multisession)))
-                               return -EFAULT;
-#ifdef AZT_DEBUG
-                       if (ms.addr_format == CDROM_MSF)
-                               printk
-                                   ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
-                                    ms.xa_flag, ms.addr.msf.minute,
-                                    ms.addr.msf.second, ms.addr.msf.frame,
-                                    DiskInfo.lastSession.min,
-                                    DiskInfo.lastSession.sec,
-                                    DiskInfo.lastSession.frame);
-                       else
-                               printk
-                                   ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
-                                    ms.xa_flag, ms.addr.lba,
-                                    DiskInfo.lastSession.min,
-                                    DiskInfo.lastSession.sec,
-                                    DiskInfo.lastSession.frame);
-#endif
-                       return 0;
-               }
-       case CDROMPLAYTRKIND:   /* Play a track.  This currently ignores index. */
-               if (copy_from_user(&ti, argp, sizeof ti))
-                       return -EFAULT;
-               if (ti.cdti_trk0 < DiskInfo.first
-                   || ti.cdti_trk0 > DiskInfo.last
-                   || ti.cdti_trk1 < ti.cdti_trk0) {
-                       return -EINVAL;
-               }
-               if (ti.cdti_trk1 > DiskInfo.last)
-                       ti.cdti_trk1 = DiskInfo.last;
-               azt_Play.start = Toc[ti.cdti_trk0].diskTime;
-               azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
-#ifdef AZT_DEBUG
-               printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-                      azt_Play.start.min, azt_Play.start.sec,
-                      azt_Play.start.frame, azt_Play.end.min,
-                      azt_Play.end.sec, azt_Play.end.frame);
-#endif
-               i = aztPlay(&azt_Play);
-               if (i < 0) {
-                       aztAudioStatus = CDROM_AUDIO_ERROR;
-                       return -EIO;
-               }
-               aztAudioStatus = CDROM_AUDIO_PLAY;
-               break;
-       case CDROMPLAYMSF:      /* Play starting at the given MSF address. */
-/*              if (aztAudioStatus == CDROM_AUDIO_PLAY) 
-               { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
-                 STEN_LOW;
-                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-               }
-*/
-               if (copy_from_user(&msf, argp, sizeof msf))
-                       return -EFAULT;
-               /* convert to bcd */
-               azt_bin2bcd(&msf.cdmsf_min0);
-               azt_bin2bcd(&msf.cdmsf_sec0);
-               azt_bin2bcd(&msf.cdmsf_frame0);
-               azt_bin2bcd(&msf.cdmsf_min1);
-               azt_bin2bcd(&msf.cdmsf_sec1);
-               azt_bin2bcd(&msf.cdmsf_frame1);
-               azt_Play.start.min = msf.cdmsf_min0;
-               azt_Play.start.sec = msf.cdmsf_sec0;
-               azt_Play.start.frame = msf.cdmsf_frame0;
-               azt_Play.end.min = msf.cdmsf_min1;
-               azt_Play.end.sec = msf.cdmsf_sec1;
-               azt_Play.end.frame = msf.cdmsf_frame1;
-#ifdef AZT_DEBUG
-               printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-                      azt_Play.start.min, azt_Play.start.sec,
-                      azt_Play.start.frame, azt_Play.end.min,
-                      azt_Play.end.sec, azt_Play.end.frame);
-#endif
-               i = aztPlay(&azt_Play);
-               if (i < 0) {
-                       aztAudioStatus = CDROM_AUDIO_ERROR;
-                       return -EIO;
-               }
-               aztAudioStatus = CDROM_AUDIO_PLAY;
-               break;
-
-       case CDROMREADTOCHDR:   /* Read the table of contents header */
-               tocHdr.cdth_trk0 = DiskInfo.first;
-               tocHdr.cdth_trk1 = DiskInfo.last;
-               if (copy_to_user(argp, &tocHdr, sizeof tocHdr))
-                       return -EFAULT;
-               break;
-       case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
-               if (copy_from_user(&entry, argp, sizeof entry))
-                       return -EFAULT;
-               if ((!aztTocUpToDate) || aztDiskChanged)
-                       aztUpdateToc();
-               if (entry.cdte_track == CDROM_LEADOUT)
-                       tocPtr = &Toc[DiskInfo.last + 1];
-               else if (entry.cdte_track > DiskInfo.last
-                        || entry.cdte_track < DiskInfo.first) {
-                       return -EINVAL;
-               } else
-                       tocPtr = &Toc[entry.cdte_track];
-               entry.cdte_adr = tocPtr->ctrl_addr;
-               entry.cdte_ctrl = tocPtr->ctrl_addr >> 4;
-               if (entry.cdte_format == CDROM_LBA)
-                       entry.cdte_addr.lba =
-                           azt_msf2hsg(&tocPtr->diskTime);
-               else if (entry.cdte_format == CDROM_MSF) {
-                       entry.cdte_addr.msf.minute =
-                           azt_bcd2bin(tocPtr->diskTime.min);
-                       entry.cdte_addr.msf.second =
-                           azt_bcd2bin(tocPtr->diskTime.sec);
-                       entry.cdte_addr.msf.frame =
-                           azt_bcd2bin(tocPtr->diskTime.frame);
-               } else {
-                       return -EINVAL;
-               }
-               if (copy_to_user(argp, &entry, sizeof entry))
-                       return -EFAULT;
-               break;
-       case CDROMSUBCHNL:      /* Get subchannel info */
-               if (copy_from_user
-                   (&subchnl, argp, sizeof(struct cdrom_subchnl)))
-                       return -EFAULT;
-               if (aztGetQChannelInfo(&qInfo) < 0) {
-#ifdef AZT_DEBUG
-                       printk
-                           ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",
-                            cmd);
-#endif
-                       return -EIO;
-               }
-               subchnl.cdsc_audiostatus = aztAudioStatus;
-               subchnl.cdsc_adr = qInfo.ctrl_addr;
-               subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
-               subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
-               subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
-               if (subchnl.cdsc_format == CDROM_LBA) {
-                       subchnl.cdsc_absaddr.lba =
-                           azt_msf2hsg(&qInfo.diskTime);
-                       subchnl.cdsc_reladdr.lba =
-                           azt_msf2hsg(&qInfo.trackTime);
-               } else {        /*default */
-                       subchnl.cdsc_format = CDROM_MSF;
-                       subchnl.cdsc_absaddr.msf.minute =
-                           azt_bcd2bin(qInfo.diskTime.min);
-                       subchnl.cdsc_absaddr.msf.second =
-                           azt_bcd2bin(qInfo.diskTime.sec);
-                       subchnl.cdsc_absaddr.msf.frame =
-                           azt_bcd2bin(qInfo.diskTime.frame);
-                       subchnl.cdsc_reladdr.msf.minute =
-                           azt_bcd2bin(qInfo.trackTime.min);
-                       subchnl.cdsc_reladdr.msf.second =
-                           azt_bcd2bin(qInfo.trackTime.sec);
-                       subchnl.cdsc_reladdr.msf.frame =
-                           azt_bcd2bin(qInfo.trackTime.frame);
-               }
-               if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl)))
-                       return -EFAULT;
-               break;
-       case CDROMVOLCTRL:      /* Volume control 
-                                  * With my Aztech CD268-01A volume control does not work, I can only
-                                  turn the channels on (any value !=0) or off (value==0). Maybe it
-                                  works better with your drive */
-               if (copy_from_user(&volctrl, argp, sizeof(volctrl)))
-                       return -EFAULT;
-               azt_Play.start.min = 0x21;
-               azt_Play.start.sec = 0x84;
-               azt_Play.start.frame = volctrl.channel0;
-               azt_Play.end.min = volctrl.channel1;
-               azt_Play.end.sec = volctrl.channel2;
-               azt_Play.end.frame = volctrl.channel3;
-               sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
-               STEN_LOW_WAIT;
-               break;
-       case CDROMEJECT:
-               aztUnlockDoor();        /* Assume user knows what they're doing */
-               /* all drives can at least stop! */
-               if (aztAudioStatus == CDROM_AUDIO_PLAY) {
-                       if (aztSendCmd(ACMD_STOP))
-                               RETURNM("azt_ioctl 10", -1);
-                       STEN_LOW_WAIT;
-               }
-               if (aztSendCmd(ACMD_EJECT))
-                       RETURNM("azt_ioctl 11", -1);
-               STEN_LOW_WAIT;
-               aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-               break;
-       case CDROMEJECT_SW:
-               azt_auto_eject = (char) arg;
-               break;
-       case CDROMRESET:
-               outb(ACMD_SOFT_RESET, CMD_PORT);        /*send reset */
-               STEN_LOW;
-               if (inb(DATA_PORT) != AFL_OP_OK) {      /*OP_OK? */
-                       printk
-                           ("aztcd: AZTECH CD-ROM drive does not respond\n");
-               }
-               break;
-/*Take care, the following code is not compatible with other CD-ROM drivers,
-  use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
-  if you do not want to use it!
-*/
-#if AZT_PRIVATE_IOCTLS
-       case CDROMREADCOOKED:   /*read data in mode 1 (2048 Bytes) */
-       case CDROMREADRAW:      /*read data in mode 2 (2336 Bytes) */
-               {
-                       if (copy_from_user(&msf, argp, sizeof msf))
-                               return -EFAULT;
-                       /* convert to bcd */
-                       azt_bin2bcd(&msf.cdmsf_min0);
-                       azt_bin2bcd(&msf.cdmsf_sec0);
-                       azt_bin2bcd(&msf.cdmsf_frame0);
-                       msf.cdmsf_min1 = 0;
-                       msf.cdmsf_sec1 = 0;
-                       msf.cdmsf_frame1 = 1;   /*read only one frame */
-                       azt_Play.start.min = msf.cdmsf_min0;
-                       azt_Play.start.sec = msf.cdmsf_sec0;
-                       azt_Play.start.frame = msf.cdmsf_frame0;
-                       azt_Play.end.min = msf.cdmsf_min1;
-                       azt_Play.end.sec = msf.cdmsf_sec1;
-                       azt_Play.end.frame = msf.cdmsf_frame1;
-                       if (cmd == CDROMREADRAW) {
-                               if (DiskInfo.xa) {
-                                       return -1;      /*XA Disks can't be read raw */
-                               } else {
-                                       if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play))
-                                               return -1;
-                                       DTEN_LOW;
-                                       insb(DATA_PORT, buf, CD_FRAMESIZE_RAW);
-                                       if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW))
-                                               return -EFAULT;
-                               }
-                       } else
-                               /*CDROMREADCOOKED*/ {
-                               if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
-                                       return -1;
-                               DTEN_LOW;
-                               insb(DATA_PORT, buf, CD_FRAMESIZE);
-                               if (copy_to_user(argp, &buf, CD_FRAMESIZE))
-                                       return -EFAULT;
-                               }
-               }
-               break;
-       case CDROMSEEK: /*seek msf address */
-               if (copy_from_user(&msf, argp, sizeof msf))
-                       return -EFAULT;
-               /* convert to bcd */
-               azt_bin2bcd(&msf.cdmsf_min0);
-               azt_bin2bcd(&msf.cdmsf_sec0);
-               azt_bin2bcd(&msf.cdmsf_frame0);
-               azt_Play.start.min = msf.cdmsf_min0;
-               azt_Play.start.sec = msf.cdmsf_sec0;
-               azt_Play.start.frame = msf.cdmsf_frame0;
-               if (aztSeek(&azt_Play))
-                       return -1;
-               break;
-#endif                         /*end of incompatible code */
-       case CDROMREADMODE1:    /*set read data in mode 1 */
-               return aztSetDiskType(AZT_MODE_1);
-       case CDROMREADMODE2:    /*set read data in mode 2 */
-               return aztSetDiskType(AZT_MODE_2);
-       default:
-               return -EINVAL;
-       }
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztcd_ioctl Command:%x  Time:%li\n", cmd,
-              jiffies);
-#endif
-       return 0;
-}
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-static void azt_transfer(void)
-{
-#ifdef AZT_TEST
-       printk("aztcd: executing azt_transfer Time:%li\n", jiffies);
-#endif
-       if (!current_valid())
-               return;
-
-       while (CURRENT->nr_sectors) {
-               int bn = CURRENT->sector / 4;
-               int i;
-               for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i);
-               if (i < AZT_BUF_SIZ) {
-                       int offs = (i * 4 + (CURRENT->sector & 3)) * 512;
-                       int nr_sectors = 4 - (CURRENT->sector & 3);
-                       if (azt_buf_out != i) {
-                               azt_buf_out = i;
-                               if (azt_buf_bn[i] != bn) {
-                                       azt_buf_out = -1;
-                                       continue;
-                               }
-                       }
-                       if (nr_sectors > CURRENT->nr_sectors)
-                           nr_sectors = CURRENT->nr_sectors;
-                       memcpy(CURRENT->buffer, azt_buf + offs,
-                               nr_sectors * 512);
-                       CURRENT->nr_sectors -= nr_sectors;
-                       CURRENT->sector += nr_sectors;
-                       CURRENT->buffer += nr_sectors * 512;
-               } else {
-                       azt_buf_out = -1;
-                       break;
-               }
-       }
-}
-
-static void do_aztcd_request(request_queue_t * q)
-{
-#ifdef AZT_TEST
-       printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector,
-              CURRENT->nr_sectors, jiffies);
-#endif
-       if (DiskInfo.audio) {
-               printk("aztcd: Error, tried to mount an Audio CD\n");
-               end_request(CURRENT, 0);
-               return;
-       }
-       azt_transfer_is_active = 1;
-       while (current_valid()) {
-               azt_transfer();
-               if (CURRENT->nr_sectors == 0) {
-                       end_request(CURRENT, 1);
-               } else {
-                       azt_buf_out = -1;       /* Want to read a block not in buffer */
-                       if (azt_state == AZT_S_IDLE) {
-                               if ((!aztTocUpToDate) || aztDiskChanged) {
-                                       if (aztUpdateToc() < 0) {
-                                               while (current_valid())
-                                                       end_request(CURRENT, 0);
-                                               break;
-                                       }
-                               }
-                               azt_state = AZT_S_START;
-                               AztTries = 5;
-                               SET_TIMER(azt_poll, HZ / 100);
-                       }
-                       break;
-               }
-       }
-       azt_transfer_is_active = 0;
-#ifdef AZT_TEST2
-       printk
-           ("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n",
-            azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
-       printk(" do_aztcd_request ends  Time:%li\n", jiffies);
-#endif
-}
-
-
-static void azt_invalidate_buffers(void)
-{
-       int i;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: executing azt_invalidate_buffers\n");
-#endif
-       for (i = 0; i < AZT_BUF_SIZ; ++i)
-               azt_buf_bn[i] = -1;
-       azt_buf_out = -1;
-}
-
-/*
- * Open the device special file.  Check that a disk is in.
- */
-static int aztcd_open(struct inode *ip, struct file *fp)
-{
-       int st;
-
-#ifdef AZT_DEBUG
-       printk("aztcd: starting aztcd_open\n");
-#endif
-
-       if (aztPresent == 0)
-               return -ENXIO;  /* no hardware */
-
-       if (!azt_open_count && azt_state == AZT_S_IDLE) {
-               azt_invalidate_buffers();
-
-               st = getAztStatus();    /* check drive status */
-               if (st == -1)
-                       goto err_out;   /* drive doesn't respond */
-
-               if (st & AST_DOOR_OPEN) {       /* close door, then get the status again. */
-                       printk("aztcd: Door Open?\n");
-                       aztCloseDoor();
-                       st = getAztStatus();
-               }
-
-               if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) {       /*no disk in drive or changed */
-                       printk
-                           ("aztcd: Disk Changed or No Disk in Drive?\n");
-                       aztTocUpToDate = 0;
-               }
-               if (aztUpdateToc())
-                       goto err_out;
-
-       }
-       ++azt_open_count;
-       aztLockDoor();
-
-#ifdef AZT_DEBUG
-       printk("aztcd: exiting aztcd_open\n");
-#endif
-       return 0;
-
-      err_out:
-       return -EIO;
-}
-
-
-/*
- * On close, we flush all azt blocks from the buffer cache.
- */
-static int aztcd_release(struct inode *inode, struct file *file)
-{
-#ifdef AZT_DEBUG
-       printk("aztcd: executing aztcd_release\n");
-       printk("inode: %p, device: %s    file: %p\n", inode,
-              inode->i_bdev->bd_disk->disk_name, file);
-#endif
-       if (!--azt_open_count) {
-               azt_invalidate_buffers();
-               aztUnlockDoor();
-               if (azt_auto_eject)
-                       aztSendCmd(ACMD_EJECT);
-               CLEAR_TIMER;
-       }
-       return 0;
-}
-
-static struct gendisk *azt_disk;
-
-/*
- * Test for presence of drive and initialize it.  Called at boot time.
- */
-
-static int __init aztcd_init(void)
-{
-       long int count, max_count;
-       unsigned char result[50];
-       int st;
-       void* status = NULL;
-       int i = 0;
-       int ret = 0;
-
-       if (azt_port == 0) {
-               printk(KERN_INFO "aztcd: no Aztech CD-ROM Initialization");
-               return -EIO;
-       }
-
-       printk(KERN_INFO "aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM "
-              "CD-ROM Driver\n");
-       printk(KERN_INFO "aztcd: (C) 1994-98 W.Zimmermann\n");
-       if (azt_port == -1) {
-               printk
-                   ("aztcd: DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n",
-                    AZT_VERSION);
-       } else
-               printk
-                   ("aztcd: DriverVersion=%s BaseAddress=0x%x  For IDE/ATAPI-drives use ide-cd.c\n",
-                    AZT_VERSION, azt_port);
-       printk(KERN_INFO "aztcd: If you have problems, read /usr/src/linux/"
-              "Documentation/cdrom/aztcd\n");
-
-
-#ifdef AZT_SW32                        /*CDROM connected to Soundwave32 card */
-       if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) {
-               printk
-                   ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
-                    AZT_SW32_BASE_ADDR, AZT_SW32_INIT,
-                    AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG);
-               return -EIO;
-       } else {
-               printk(KERN_INFO
-                      "aztcd: Soundwave32 card detected at %x  Version %x\n",
-                      AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
-               outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG);
-               for (count = 0; count < 10000; count++);        /*delay a bit */
-       }
-#endif
-
-       /* check for presence of drive */
-
-       if (azt_port == -1) {   /* autoprobing for proprietary interface  */
-               for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) {
-                       azt_port = azt_port_auto[i];
-                       printk(KERN_INFO "aztcd: Autoprobing BaseAddress=0x%x"
-                              "\n", azt_port);
-                        /*proprietary interfaces need 4 bytes */
-                       if (!request_region(azt_port, 4, "aztcd")) {
-                               continue;
-                       }
-                       outb(POLLED, MODE_PORT);
-                       inb(CMD_PORT);
-                       inb(CMD_PORT);
-                       outb(ACMD_GET_VERSION, CMD_PORT);       /*Try to get version info */
-
-                       aztTimeOutCount = 0;
-                       do {
-                               aztIndatum = inb(STATUS_PORT);
-                               aztTimeOutCount++;
-                               if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
-                                       break;
-                       } while (aztIndatum & AFL_STATUS);
-                       if (inb(DATA_PORT) == AFL_OP_OK) { /* OK drive found */
-                               break;
-                       }
-                       else {  /* Drive not found on this port - try next one */
-                               release_region(azt_port, 4);
-                       }
-               }
-               if ((i == 16) || (azt_port_auto[i] == 0)) {
-                       printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n");
-                       return -EIO;
-               }
-       } else {                /* no autoprobing */
-               if ((azt_port == 0x1f0) || (azt_port == 0x170))
-                       status = request_region(azt_port, 8, "aztcd");  /*IDE-interfaces need 8 bytes */
-               else
-                       status = request_region(azt_port, 4, "aztcd");  /*proprietary interfaces need 4 bytes */
-               if (!status) {
-                       printk(KERN_WARNING "aztcd: conflict, I/O port (%X) "
-                              "already used\n", azt_port);
-                       return -EIO;
-               }
-
-               if ((azt_port == 0x1f0) || (azt_port == 0x170))
-                       SWITCH_IDE_SLAVE;       /*switch IDE interface to slave configuration */
-
-               outb(POLLED, MODE_PORT);
-               inb(CMD_PORT);
-               inb(CMD_PORT);
-               outb(ACMD_GET_VERSION, CMD_PORT);       /*Try to get version info */
-
-               aztTimeOutCount = 0;
-               do {
-                       aztIndatum = inb(STATUS_PORT);
-                       aztTimeOutCount++;
-                       if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
-                               break;
-               } while (aztIndatum & AFL_STATUS);
-
-               if (inb(DATA_PORT) != AFL_OP_OK) {      /*OP_OK? If not, reset and try again */
-#ifndef MODULE
-                       if (azt_cont != 0x79) {
-                               printk(KERN_WARNING "aztcd: no AZTECH CD-ROM "
-                                      "drive found-Try boot parameter aztcd="
-                                      "<BaseAddress>,0x79\n");
-                               ret = -EIO;
-                               goto err_out;
-                       }
-#else
-                       if (0) {
-                       }
-#endif
-                       else {
-                               printk(KERN_INFO "aztcd: drive reset - "
-                                      "please wait\n");
-                               for (count = 0; count < 50; count++) {
-                                       inb(STATUS_PORT);       /*removing all data from earlier tries */
-                                       inb(DATA_PORT);
-                               }
-                               outb(POLLED, MODE_PORT);
-                               inb(CMD_PORT);
-                               inb(CMD_PORT);
-                               getAztStatus(); /*trap errors */
-                               outb(ACMD_SOFT_RESET, CMD_PORT);        /*send reset */
-                               STEN_LOW;
-                               if (inb(DATA_PORT) != AFL_OP_OK) {      /*OP_OK? */
-                                       printk(KERN_WARNING "aztcd: no AZTECH "
-                                              "CD-ROM drive found\n");
-                                       ret = -EIO;
-                                       goto err_out;
-                               }
-
-                               for (count = 0; count < AZT_TIMEOUT;
-                                    count++)
-                                       barrier();      /* Stop gcc 2.96 being smart */
-                               /* use udelay(), damnit -- AV */
-
-                               if ((st = getAztStatus()) == -1) {
-                                       printk(KERN_WARNING "aztcd: Drive Status"
-                                              " Error Status=%x\n", st);
-                                       ret = -EIO;
-                                       goto err_out;
-                               }
-#ifdef AZT_DEBUG
-                               printk(KERN_DEBUG "aztcd: Status = %x\n", st);
-#endif
-                               outb(POLLED, MODE_PORT);
-                               inb(CMD_PORT);
-                               inb(CMD_PORT);
-                               outb(ACMD_GET_VERSION, CMD_PORT);       /*GetVersion */
-                               STEN_LOW;
-                               OP_OK;
-                       }
-               }
-       }
-
-       azt_init_end = 1;
-       STEN_LOW;
-       result[0] = inb(DATA_PORT);     /*reading in a null byte??? */
-       for (count = 1; count < 50; count++) {  /*Reading version string */
-               aztTimeOutCount = 0;    /*here we must implement STEN_LOW differently */
-               do {
-                       aztIndatum = inb(STATUS_PORT);  /*because we want to exit by timeout */
-                       aztTimeOutCount++;
-                       if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
-                               break;
-               } while (aztIndatum & AFL_STATUS);
-               if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
-                       break;  /*all chars read? */
-               result[count] = inb(DATA_PORT);
-       }
-       if (count > 30)
-               max_count = 30; /*print max.30 chars of the version string */
-       else
-               max_count = count;
-       printk(KERN_INFO "aztcd: FirmwareVersion=");
-       for (count = 1; count < max_count; count++)
-               printk("%c", result[count]);
-       printk("<<>> ");
-
-       if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) {
-               printk("AZTECH drive detected\n");
-       /*AZTECH*/}
-               else if ((result[2] == 'C') && (result[3] == 'D')
-                        && (result[4] == 'D')) {
-               printk("ORCHID or WEARNES drive detected\n");   /*ORCHID or WEARNES */
-       } else if ((result[1] == 0x03) && (result[2] == '5')) {
-               printk("TXC or CyCDROM drive detected\n");      /*Conrad TXC, CyCDROM */
-       } else {                /*OTHERS or none */
-               printk("\nunknown drive or firmware version detected\n");
-               printk
-                   ("aztcd may not run stable, if you want to try anyhow,\n");
-               printk("boot with: aztcd=<BaseAddress>,0x79\n");
-               if ((azt_cont != 0x79)) {
-                       printk("aztcd: FirmwareVersion=");
-                       for (count = 1; count < 5; count++)
-                               printk("%c", result[count]);
-                       printk("<<>> ");
-                       printk("Aborted\n");
-                       ret = -EIO;
-                       goto err_out;
-               }
-       }
-       azt_disk = alloc_disk(1);
-       if (!azt_disk)
-               goto err_out;
-
-       if (register_blkdev(MAJOR_NR, "aztcd")) {
-               ret = -EIO;
-               goto err_out2;
-       }
-
-       azt_queue = blk_init_queue(do_aztcd_request, &aztSpin);
-       if (!azt_queue) {
-               ret = -ENOMEM;
-               goto err_out3;
-       }
-
-       blk_queue_hardsect_size(azt_queue, 2048);
-       azt_disk->major = MAJOR_NR;
-       azt_disk->first_minor = 0;
-       azt_disk->fops = &azt_fops;
-       sprintf(azt_disk->disk_name, "aztcd");
-       azt_disk->queue = azt_queue;
-       add_disk(azt_disk);
-       azt_invalidate_buffers();
-       aztPresent = 1;
-       aztCloseDoor();
-       return 0;
-err_out3:
-       unregister_blkdev(MAJOR_NR, "aztcd");
-err_out2:
-       put_disk(azt_disk);
-err_out:
-       if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
-               SWITCH_IDE_MASTER;
-               release_region(azt_port, 8);    /*IDE-interface */
-       } else
-               release_region(azt_port, 4);    /*proprietary interface */
-       return ret;
-
-}
-
-static void __exit aztcd_exit(void)
-{
-       del_gendisk(azt_disk);
-       put_disk(azt_disk);
-       if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) {
-               printk("What's that: can't unregister aztcd\n");
-               return;
-       }
-       blk_cleanup_queue(azt_queue);
-       if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
-               SWITCH_IDE_MASTER;
-               release_region(azt_port, 8);    /*IDE-interface */
-       } else
-               release_region(azt_port, 4);    /*proprietary interface */
-       printk(KERN_INFO "aztcd module released.\n");
-}
-
-module_init(aztcd_init);
-module_exit(aztcd_exit);
-
-/*##########################################################################
-  Aztcd State Machine: Controls Drive Operating State
-  ##########################################################################
-*/
-static void azt_poll(void)
-{
-       int st = 0;
-       int loop_ctl = 1;
-       int skip = 0;
-
-       if (azt_error) {
-               if (aztSendCmd(ACMD_GET_ERROR))
-                       RETURN("azt_poll 1");
-               STEN_LOW;
-               azt_error = inb(DATA_PORT) & 0xFF;
-               printk("aztcd: I/O error 0x%02x\n", azt_error);
-               azt_invalidate_buffers();
-#ifdef WARN_IF_READ_FAILURE
-               if (AztTries == 5)
-                       printk
-                           ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n",
-                            azt_next_bn);
-#endif
-               if (!AztTries--) {
-                       printk
-                           ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n",
-                            azt_next_bn);
-                       if (azt_transfer_is_active) {
-                               AztTries = 0;
-                               loop_ctl = 0;
-                       }
-                       if (current_valid())
-                               end_request(CURRENT, 0);
-                       AztTries = 5;
-               }
-               azt_error = 0;
-               azt_state = AZT_S_STOP;
-       }
-
-       while (loop_ctl) {
-               loop_ctl = 0;   /* each case must flip this back to 1 if we want
-                                  to come back up here */
-               switch (azt_state) {
-
-               case AZT_S_IDLE:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_IDLE\n");
-                       }
-#endif
-                       return;
-
-               case AZT_S_START:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_START\n");
-                       }
-#endif
-                       if (aztSendCmd(ACMD_GET_STATUS))
-                               RETURN("azt_poll 2");   /*result will be checked by aztStatus() */
-                       azt_state =
-                           azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
-                       AztTimeout = 3000;
-                       break;
-
-               case AZT_S_MODE:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_MODE\n");
-                       }
-#endif
-                       if (!skip) {
-                               if ((st = aztStatus()) != -1) {
-                                       if ((st & AST_DSK_CHG)
-                                           || (st & AST_NOT_READY)) {
-                                               aztDiskChanged = 1;
-                                               aztTocUpToDate = 0;
-                                               azt_invalidate_buffers();
-                                               end_request(CURRENT, 0);
-                                               printk
-                                                   ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
-                                       }
-                               } else
-                                       break;
-                       }
-                       skip = 0;
-
-                       if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
-                               aztDiskChanged = 1;
-                               aztTocUpToDate = 0;
-                               printk
-                                   ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
-                               end_request(CURRENT, 0);
-                               printk((st & AST_DOOR_OPEN) ?
-                                      "aztcd: door open\n" :
-                                      "aztcd: disk removed\n");
-                               if (azt_transfer_is_active) {
-                                       azt_state = AZT_S_START;
-                                       loop_ctl = 1;   /* goto immediately */
-                                       break;
-                               }
-                               azt_state = AZT_S_IDLE;
-                               while (current_valid())
-                                       end_request(CURRENT, 0);
-                               return;
-                       }
-
-/*       if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
-         outb(0x01, DATA_PORT);
-         PA_OK;
-         STEN_LOW;
-*/
-                       if (aztSendCmd(ACMD_GET_STATUS))
-                               RETURN("azt_poll 4");
-                       STEN_LOW;
-                       azt_mode = 1;
-                       azt_state = AZT_S_READ;
-                       AztTimeout = 3000;
-
-                       break;
-
-
-               case AZT_S_READ:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_READ\n");
-                       }
-#endif
-                       if (!skip) {
-                               if ((st = aztStatus()) != -1) {
-                                       if ((st & AST_DSK_CHG)
-                                           || (st & AST_NOT_READY)) {
-                                               aztDiskChanged = 1;
-                                               aztTocUpToDate = 0;
-                                               azt_invalidate_buffers();
-                                               printk
-                                                   ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
-                                               end_request(CURRENT, 0);
-                                       }
-                               } else
-                                       break;
-                       }
-
-                       skip = 0;
-                       if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
-                               aztDiskChanged = 1;
-                               aztTocUpToDate = 0;
-                               printk((st & AST_DOOR_OPEN) ?
-                                      "aztcd: door open\n" :
-                                      "aztcd: disk removed\n");
-                               if (azt_transfer_is_active) {
-                                       azt_state = AZT_S_START;
-                                       loop_ctl = 1;
-                                       break;
-                               }
-                               azt_state = AZT_S_IDLE;
-                               while (current_valid())
-                                       end_request(CURRENT, 0);
-                               return;
-                       }
-
-                       if (current_valid()) {
-                               struct azt_Play_msf msf;
-                               int i;
-                               azt_next_bn = CURRENT->sector / 4;
-                               azt_hsg2msf(azt_next_bn, &msf.start);
-                               i = 0;
-                               /* find out in which track we are */
-                               while (azt_msf2hsg(&msf.start) >
-                                      azt_msf2hsg(&Toc[++i].trackTime)) {
-                               };
-                               if (azt_msf2hsg(&msf.start) <
-                                   azt_msf2hsg(&Toc[i].trackTime) -
-                                   AZT_BUF_SIZ) {
-                                       azt_read_count = AZT_BUF_SIZ;   /*fast, because we read ahead */
-                                       /*azt_read_count=CURRENT->nr_sectors;    slow, no read ahead */
-                               } else  /* don't read beyond end of track */
-#if AZT_MULTISESSION
-                               {
-                                       azt_read_count =
-                                           (azt_msf2hsg(&Toc[i].trackTime)
-                                            / 4) * 4 -
-                                           azt_msf2hsg(&msf.start);
-                                       if (azt_read_count < 0)
-                                               azt_read_count = 0;
-                                       if (azt_read_count > AZT_BUF_SIZ)
-                                               azt_read_count =
-                                                   AZT_BUF_SIZ;
-                                       printk
-                                           ("aztcd: warning - trying to read beyond end of track\n");
-/*               printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime));
-*/ }
-#else
-                               {
-                                       azt_read_count = AZT_BUF_SIZ;
-                               }
-#endif
-                               msf.end.min = 0;
-                               msf.end.sec = 0;
-                               msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */
-#ifdef AZT_TEST3
-                               printk
-                                   ("---reading msf-address %x:%x:%x  %x:%x:%x\n",
-                                    msf.start.min, msf.start.sec,
-                                    msf.start.frame, msf.end.min,
-                                    msf.end.sec, msf.end.frame);
-                               printk
-                                   ("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n",
-                                    azt_next_bn, azt_buf_in, azt_buf_out,
-                                    azt_buf_bn[azt_buf_in]);
-#endif
-                               if (azt_read_mode == AZT_MODE_2) {
-                                       sendAztCmd(ACMD_PLAY_READ_RAW, &msf);   /*XA disks in raw mode */
-                               } else {
-                                       sendAztCmd(ACMD_PLAY_READ, &msf);       /*others in cooked mode */
-                               }
-                               azt_state = AZT_S_DATA;
-                               AztTimeout = READ_TIMEOUT;
-                       } else {
-                               azt_state = AZT_S_STOP;
-                               loop_ctl = 1;
-                               break;
-                       }
-
-                       break;
-
-
-               case AZT_S_DATA:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_DATA\n");
-                       }
-#endif
-
-                       st = inb(STATUS_PORT) & AFL_STATUSorDATA;
-
-                       switch (st) {
-
-                       case AFL_DATA:
-#ifdef AZT_TEST3
-                               if (st != azt_st_old) {
-                                       azt_st_old = st;
-                                       printk("---AFL_DATA st:%x\n", st);
-                               }
-#endif
-                               if (!AztTries--) {
-                                       printk
-                                           ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n",
-                                            azt_next_bn);
-                                       if (azt_transfer_is_active) {
-                                               AztTries = 0;
-                                               break;
-                                       }
-                                       if (current_valid())
-                                               end_request(CURRENT, 0);
-                                       AztTries = 5;
-                               }
-                               azt_state = AZT_S_START;
-                               AztTimeout = READ_TIMEOUT;
-                               loop_ctl = 1;
-                               break;
-
-                       case AFL_STATUSorDATA:
-#ifdef AZT_TEST3
-                               if (st != azt_st_old) {
-                                       azt_st_old = st;
-                                       printk
-                                           ("---AFL_STATUSorDATA st:%x\n",
-                                            st);
-                               }
-#endif
-                               break;
-
-                       default:
-#ifdef AZT_TEST3
-                               if (st != azt_st_old) {
-                                       azt_st_old = st;
-                                       printk("---default: st:%x\n", st);
-                               }
-#endif
-                               AztTries = 5;
-                               if (!current_valid() && azt_buf_in == azt_buf_out) {
-                                       azt_state = AZT_S_STOP;
-                                       loop_ctl = 1;
-                                       break;
-                               }
-                               if (azt_read_count <= 0)
-                                       printk
-                                           ("aztcd: warning - try to read 0 frames\n");
-                               while (azt_read_count) {        /*??? fast read ahead loop */
-                                       azt_buf_bn[azt_buf_in] = -1;
-                                       DTEN_LOW;       /*??? unsolved problem, very
-                                                          seldom we get timeouts
-                                                          here, don't now the real
-                                                          reason. With my drive this
-                                                          sometimes also happens with
-                                                          Aztech's original driver under
-                                                          DOS. Is it a hardware bug? 
-                                                          I tried to recover from such
-                                                          situations here. Zimmermann */
-                                       if (aztTimeOutCount >= AZT_TIMEOUT) {
-                                               printk
-                                                   ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n",
-                                                    azt_read_count,
-                                                    CURRENT->nr_sectors,
-                                                    azt_buf_in);
-                                               printk
-                                                   ("azt_transfer_is_active:%x\n",
-                                                    azt_transfer_is_active);
-                                               azt_read_count = 0;
-                                               azt_state = AZT_S_STOP;
-                                               loop_ctl = 1;
-                                               end_request(CURRENT, 1);        /*should we have here (1) or (0)? */
-                                       } else {
-                                               if (azt_read_mode ==
-                                                   AZT_MODE_2) {
-                                                       insb(DATA_PORT,
-                                                            azt_buf +
-                                                            CD_FRAMESIZE_RAW
-                                                            * azt_buf_in,
-                                                            CD_FRAMESIZE_RAW);
-                                               } else {
-                                                       insb(DATA_PORT,
-                                                            azt_buf +
-                                                            CD_FRAMESIZE *
-                                                            azt_buf_in,
-                                                            CD_FRAMESIZE);
-                                               }
-                                               azt_read_count--;
-#ifdef AZT_TEST3
-                                               printk
-                                                   ("AZT_S_DATA; ---I've read data- read_count: %d\n",
-                                                    azt_read_count);
-                                               printk
-                                                   ("azt_next_bn:%d  azt_buf_in:%d azt_buf_out:%d  azt_buf_bn:%d\n",
-                                                    azt_next_bn,
-                                                    azt_buf_in,
-                                                    azt_buf_out,
-                                                    azt_buf_bn
-                                                    [azt_buf_in]);
-#endif
-                                               azt_buf_bn[azt_buf_in] =
-                                                   azt_next_bn++;
-                                               if (azt_buf_out == -1)
-                                                       azt_buf_out =
-                                                           azt_buf_in;
-                                               azt_buf_in =
-                                                   azt_buf_in + 1 ==
-                                                   AZT_BUF_SIZ ? 0 :
-                                                   azt_buf_in + 1;
-                                       }
-                               }
-                               if (!azt_transfer_is_active) {
-                                       while (current_valid()) {
-                                               azt_transfer();
-                                               if (CURRENT->nr_sectors ==
-                                                   0)
-                                                       end_request(CURRENT, 1);
-                                               else
-                                                       break;
-                                       }
-                               }
-
-                               if (current_valid()
-                                   && (CURRENT->sector / 4 < azt_next_bn
-                                       || CURRENT->sector / 4 >
-                                       azt_next_bn + AZT_BUF_SIZ)) {
-                                       azt_state = AZT_S_STOP;
-                                       loop_ctl = 1;
-                                       break;
-                               }
-                               AztTimeout = READ_TIMEOUT;
-                               if (azt_read_count == 0) {
-                                       azt_state = AZT_S_STOP;
-                                       loop_ctl = 1;
-                                       break;
-                               }
-                               break;
-                       }
-                       break;
-
-
-               case AZT_S_STOP:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_STOP\n");
-                       }
-#endif
-                       if (azt_read_count != 0)
-                               printk("aztcd: discard data=%x frames\n",
-                                      azt_read_count);
-                       while (azt_read_count != 0) {
-                               int i;
-                               if (!(inb(STATUS_PORT) & AFL_DATA)) {
-                                       if (azt_read_mode == AZT_MODE_2)
-                                               for (i = 0;
-                                                    i < CD_FRAMESIZE_RAW;
-                                                    i++)
-                                                       inb(DATA_PORT);
-                                       else
-                                               for (i = 0;
-                                                    i < CD_FRAMESIZE; i++)
-                                                       inb(DATA_PORT);
-                               }
-                               azt_read_count--;
-                       }
-                       if (aztSendCmd(ACMD_GET_STATUS))
-                               RETURN("azt_poll 5");
-                       azt_state = AZT_S_STOPPING;
-                       AztTimeout = 1000;
-                       break;
-
-               case AZT_S_STOPPING:
-#ifdef AZT_TEST3
-                       if (azt_state != azt_state_old) {
-                               azt_state_old = azt_state;
-                               printk("AZT_S_STOPPING\n");
-                       }
-#endif
-
-                       if ((st = aztStatus()) == -1 && AztTimeout)
-                               break;
-
-                       if ((st != -1)
-                           && ((st & AST_DSK_CHG)
-                               || (st & AST_NOT_READY))) {
-                               aztDiskChanged = 1;
-                               aztTocUpToDate = 0;
-                               azt_invalidate_buffers();
-                               printk
-                                   ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
-                               end_request(CURRENT, 0);
-                       }
-
-#ifdef AZT_TEST3
-                       printk("CURRENT_VALID %d azt_mode %d\n",
-                              current_valid(), azt_mode);
-#endif
-
-                       if (current_valid()) {
-                               if (st != -1) {
-                                       if (azt_mode == 1) {
-                                               azt_state = AZT_S_READ;
-                                               loop_ctl = 1;
-                                               skip = 1;
-                                               break;
-                                       } else {
-                                               azt_state = AZT_S_MODE;
-                                               loop_ctl = 1;
-                                               skip = 1;
-                                               break;
-                                       }
-                               } else {
-                                       azt_state = AZT_S_START;
-                                       AztTimeout = 1;
-                               }
-                       } else {
-                               azt_state = AZT_S_IDLE;
-                               return;
-                       }
-                       break;
-
-               default:
-                       printk("aztcd: invalid state %d\n", azt_state);
-                       return;
-               }               /* case */
-       }                       /* while */
-
-
-       if (!AztTimeout--) {
-               printk("aztcd: timeout in state %d\n", azt_state);
-               azt_state = AZT_S_STOP;
-               if (aztSendCmd(ACMD_STOP))
-                       RETURN("azt_poll 6");
-               STEN_LOW_WAIT;
-       };
-
-       SET_TIMER(azt_poll, HZ / 100);
-}
-
-
-/*###########################################################################
- * Miscellaneous support functions
-  ###########################################################################
-*/
-static void azt_hsg2msf(long hsg, struct msf *msf)
-{
-       hsg += 150;
-       msf->min = hsg / 4500;
-       hsg %= 4500;
-       msf->sec = hsg / 75;
-       msf->frame = hsg % 75;
-#ifdef AZT_DEBUG
-       if (msf->min >= 70)
-               printk("aztcd: Error hsg2msf address Minutes\n");
-       if (msf->sec >= 60)
-               printk("aztcd: Error hsg2msf address Seconds\n");
-       if (msf->frame >= 75)
-               printk("aztcd: Error hsg2msf address Frames\n");
-#endif
-       azt_bin2bcd(&msf->min); /* convert to BCD */
-       azt_bin2bcd(&msf->sec);
-       azt_bin2bcd(&msf->frame);
-}
-
-static long azt_msf2hsg(struct msf *mp)
-{
-       return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75
-           + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET;
-}
-
-static void azt_bin2bcd(unsigned char *p)
-{
-       int u, t;
-
-       u = *p % 10;
-       t = *p / 10;
-       *p = u | (t << 4);
-}
-
-static int azt_bcd2bin(unsigned char bcd)
-{
-       return (bcd >> 4) * 10 + (bcd & 0xF);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(AZTECH_CDROM_MAJOR);
diff --git a/drivers/cdrom/aztcd.h b/drivers/cdrom/aztcd.h
deleted file mode 100644 (file)
index 057501e..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* $Id: aztcd.h,v 2.60 1997/11/29 09:51:22 root Exp root $
- *
- * Definitions for a AztechCD268 CD-ROM interface
- *     Copyright (C) 1994-98  Werner Zimmermann
- *
- *     based on Mitsumi CDROM driver by Martin Harriss
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  History:   W.Zimmermann adaption to Aztech CD268-01A Version 1.3
- *             October 1994 Email: Werner.Zimmermann@fht-esslingen.de
- */
-
-/* *** change this to set the I/O port address of your CD-ROM drive,
-       set to '-1', if you want autoprobing */
-#define AZT_BASE_ADDR          -1
-
-/* list of autoprobing addresses (not more than 15), last value must be 0x000
-   Note: Autoprobing is only enabled, if AZT_BASE_ADDR is set to '-1' ! */
-#define AZT_BASE_AUTO          { 0x320, 0x300, 0x310, 0x330, 0x000 }
-
-/* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard
-   and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */
-/*#define AZT_SW32 1
-*/
-
-#ifdef AZT_SW32 
-#define AZT_SW32_BASE_ADDR      0x220  /*I/O port base address of your soundcard*/
-#endif
-
-/* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray 
-   from locking */
-#define AZT_ALLOW_TRAY_LOCK    1
-
-/*Set this to 1 to allow auto-eject when unmounting a disk, set to 0, if you 
-  don't want the auto-eject feature*/
-#define AZT_AUTO_EJECT          0
-
-/*Set this to 1, if you want to use incompatible ioctls for reading in raw and
-  cooked mode */
-#define AZT_PRIVATE_IOCTLS      1
-
-/*Set this to 1, if you want multisession support by the ISO fs. Even if you set 
-  this value to '0' you can use multisession CDs. In that case the drive's firm-
-  ware will do the appropriate redirection automatically. The CD will then look
-  like a single session CD (but nevertheless all data may be read). Please read 
-  chapter '5.1 Multisession support' in README.aztcd for details. Normally it's 
-  uncritical to leave this setting untouched */
-#define AZT_MULTISESSION        1
-
-/*Uncomment this, if you are using a linux kernel version prior to 2.1.0 */
-/*#define AZT_KERNEL_PRIOR_2_1 */
-
-/*---------------------------------------------------------------------------*/
-/*-----nothing to be configured for normal applications below this line------*/
-
-
-/* Increase this if you get lots of timeouts; if you get kernel panic, replace
-   STEN_LOW_WAIT by STEN_LOW in the source code */
-#define AZT_STATUS_DELAY       400       /*for timer wait, STEN_LOW_WAIT*/
-#define AZT_TIMEOUT            8000000   /*for busy wait STEN_LOW, DTEN_LOW*/
-#define AZT_FAST_TIMEOUT       10000     /*for reading the version string*/
-
-/* number of times to retry a command before giving up */
-#define AZT_RETRY_ATTEMPTS     3
-
-/* port access macros */
-#define CMD_PORT               azt_port
-#define DATA_PORT              azt_port
-#define STATUS_PORT            azt_port+1
-#define MODE_PORT              azt_port+2
-#ifdef  AZT_SW32                
- #define AZT_SW32_INIT          (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16))
- #define AZT_SW32_CONFIG_REG    AZT_SW32_BASE_ADDR+0x16  /*Soundwave32 Config. Register*/
- #define AZT_SW32_ID_REG        AZT_SW32_BASE_ADDR+0x04  /*Soundwave32 ID Version Register*/
-#endif
-
-/* status bits */
-#define AST_CMD_CHECK          0x80            /* 1 = command error */
-#define AST_DOOR_OPEN          0x40            /* 1 = door is open */
-#define AST_NOT_READY          0x20            /* 1 = no disk in the drive */
-#define AST_DSK_CHG            0x02            /* 1 = disk removed or changed */
-#define AST_MODE                0x01            /* 0=MODE1, 1=MODE2 */
-#define AST_MODE_BITS          0x1C            /* Mode Bits */
-#define AST_INITIAL            0x0C            /* initial, only valid ... */
-#define AST_BUSY               0x04            /* now playing, only valid
-                                                  in combination with mode
-                                                  bits */
-/* flag bits */
-#define AFL_DATA               0x02            /* data available if low */
-#define AFL_STATUS             0x04            /* status available if low */
-#define AFL_OP_OK              0x01            /* OP_OK command correct*/
-#define AFL_PA_OK              0x02            /* PA_OK parameter correct*/
-#define AFL_OP_ERR             0x05            /* error in command*/
-#define AFL_PA_ERR             0x06            /* error in parameters*/
-#define POLLED                 0x04            /* polled mode */
-
-/* commands */
-#define ACMD_SOFT_RESET                0x10            /* reset drive */
-#define ACMD_PLAY_READ         0x20            /* read data track in cooked mode */
-#define ACMD_PLAY_READ_RAW      0x21           /* reading in raw mode*/
-#define ACMD_SEEK               0x30            /* seek msf address*/
-#define ACMD_SEEK_TO_LEADIN     0x31           /* seek to leadin track*/
-#define ACMD_GET_ERROR         0x40            /* get error code */
-#define ACMD_GET_STATUS                0x41            /* get status */
-#define ACMD_GET_Q_CHANNEL      0x50           /* read info from q channel */
-#define ACMD_EJECT             0x60            /* eject/open tray */
-#define ACMD_CLOSE              0x61            /* close tray */
-#define ACMD_LOCK              0x71            /* lock tray closed */
-#define ACMD_UNLOCK            0x72            /* unlock tray */
-#define ACMD_PAUSE             0x80            /* pause */
-#define ACMD_STOP              0x81            /* stop play */
-#define ACMD_PLAY_AUDIO                0x90            /* play audio track */
-#define ACMD_SET_VOLUME                0x93            /* set audio level */
-#define ACMD_GET_VERSION       0xA0            /* get firmware version */
-#define ACMD_SET_DISK_TYPE     0xA1            /* set disk data mode */
-
-#define MAX_TRACKS             104
-
-struct msf {
-       unsigned char   min;
-       unsigned char   sec;
-       unsigned char   frame;
-};
-
-struct azt_Play_msf {
-       struct msf      start;
-       struct msf      end;
-};
-
-struct azt_DiskInfo {
-       unsigned char   first;
-        unsigned char   next;
-       unsigned char   last;
-       struct msf      diskLength;
-       struct msf      firstTrack;
-        unsigned char   multi;
-        struct msf      nextSession;
-        struct msf      lastSession;
-        unsigned char   xa;
-        unsigned char   audio;
-};
-
-struct azt_Toc {
-       unsigned char   ctrl_addr;
-       unsigned char   track;
-       unsigned char   pointIndex;
-       struct msf      trackTime;
-       struct msf      diskTime;
-};
index 3625a05bc3d33fbd78c97d1a6a04ac03b596822d..aa5468f487ba3d9e55172a52587a5257d85d2e48 100644 (file)
@@ -302,7 +302,7 @@ module_param(lockdoor, bool, 0);
 module_param(check_media_type, bool, 0);
 module_param(mrw_format_restart, bool, 0);
 
-static DEFINE_SPINLOCK(cdrom_lock);
+static DEFINE_MUTEX(cdrom_mutex);
 
 static const char *mrw_format_status[] = {
        "not mrw",
@@ -438,10 +438,10 @@ int register_cdrom(struct cdrom_device_info *cdi)
                cdo->generic_packet = cdrom_dummy_generic_packet;
 
        cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
-       spin_lock(&cdrom_lock);
+       mutex_lock(&cdrom_mutex);
        cdi->next = topCdromPtr;        
        topCdromPtr = cdi;
-       spin_unlock(&cdrom_lock);
+       mutex_unlock(&cdrom_mutex);
        return 0;
 }
 #undef ENSURE
@@ -452,7 +452,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
        cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
 
        prev = NULL;
-       spin_lock(&cdrom_lock);
+       mutex_lock(&cdrom_mutex);
        cdi = topCdromPtr;
        while (cdi && cdi != unreg) {
                prev = cdi;
@@ -460,7 +460,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
        }
 
        if (cdi == NULL) {
-               spin_unlock(&cdrom_lock);
+               mutex_unlock(&cdrom_mutex);
                return -2;
        }
        if (prev)
@@ -468,7 +468,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
        else
                topCdromPtr = cdi->next;
 
-       spin_unlock(&cdrom_lock);
+       mutex_unlock(&cdrom_mutex);
 
        if (cdi->exit)
                cdi->exit(cdi);
@@ -3289,103 +3289,137 @@ static struct cdrom_sysctl_settings {
        int     check;                  /* check media type */
 } cdrom_sysctl_settings;
 
+enum cdrom_print_option {
+       CTL_NAME,
+       CTL_SPEED,
+       CTL_SLOTS,
+       CTL_CAPABILITY
+};
+
+static int cdrom_print_info(const char *header, int val, char *info,
+                               int *pos, enum cdrom_print_option option)
+{
+       const int max_size = sizeof(cdrom_sysctl_settings.info);
+       struct cdrom_device_info *cdi;
+       int ret;
+
+       ret = scnprintf(info + *pos, max_size - *pos, header);
+       if (!ret)
+               return 1;
+
+       *pos += ret;
+
+       for (cdi = topCdromPtr; cdi; cdi = cdi->next) {
+               switch (option) {
+               case CTL_NAME:
+                       ret = scnprintf(info + *pos, max_size - *pos,
+                                       "\t%s", cdi->name);
+                       break;
+               case CTL_SPEED:
+                       ret = scnprintf(info + *pos, max_size - *pos,
+                                       "\t%d", cdi->speed);
+                       break;
+               case CTL_SLOTS:
+                       ret = scnprintf(info + *pos, max_size - *pos,
+                                       "\t%d", cdi->capacity);
+                       break;
+               case CTL_CAPABILITY:
+                       ret = scnprintf(info + *pos, max_size - *pos,
+                                       "\t%d", CDROM_CAN(val) != 0);
+                       break;
+               default:
+                       printk(KERN_INFO "cdrom: invalid option%d\n", option);
+                       return 1;
+               }
+               if (!ret)
+                       return 1;
+               *pos += ret;
+       }
+
+       return 0;
+}
+
 static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
                            void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-        int pos;
-       struct cdrom_device_info *cdi;
+       int pos;
        char *info = cdrom_sysctl_settings.info;
+       const int max_size = sizeof(cdrom_sysctl_settings.info);
        
        if (!*lenp || (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }
 
+       mutex_lock(&cdrom_mutex);
+
        pos = sprintf(info, "CD-ROM information, " VERSION "\n");
        
-       pos += sprintf(info+pos, "\ndrive name:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%s", cdi->name);
-
-       pos += sprintf(info+pos, "\ndrive speed:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", cdi->speed);
-
-       pos += sprintf(info+pos, "\ndrive # of slots:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", cdi->capacity);
-
-       pos += sprintf(info+pos, "\nCan close tray:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0);
-
-       pos += sprintf(info+pos, "\nCan open tray:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0);
-
-       pos += sprintf(info+pos, "\nCan lock tray:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0);
-
-       pos += sprintf(info+pos, "\nCan change speed:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0);
-
-       pos += sprintf(info+pos, "\nCan select disk:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0);
-
-       pos += sprintf(info+pos, "\nCan read multisession:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0);
-
-       pos += sprintf(info+pos, "\nCan read MCN:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0);
-
-       pos += sprintf(info+pos, "\nReports media changed:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0);
-
-       pos += sprintf(info+pos, "\nCan play audio:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0);
-
-       pos += sprintf(info+pos, "\nCan write CD-R:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0);
-
-       pos += sprintf(info+pos, "\nCan write CD-RW:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0);
-
-       pos += sprintf(info+pos, "\nCan read DVD:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0);
-
-       pos += sprintf(info+pos, "\nCan write DVD-R:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0);
-
-       pos += sprintf(info+pos, "\nCan write DVD-RAM:");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0);
-
-       pos += sprintf(info+pos, "\nCan read MRW:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0);
-
-       pos += sprintf(info+pos, "\nCan write MRW:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0);
-
-       pos += sprintf(info+pos, "\nCan write RAM:\t");
-       for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-           pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0);
-
-       strcpy(info+pos,"\n\n");
-               
-        return proc_dostring(ctl, write, filp, buffer, lenp, ppos);
+       if (cdrom_print_info("\ndrive name:\t", 0, info, &pos, CTL_NAME))
+               goto done;
+       if (cdrom_print_info("\ndrive speed:\t", 0, info, &pos, CTL_SPEED))
+               goto done;
+       if (cdrom_print_info("\ndrive # of slots:", 0, info, &pos, CTL_SLOTS))
+               goto done;
+       if (cdrom_print_info("\nCan close tray:\t",
+                               CDC_CLOSE_TRAY, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan open tray:\t",
+                               CDC_OPEN_TRAY, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan lock tray:\t",
+                               CDC_LOCK, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan change speed:",
+                               CDC_SELECT_SPEED, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan select disk:",
+                               CDC_SELECT_DISC, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan read multisession:",
+                               CDC_MULTI_SESSION, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan read MCN:\t",
+                               CDC_MCN, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nReports media changed:",
+                               CDC_MEDIA_CHANGED, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan play audio:\t",
+                               CDC_PLAY_AUDIO, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan write CD-R:\t",
+                               CDC_CD_R, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan write CD-RW:",
+                               CDC_CD_RW, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan read DVD:\t",
+                               CDC_DVD, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan write DVD-R:",
+                               CDC_DVD_R, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan write DVD-RAM:",
+                               CDC_DVD_RAM, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan read MRW:\t",
+                               CDC_MRW, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan write MRW:\t",
+                               CDC_MRW_W, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (cdrom_print_info("\nCan write RAM:\t",
+                               CDC_RAM, info, &pos, CTL_CAPABILITY))
+               goto done;
+       if (!scnprintf(info + pos, max_size - pos, "\n\n"))
+               goto done;
+doit:
+       mutex_unlock(&cdrom_mutex);
+       return proc_dostring(ctl, write, filp, buffer, lenp, ppos);
+done:
+       printk(KERN_INFO "cdrom: info buffer too small\n");
+       goto doit;
 }
 
 /* Unfortunately, per device settings are not implemented through
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
deleted file mode 100644 (file)
index 2157c58..0000000
+++ /dev/null
@@ -1,3251 +0,0 @@
-/*
-* Sony CDU-31A CDROM interface device driver.
-*
-* Corey Minyard (minyard@wf-rch.cirr.com)
-*
-* Colossians 3:17
-*
-*  See Documentation/cdrom/cdu31a for additional details about this driver.
-* 
-* The Sony interface device driver handles Sony interface CDROM
-* drives and provides a complete block-level interface as well as an
-* ioctl() interface compatible with the Sun (as specified in
-* include/linux/cdrom.h).  With this interface, CDROMs can be
-* accessed and standard audio CDs can be played back normally.
-*
-* WARNING -    All autoprobes have been removed from the driver.
-*              You MUST configure the CDU31A via a LILO config
-*              at boot time or in lilo.conf.  I have the
-*              following in my lilo.conf:
-*
-*                append="cdu31a=0x1f88,0,PAS"
-*
-*              The first number is the I/O base address of the
-*              card.  The second is the interrupt (0 means none).
- *             The third should be "PAS" if on a Pro-Audio
- *             spectrum, or nothing if on something else.
- *
- * This interface is (unfortunately) a polled interface.  This is
- * because most Sony interfaces are set up with DMA and interrupts
- * disables.  Some (like mine) do not even have the capability to
- * handle interrupts or DMA.  For this reason you will see a lot of
- * the following:
- *
- *   retry_count = jiffies+ SONY_JIFFIES_TIMEOUT;
- *   while (time_before(jiffies, retry_count) && (! <some condition to wait for))
- *   {
- *      while (handle_sony_cd_attention())
- *         ;
- *
- *      sony_sleep();
- *   }
- *   if (the condition not met)
- *   {
- *      return an error;
- *   }
- *
- * This ugly hack waits for something to happen, sleeping a little
- * between every try.  it also handles attentions, which are
- * asynchronous events from the drive informing the driver that a disk
- * has been inserted, removed, etc.
- *
- * NEWS FLASH - The driver now supports interrupts but they are
- * turned off by default.  Use of interrupts is highly encouraged, it
- * cuts CPU usage down to a reasonable level.  I had DMA in for a while
- * but PC DMA is just too slow.  Better to just insb() it.
- *
- * One thing about these drives: They talk in MSF (Minute Second Frame) format.
- * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a
- * disk.  The funny thing is that these are sent to the drive in BCD, but the
- * interface wants to see them in decimal.  A lot of conversion goes on.
- *
- * DRIVER SPECIAL FEATURES
- * -----------------------
- *
- * This section describes features beyond the normal audio and CD-ROM
- * functions of the drive.
- *
- * XA compatibility
- *
- * The driver should support XA disks for both the CDU31A and CDU33A.
- * It does this transparently, the using program doesn't need to set it.
- *
- * Multi-Session
- *
- * A multi-session disk looks just like a normal disk to the user.
- * Just mount one normally, and all the data should be there.
- * A special thanks to Koen for help with this!
- * 
- * Raw sector I/O
- *
- * Using the CDROMREADAUDIO it is possible to read raw audio and data
- * tracks.  Both operations return 2352 bytes per sector.  On the data
- * tracks, the first 12 bytes is not returned by the drive and the value
- * of that data is indeterminate.
- *
- *
- *  Copyright (C) 1993  Corey Minyard
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * TODO: 
- *       CDs with form1 and form2 sectors cause problems
- *       with current read-ahead strategy.
- *
- * Credits:
- *    Heiko Eissfeldt <heiko@colossus.escape.de>
- *         For finding abug in the return of the track numbers.
- *         TOC processing redone for proper multisession support.
- *
- *
- *  It probably a little late to be adding a history, but I guess I
- *  will start.
- *
- *  10/24/95 - Added support for disabling the eject button when the
- *             drive is open.  Note that there is a small problem
- *             still here, if the eject button is pushed while the
- *             drive light is flashing, the drive will return a bad
- *             status and be reset.  It recovers, though.
- *
- *  03/07/97 - Fixed a problem with timers.
- *
- *
- *  18 Spetember 1997 -- Ported to Uniform CD-ROM driver by 
- *                 Heiko Eissfeldt <heiko@colossus.escape.de> with additional
- *                 changes by Erik Andersen <andersee@debian.org>
- *
- *  24 January 1998 -- Removed the scd_disc_status() function, which was now
- *                     just dead code left over from the port.
- *                          Erik Andersen <andersee@debian.org>
- *
- *  16 July 1998 -- Drive donated to Erik Andersen by John Kodis
- *                   <kodis@jagunet.com>.  Work begun on fixing driver to
- *                   work under 2.1.X.  Added temporary extra printks
- *                   which seem to slow it down enough to work.
- *
- *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                    Removed init_module & cleanup_module in favor of 
- *                    module_init & module_exit.
- *                    Torben Mathiasen <tmm@image.dk>
- *
- * 22 October 2004 -- Make the driver work in 2.6.X
- *                   Added workaround to fix hard lockups on eject
- *                   Fixed door locking problem after mounting empty drive
- *                   Set double-speed drives to double speed by default
- *                   Removed all readahead things - not needed anymore
- *                     Ondrej Zary <rainbow@rainbow-software.org>
-*/
-
-#define DEBUG 1
-
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/cdrom.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/dma.h>
-
-#include "cdu31a.h"
-
-#define MAJOR_NR CDU31A_CDROM_MAJOR
-#include <linux/blkdev.h>
-
-#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
-
-#define PFX "CDU31A: "
-
-/*
-** Edit the following data to change interrupts, DMA channels, etc.
-** Default is polled and no DMA.  DMA is not recommended for double-speed
-** drives.
-*/
-static struct {
-       unsigned short base;    /* I/O Base Address */
-       short int_num;          /* Interrupt Number (-1 means scan for it,
-                                  0 means don't use) */
-} cdu31a_addresses[] __initdata = {
-       {0}
-};
-
-static int handle_sony_cd_attention(void);
-static int read_subcode(void);
-static void sony_get_toc(void);
-static int scd_spinup(void);
-/*static int scd_open(struct inode *inode, struct file *filp);*/
-static int scd_open(struct cdrom_device_info *, int);
-static void do_sony_cd_cmd(unsigned char cmd,
-                          unsigned char *params,
-                          unsigned int num_params,
-                          unsigned char *result_buffer,
-                          unsigned int *result_size);
-static void size_to_buf(unsigned int size, unsigned char *buf);
-
-/* Parameters for the read-ahead. */
-static unsigned int sony_next_block;   /* Next 512 byte block offset */
-static unsigned int sony_blocks_left = 0;      /* Number of 512 byte blocks left
-                                                  in the current read command. */
-
-
-/* The base I/O address of the Sony Interface.  This is a variable (not a
-   #define) so it can be easily changed via some future ioctl() */
-static unsigned int cdu31a_port = 0;
-module_param(cdu31a_port, uint, 0);
-
-/*
- * The following are I/O addresses of the various registers for the drive.  The
- * comment for the base address also applies here.
- */
-static volatile unsigned short sony_cd_cmd_reg;
-static volatile unsigned short sony_cd_param_reg;
-static volatile unsigned short sony_cd_write_reg;
-static volatile unsigned short sony_cd_control_reg;
-static volatile unsigned short sony_cd_status_reg;
-static volatile unsigned short sony_cd_result_reg;
-static volatile unsigned short sony_cd_read_reg;
-static volatile unsigned short sony_cd_fifost_reg;
-
-static struct request_queue *cdu31a_queue;
-static DEFINE_SPINLOCK(cdu31a_lock); /* queue lock */
-
-static int sony_spun_up = 0;   /* Has the drive been spun up? */
-
-static int sony_speed = 0;     /* Last wanted speed */
-
-static int sony_xa_mode = 0;   /* Is an XA disk in the drive
-                                  and the drive a CDU31A? */
-
-static int sony_raw_data_mode = 1;     /* 1 if data tracks, 0 if audio.
-                                          For raw data reads. */
-
-static unsigned int sony_usage = 0;    /* How many processes have the
-                                          drive open. */
-
-static int sony_pas_init = 0;  /* Initialize the Pro-Audio
-                                  Spectrum card? */
-
-static struct s_sony_session_toc single_toc;   /* Holds the
-                                                  table of
-                                                  contents. */
-
-static struct s_all_sessions_toc sony_toc;     /* entries gathered from all
-                                                  sessions */
-
-static int sony_toc_read = 0;  /* Has the TOC been read for
-                                  the drive? */
-
-static struct s_sony_subcode last_sony_subcode;        /* Points to the last
-                                                  subcode address read */
-
-static DECLARE_MUTEX(sony_sem);                /* Semaphore for drive hardware access */
-
-static int is_double_speed = 0;        /* does the drive support double speed ? */
-
-static int is_auto_eject = 1;  /* Door has been locked? 1=No/0=Yes */
-
-/*
- * The audio status uses the values from read subchannel data as specified
- * in include/linux/cdrom.h.
- */
-static volatile int sony_audio_status = CDROM_AUDIO_NO_STATUS;
-
-/*
- * The following are a hack for pausing and resuming audio play.  The drive
- * does not work as I would expect it, if you stop it then start it again,
- * the drive seeks back to the beginning and starts over.  This holds the
- * position during a pause so a resume can restart it.  It uses the
- * audio status variable above to tell if it is paused.
- */
-static unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 };
-static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 };
-
-/* What IRQ is the drive using?  0 if none. */
-static int cdu31a_irq = 0;
-module_param(cdu31a_irq, int, 0);
-
-/* The interrupt handler will wake this queue up when it gets an
-   interrupts. */
-static DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait);
-static int irq_flag = 0;
-
-static int curr_control_reg = 0;       /* Current value of the control register */
-
-/* A disk changed variable.  When a disk change is detected, it will
-   all be set to TRUE.  As the upper layers ask for disk_changed status
-   it will be cleared. */
-static char disk_changed;
-
-/* This was readahead_buffer once... Now it's used only for audio reads */
-static char audio_buffer[CD_FRAMESIZE_RAW];
-
-/* Used to time a short period to abort an operation after the
-   drive has been idle for a while.  This keeps the light on
-   the drive from flashing for very long. */
-static struct timer_list cdu31a_abort_timer;
-
-/* Marks if the timeout has started an abort read.  This is used
-   on entry to the drive to tell the code to read out the status
-   from the abort read. */
-static int abort_read_started = 0;
-
-/*
- * Uniform cdrom interface function
- * report back, if disc has changed from time of last request.
- */
-static int scd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-{
-       int retval;
-
-       retval = disk_changed;
-       disk_changed = 0;
-
-       return retval;
-}
-
-/*
- * Uniform cdrom interface function
- * report back, if drive is ready
- */
-static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
-       if (CDSL_CURRENT != slot_nr)
-               /* we have no changer support */
-               return -EINVAL;
-       if (sony_spun_up)
-               return CDS_DISC_OK;
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       if (scd_spinup() == 0)
-               sony_spun_up = 1;
-       up(&sony_sem);
-       return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;
-}
-
-static inline void enable_interrupts(void)
-{
-       curr_control_reg |= (SONY_ATTN_INT_EN_BIT
-                            | SONY_RES_RDY_INT_EN_BIT
-                            | SONY_DATA_RDY_INT_EN_BIT);
-       outb(curr_control_reg, sony_cd_control_reg);
-}
-
-static inline void disable_interrupts(void)
-{
-       curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT
-                             | SONY_RES_RDY_INT_EN_BIT
-                             | SONY_DATA_RDY_INT_EN_BIT);
-       outb(curr_control_reg, sony_cd_control_reg);
-}
-
-/*
- * Wait a little while (used for polling the drive).  If in initialization,
- * setting a timeout doesn't work, so just loop for a while.
- */
-static inline void sony_sleep(void)
-{
-       if (cdu31a_irq <= 0) {
-               yield();
-       } else {                /* Interrupt driven */
-               DEFINE_WAIT(w);
-               int first = 1;
-
-               while (1) {
-                       prepare_to_wait(&cdu31a_irq_wait, &w,
-                                       TASK_INTERRUPTIBLE);
-                       if (first) {
-                               enable_interrupts();
-                               first = 0;
-                       }
-
-                       if (irq_flag != 0)
-                               break;
-                       if (!signal_pending(current)) {
-                               schedule();
-                               continue;
-                       } else
-                               disable_interrupts();
-                       break;
-               }
-               finish_wait(&cdu31a_irq_wait, &w);
-               irq_flag = 0;
-       }
-}
-
-
-/*
- * The following are convenience routine to read various status and set
- * various conditions in the drive.
- */
-static inline int is_attention(void)
-{
-       return (inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0;
-}
-
-static inline int is_busy(void)
-{
-       return (inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0;
-}
-
-static inline int is_data_ready(void)
-{
-       return (inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0;
-}
-
-static inline int is_data_requested(void)
-{
-       return (inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0;
-}
-
-static inline int is_result_ready(void)
-{
-       return (inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0;
-}
-
-static inline int is_param_write_rdy(void)
-{
-       return (inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0;
-}
-
-static inline int is_result_reg_not_empty(void)
-{
-       return (inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0;
-}
-
-static inline void reset_drive(void)
-{
-       curr_control_reg = 0;
-       sony_toc_read = 0;
-       outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg);
-}
-
-/*
- * Uniform cdrom interface function
- * reset drive and return when it is ready
- */
-static int scd_reset(struct cdrom_device_info *cdi)
-{
-       unsigned long retry_count;
-
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       reset_drive();
-
-       retry_count = jiffies + SONY_RESET_TIMEOUT;
-       while (time_before(jiffies, retry_count) && (!is_attention())) {
-               sony_sleep();
-       }
-
-       up(&sony_sem);
-       return 0;
-}
-
-static inline void clear_attention(void)
-{
-       outb(curr_control_reg | SONY_ATTN_CLR_BIT, sony_cd_control_reg);
-}
-
-static inline void clear_result_ready(void)
-{
-       outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg);
-}
-
-static inline void clear_data_ready(void)
-{
-       outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT,
-            sony_cd_control_reg);
-}
-
-static inline void clear_param_reg(void)
-{
-       outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg);
-}
-
-static inline unsigned char read_status_register(void)
-{
-       return inb(sony_cd_status_reg);
-}
-
-static inline unsigned char read_result_register(void)
-{
-       return inb(sony_cd_result_reg);
-}
-
-static inline unsigned char read_data_register(void)
-{
-       return inb(sony_cd_read_reg);
-}
-
-static inline void write_param(unsigned char param)
-{
-       outb(param, sony_cd_param_reg);
-}
-
-static inline void write_cmd(unsigned char cmd)
-{
-       outb(curr_control_reg | SONY_RES_RDY_INT_EN_BIT,
-            sony_cd_control_reg);
-       outb(cmd, sony_cd_cmd_reg);
-}
-
-static irqreturn_t cdu31a_interrupt(int irq, void *dev_id)
-{
-       unsigned char val;
-
-       if (abort_read_started) {
-               /* We might be waiting for an abort to finish.  Don't
-                  disable interrupts yet, though, because we handle
-                  this one here. */
-               /* Clear out the result registers. */
-               while (is_result_reg_not_empty()) {
-                       val = read_result_register();
-               }
-               clear_data_ready();
-               clear_result_ready();
-
-               /* Clear out the data */
-               while (is_data_requested()) {
-                       val = read_data_register();
-               }
-               abort_read_started = 0;
-
-               /* If something was waiting, wake it up now. */
-               if (waitqueue_active(&cdu31a_irq_wait)) {
-                       disable_interrupts();
-                       irq_flag = 1;
-                       wake_up_interruptible(&cdu31a_irq_wait);
-               }
-       } else if (waitqueue_active(&cdu31a_irq_wait)) {
-               disable_interrupts();
-               irq_flag = 1;
-               wake_up_interruptible(&cdu31a_irq_wait);
-       } else {
-               disable_interrupts();
-               printk(KERN_NOTICE PFX
-                               "Got an interrupt but nothing was waiting\n");
-       }
-       return IRQ_HANDLED;
-}
-
-/*
- * give more verbose error messages
- */
-static unsigned char *translate_error(unsigned char err_code)
-{
-       static unsigned char errbuf[80];
-
-       switch (err_code) {
-               case 0x10: return "illegal command ";
-               case 0x11: return "illegal parameter ";
-
-               case 0x20: return "not loaded ";
-               case 0x21: return "no disc ";
-               case 0x22: return "not spinning ";
-               case 0x23: return "spinning ";
-               case 0x25: return "spindle servo ";
-               case 0x26: return "focus servo ";
-               case 0x29: return "eject mechanism ";
-               case 0x2a: return "audio playing ";
-               case 0x2c: return "emergency eject ";
-
-               case 0x30: return "focus ";
-               case 0x31: return "frame sync ";
-               case 0x32: return "subcode address ";
-               case 0x33: return "block sync ";
-               case 0x34: return "header address ";
-
-               case 0x40: return "illegal track read ";
-               case 0x41: return "mode 0 read ";
-               case 0x42: return "illegal mode read ";
-               case 0x43: return "illegal block size read ";
-               case 0x44: return "mode read ";
-               case 0x45: return "form read ";
-               case 0x46: return "leadout read ";
-               case 0x47: return "buffer overrun ";
-
-               case 0x53: return "unrecoverable CIRC ";
-               case 0x57: return "unrecoverable LECC ";
-
-               case 0x60: return "no TOC ";
-               case 0x61: return "invalid subcode data ";
-               case 0x63: return "focus on TOC read ";
-               case 0x64: return "frame sync on TOC read ";
-               case 0x65: return "TOC data ";
-
-               case 0x70: return "hardware failure ";
-               case 0x91: return "leadin ";
-               case 0x92: return "leadout ";
-               case 0x93: return "data track ";
-       }
-       sprintf(errbuf, "unknown 0x%02x ", err_code);
-       return errbuf;
-}
-
-/*
- * Set the drive parameters so the drive will auto-spin-up when a
- * disk is inserted.
- */
-static void set_drive_params(int want_doublespeed)
-{
-       unsigned char res_reg[12];
-       unsigned int res_size;
-       unsigned char params[3];
-
-
-       params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME;
-       params[1] = 0x00;       /* Never spin down the drive. */
-       do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                      params, 2, res_reg, &res_size);
-       if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-               printk(KERN_NOTICE PFX
-                       "Unable to set spin-down time: 0x%2.2x\n", res_reg[1]);
-       }
-
-       params[0] = SONY_SD_MECH_CONTROL;
-       params[1] = SONY_AUTO_SPIN_UP_BIT;      /* Set auto spin up */
-
-       if (is_auto_eject)
-               params[1] |= SONY_AUTO_EJECT_BIT;
-
-       if (is_double_speed && want_doublespeed) {
-               params[1] |= SONY_DOUBLE_SPEED_BIT;     /* Set the drive to double speed if 
-                                                          possible */
-       }
-       do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                      params, 2, res_reg, &res_size);
-       if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-               printk(KERN_NOTICE PFX "Unable to set mechanical "
-                               "parameters: 0x%2.2x\n", res_reg[1]);
-       }
-}
-
-/*
- * Uniform cdrom interface function
- * select reading speed for data access
- */
-static int scd_select_speed(struct cdrom_device_info *cdi, int speed)
-{
-       if (speed == 0)
-               sony_speed = 1;
-       else
-               sony_speed = speed - 1;
-
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       set_drive_params(sony_speed);
-       up(&sony_sem);
-       return 0;
-}
-
-/*
- * Uniform cdrom interface function
- * lock or unlock eject button
- */
-static int scd_lock_door(struct cdrom_device_info *cdi, int lock)
-{
-       if (lock == 0) {
-               is_auto_eject = 1;
-       } else {
-               is_auto_eject = 0;
-       }
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       set_drive_params(sony_speed);
-       up(&sony_sem);
-       return 0;
-}
-
-/*
- * This code will reset the drive and attempt to restore sane parameters.
- */
-static void restart_on_error(void)
-{
-       unsigned char res_reg[12];
-       unsigned int res_size;
-       unsigned long retry_count;
-
-
-       printk(KERN_NOTICE PFX "Resetting drive on error\n");
-       reset_drive();
-       retry_count = jiffies + SONY_RESET_TIMEOUT;
-       while (time_before(jiffies, retry_count) && (!is_attention())) {
-               sony_sleep();
-       }
-       set_drive_params(sony_speed);
-       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
-       if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-               printk(KERN_NOTICE PFX "Unable to spin up drive: 0x%2.2x\n",
-                      res_reg[1]);
-       }
-
-       msleep(2000);
-
-       sony_get_toc();
-}
-
-/*
- * This routine writes data to the parameter register.  Since this should
- * happen fairly fast, it is polled with no OS waits between.
- */
-static int write_params(unsigned char *params, int num_params)
-{
-       unsigned int retry_count;
-
-
-       retry_count = SONY_READY_RETRIES;
-       while ((retry_count > 0) && (!is_param_write_rdy())) {
-               retry_count--;
-       }
-       if (!is_param_write_rdy()) {
-               return -EIO;
-       }
-
-       while (num_params > 0) {
-               write_param(*params);
-               params++;
-               num_params--;
-       }
-
-       return 0;
-}
-
-
-/*
- * The following reads data from the command result register.  It is a
- * fairly complex routine, all status info flows back through this
- * interface.  The algorithm is stolen directly from the flowcharts in
- * the drive manual.
- */
-static void
-get_result(unsigned char *result_buffer, unsigned int *result_size)
-{
-       unsigned char a, b;
-       int i;
-       unsigned long retry_count;
-
-
-       while (handle_sony_cd_attention());
-       /* Wait for the result data to be ready */
-       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-       while (time_before(jiffies, retry_count)
-              && (is_busy() || (!(is_result_ready())))) {
-               sony_sleep();
-
-               while (handle_sony_cd_attention());
-       }
-       if (is_busy() || (!(is_result_ready()))) {
-               pr_debug(PFX "timeout out %d\n", __LINE__);
-               result_buffer[0] = 0x20;
-               result_buffer[1] = SONY_TIMEOUT_OP_ERR;
-               *result_size = 2;
-               return;
-       }
-
-       /*
-        * Get the first two bytes.  This determines what else needs
-        * to be done.
-        */
-       clear_result_ready();
-       a = read_result_register();
-       *result_buffer = a;
-       result_buffer++;
-
-       /* Check for block error status result. */
-       if ((a & 0xf0) == 0x50) {
-               *result_size = 1;
-               return;
-       }
-
-       b = read_result_register();
-       *result_buffer = b;
-       result_buffer++;
-       *result_size = 2;
-
-       /*
-        * 0x20 means an error occurred.  Byte 2 will have the error code.
-        * Otherwise, the command succeeded, byte 2 will have the count of
-        * how many more status bytes are coming.
-        *
-        * The result register can be read 10 bytes at a time, a wait for
-        * result ready to be asserted must be done between every 10 bytes.
-        */
-       if ((a & 0xf0) != 0x20) {
-               if (b > 8) {
-                       for (i = 0; i < 8; i++) {
-                               *result_buffer = read_result_register();
-                               result_buffer++;
-                               (*result_size)++;
-                       }
-                       b = b - 8;
-
-                       while (b > 10) {
-                               retry_count = SONY_READY_RETRIES;
-                               while ((retry_count > 0)
-                                      && (!is_result_ready())) {
-                                       retry_count--;
-                               }
-                               if (!is_result_ready()) {
-                                       pr_debug(PFX "timeout out %d\n",
-                                              __LINE__);
-                                       result_buffer[0] = 0x20;
-                                       result_buffer[1] =
-                                           SONY_TIMEOUT_OP_ERR;
-                                       *result_size = 2;
-                                       return;
-                               }
-
-                               clear_result_ready();
-
-                               for (i = 0; i < 10; i++) {
-                                       *result_buffer =
-                                           read_result_register();
-                                       result_buffer++;
-                                       (*result_size)++;
-                               }
-                               b = b - 10;
-                       }
-
-                       if (b > 0) {
-                               retry_count = SONY_READY_RETRIES;
-                               while ((retry_count > 0)
-                                      && (!is_result_ready())) {
-                                       retry_count--;
-                               }
-                               if (!is_result_ready()) {
-                                       pr_debug(PFX "timeout out %d\n",
-                                              __LINE__);
-                                       result_buffer[0] = 0x20;
-                                       result_buffer[1] =
-                                           SONY_TIMEOUT_OP_ERR;
-                                       *result_size = 2;
-                                       return;
-                               }
-                       }
-               }
-
-               while (b > 0) {
-                       *result_buffer = read_result_register();
-                       result_buffer++;
-                       (*result_size)++;
-                       b--;
-               }
-       }
-}
-
-/*
- * Do a command that does not involve data transfer.  This routine must
- * be re-entrant from the same task to support being called from the
- * data operation code when an error occurs.
- */
-static void
-do_sony_cd_cmd(unsigned char cmd,
-              unsigned char *params,
-              unsigned int num_params,
-              unsigned char *result_buffer, unsigned int *result_size)
-{
-       unsigned long retry_count;
-       int num_retries = 0;
-
-retry_cd_operation:
-
-       while (handle_sony_cd_attention());
-
-       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-       while (time_before(jiffies, retry_count) && (is_busy())) {
-               sony_sleep();
-
-               while (handle_sony_cd_attention());
-       }
-       if (is_busy()) {
-               pr_debug(PFX "timeout out %d\n", __LINE__);
-               result_buffer[0] = 0x20;
-               result_buffer[1] = SONY_TIMEOUT_OP_ERR;
-               *result_size = 2;
-       } else {
-               clear_result_ready();
-               clear_param_reg();
-
-               write_params(params, num_params);
-               write_cmd(cmd);
-
-               get_result(result_buffer, result_size);
-       }
-
-       if (((result_buffer[0] & 0xf0) == 0x20)
-           && (num_retries < MAX_CDU31A_RETRIES)) {
-               num_retries++;
-               msleep(100);
-               goto retry_cd_operation;
-       }
-}
-
-
-/*
- * Handle an attention from the drive.  This will return 1 if it found one
- * or 0 if not (if one is found, the caller might want to call again).
- *
- * This routine counts the number of consecutive times it is called
- * (since this is always called from a while loop until it returns
- * a 0), and returns a 0 if it happens too many times.  This will help
- * prevent a lockup.
- */
-static int handle_sony_cd_attention(void)
-{
-       unsigned char atten_code;
-       static int num_consecutive_attentions = 0;
-       volatile int val;
-
-
-#if 0
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-#endif
-       if (is_attention()) {
-               if (num_consecutive_attentions >
-                   CDU31A_MAX_CONSECUTIVE_ATTENTIONS) {
-                       printk(KERN_NOTICE PFX "Too many consecutive "
-                               "attentions: %d\n", num_consecutive_attentions);
-                       num_consecutive_attentions = 0;
-                       pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__,
-                              __LINE__);
-                       return 0;
-               }
-
-               clear_attention();
-               atten_code = read_result_register();
-
-               switch (atten_code) {
-                       /* Someone changed the CD.  Mark it as changed */
-               case SONY_MECH_LOADED_ATTN:
-                       disk_changed = 1;
-                       sony_toc_read = 0;
-                       sony_audio_status = CDROM_AUDIO_NO_STATUS;
-                       sony_blocks_left = 0;
-                       break;
-
-               case SONY_SPIN_DOWN_COMPLETE_ATTN:
-                       /* Mark the disk as spun down. */
-                       sony_spun_up = 0;
-                       break;
-
-               case SONY_AUDIO_PLAY_DONE_ATTN:
-                       sony_audio_status = CDROM_AUDIO_COMPLETED;
-                       read_subcode();
-                       break;
-
-               case SONY_EJECT_PUSHED_ATTN:
-                       if (is_auto_eject) {
-                               sony_audio_status = CDROM_AUDIO_INVALID;
-                       }
-                       break;
-
-               case SONY_LEAD_IN_ERR_ATTN:
-               case SONY_LEAD_OUT_ERR_ATTN:
-               case SONY_DATA_TRACK_ERR_ATTN:
-               case SONY_AUDIO_PLAYBACK_ERR_ATTN:
-                       sony_audio_status = CDROM_AUDIO_ERROR;
-                       break;
-               }
-
-               num_consecutive_attentions++;
-               pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-               return 1;
-       } else if (abort_read_started) {
-               while (is_result_reg_not_empty()) {
-                       val = read_result_register();
-               }
-               clear_data_ready();
-               clear_result_ready();
-               /* Clear out the data */
-               while (is_data_requested()) {
-                       val = read_data_register();
-               }
-               abort_read_started = 0;
-               pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-               return 1;
-       }
-
-       num_consecutive_attentions = 0;
-#if 0
-       pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-#endif
-       return 0;
-}
-
-
-/* Convert from an integer 0-99 to BCD */
-static inline unsigned int int_to_bcd(unsigned int val)
-{
-       int retval;
-
-
-       retval = (val / 10) << 4;
-       retval = retval | val % 10;
-       return retval;
-}
-
-
-/* Convert from BCD to an integer from 0-99 */
-static unsigned int bcd_to_int(unsigned int bcd)
-{
-       return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f);
-}
-
-
-/*
- * Convert a logical sector value (like the OS would want to use for
- * a block device) to an MSF format.
- */
-static void log_to_msf(unsigned int log, unsigned char *msf)
-{
-       log = log + LOG_START_OFFSET;
-       msf[0] = int_to_bcd(log / 4500);
-       log = log % 4500;
-       msf[1] = int_to_bcd(log / 75);
-       msf[2] = int_to_bcd(log % 75);
-}
-
-
-/*
- * Convert an MSF format to a logical sector.
- */
-static unsigned int msf_to_log(unsigned char *msf)
-{
-       unsigned int log;
-
-
-       log = msf[2];
-       log += msf[1] * 75;
-       log += msf[0] * 4500;
-       log = log - LOG_START_OFFSET;
-
-       return log;
-}
-
-
-/*
- * Take in integer size value and put it into a buffer like
- * the drive would want to see a number-of-sector value.
- */
-static void size_to_buf(unsigned int size, unsigned char *buf)
-{
-       buf[0] = size / 65536;
-       size = size % 65536;
-       buf[1] = size / 256;
-       buf[2] = size % 256;
-}
-
-/* Starts a read operation. Returns 0 on success and 1 on failure. 
-   The read operation used here allows multiple sequential sectors 
-   to be read and status returned for each sector.  The driver will
-   read the output one at a time as the requests come and abort the
-   operation if the requested sector is not the next one from the
-   drive. */
-static int
-start_request(unsigned int sector, unsigned int nsect)
-{
-       unsigned char params[6];
-       unsigned long retry_count;
-
-
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-       log_to_msf(sector, params);
-       size_to_buf(nsect, &params[3]);
-
-       /*
-        * Clear any outstanding attentions and wait for the drive to
-        * complete any pending operations.
-        */
-       while (handle_sony_cd_attention());
-
-       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-       while (time_before(jiffies, retry_count) && (is_busy())) {
-               sony_sleep();
-
-               while (handle_sony_cd_attention());
-       }
-
-       if (is_busy()) {
-               printk(KERN_NOTICE PFX "Timeout while waiting "
-                               "to issue command\n");
-               pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-               return 1;
-       } else {
-               /* Issue the command */
-               clear_result_ready();
-               clear_param_reg();
-
-               write_params(params, 6);
-               write_cmd(SONY_READ_BLKERR_STAT_CMD);
-
-               sony_blocks_left = nsect * 4;
-               sony_next_block = sector * 4;
-               pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-               return 0;
-       }
-       pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-}
-
-/* Abort a pending read operation.  Clear all the drive status variables. */
-static void abort_read(void)
-{
-       unsigned char result_reg[2];
-       int result_size;
-       volatile int val;
-
-
-       do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size);
-       if ((result_reg[0] & 0xf0) == 0x20) {
-               printk(KERN_ERR PFX "Aborting read, %s error\n",
-                      translate_error(result_reg[1]));
-       }
-
-       while (is_result_reg_not_empty()) {
-               val = read_result_register();
-       }
-       clear_data_ready();
-       clear_result_ready();
-       /* Clear out the data */
-       while (is_data_requested()) {
-               val = read_data_register();
-       }
-
-       sony_blocks_left = 0;
-}
-
-/* Called when the timer times out.  This will abort the
-   pending read operation. */
-static void handle_abort_timeout(unsigned long data)
-{
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-       /* If it is in use, ignore it. */
-       if (down_trylock(&sony_sem) == 0) {
-               /* We can't use abort_read(), because it will sleep
-                  or schedule in the timer interrupt.  Just start
-                  the operation, finish it on the next access to
-                  the drive. */
-               clear_result_ready();
-               clear_param_reg();
-               write_cmd(SONY_ABORT_CMD);
-
-               sony_blocks_left = 0;
-               abort_read_started = 1;
-               up(&sony_sem);
-       }
-       pr_debug(PFX "Leaving %s\n", __FUNCTION__);
-}
-
-/* Actually get one sector of data from the drive. */
-static void
-input_data_sector(char *buffer)
-{
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-
-       /* If an XA disk on a CDU31A, skip the first 12 bytes of data from
-          the disk.  The real data is after that. We can use audio_buffer. */
-       if (sony_xa_mode)
-               insb(sony_cd_read_reg, audio_buffer, CD_XA_HEAD);
-
-       clear_data_ready();
-
-       insb(sony_cd_read_reg, buffer, 2048);
-
-       /* If an XA disk, we have to clear out the rest of the unused
-          error correction data. We can use audio_buffer for that. */
-       if (sony_xa_mode)
-               insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL);
-
-       pr_debug(PFX "Leaving %s\n", __FUNCTION__);
-}
-
-/* read data from the drive.  Note the nsect must be <= 4. */
-static void
-read_data_block(char *buffer,
-               unsigned int block,
-               unsigned int nblocks,
-               unsigned char res_reg[], int *res_size)
-{
-       unsigned long retry_count;
-
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-
-       res_reg[0] = 0;
-       res_reg[1] = 0;
-       *res_size = 0;
-
-       /* Wait for the drive to tell us we have something */
-       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-       while (time_before(jiffies, retry_count) && !(is_data_ready())) {
-               while (handle_sony_cd_attention());
-
-               sony_sleep();
-       }
-       if (!(is_data_ready())) {
-               if (is_result_ready()) {
-                       get_result(res_reg, res_size);
-                       if ((res_reg[0] & 0xf0) != 0x20) {
-                               printk(KERN_NOTICE PFX "Got result that should"
-                                       " have been error: %d\n", res_reg[0]);
-                               res_reg[0] = 0x20;
-                               res_reg[1] = SONY_BAD_DATA_ERR;
-                               *res_size = 2;
-                       }
-                       abort_read();
-               } else {
-                       pr_debug(PFX "timeout out %d\n", __LINE__);
-                       res_reg[0] = 0x20;
-                       res_reg[1] = SONY_TIMEOUT_OP_ERR;
-                       *res_size = 2;
-                       abort_read();
-               }
-       } else {
-               input_data_sector(buffer);
-               sony_blocks_left -= nblocks;
-               sony_next_block += nblocks;
-
-               /* Wait for the status from the drive. */
-               retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-               while (time_before(jiffies, retry_count)
-                      && !(is_result_ready())) {
-                       while (handle_sony_cd_attention());
-
-                       sony_sleep();
-               }
-
-               if (!is_result_ready()) {
-                       pr_debug(PFX "timeout out %d\n", __LINE__);
-                       res_reg[0] = 0x20;
-                       res_reg[1] = SONY_TIMEOUT_OP_ERR;
-                       *res_size = 2;
-                       abort_read();
-               } else {
-                       get_result(res_reg, res_size);
-
-                       /* If we got a buffer status, handle that. */
-                       if ((res_reg[0] & 0xf0) == 0x50) {
-
-                               if ((res_reg[0] ==
-                                    SONY_NO_CIRC_ERR_BLK_STAT)
-                                   || (res_reg[0] ==
-                                       SONY_NO_LECC_ERR_BLK_STAT)
-                                   || (res_reg[0] ==
-                                       SONY_RECOV_LECC_ERR_BLK_STAT)) {
-                                       /* nothing here */
-                               } else {
-                                       printk(KERN_ERR PFX "Data block "
-                                               "error: 0x%x\n", res_reg[0]);
-                                       res_reg[0] = 0x20;
-                                       res_reg[1] = SONY_BAD_DATA_ERR;
-                                       *res_size = 2;
-                               }
-
-                               /* Final transfer is done for read command, get final result. */
-                               if (sony_blocks_left == 0) {
-                                       get_result(res_reg, res_size);
-                               }
-                       } else if ((res_reg[0] & 0xf0) != 0x20) {
-                               /* The drive gave me bad status, I don't know what to do.
-                                  Reset the driver and return an error. */
-                               printk(KERN_ERR PFX "Invalid block "
-                                       "status: 0x%x\n", res_reg[0]);
-                               restart_on_error();
-                               res_reg[0] = 0x20;
-                               res_reg[1] = SONY_BAD_DATA_ERR;
-                               *res_size = 2;
-                       }
-               }
-       }
-       pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-}
-
-
-/*
- * The OS calls this to perform a read or write operation to the drive.
- * Write obviously fail.  Reads to a read ahead of sony_buffer_size
- * bytes to help speed operations.  This especially helps since the OS
- * uses 1024 byte blocks and the drive uses 2048 byte blocks.  Since most
- * data access on a CD is done sequentially, this saves a lot of operations.
- */
-static void do_cdu31a_request(request_queue_t * q)
-{
-       struct request *req;
-       int block, nblock, num_retries;
-       unsigned char res_reg[12];
-       unsigned int res_size;
-
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-
-       spin_unlock_irq(q->queue_lock);
-       if (down_interruptible(&sony_sem)) {
-               spin_lock_irq(q->queue_lock);
-               return;
-       }
-
-       /* Get drive status before doing anything. */
-       while (handle_sony_cd_attention());
-
-       /* Make sure we have a valid TOC. */
-       sony_get_toc();
-
-
-       /* Make sure the timer is cancelled. */
-       del_timer(&cdu31a_abort_timer);
-
-       while (1) {
-               /*
-                * The beginning here is stolen from the hard disk driver.  I hope
-                * it's right.
-                */
-               req = elv_next_request(q);
-               if (!req)
-                       goto end_do_cdu31a_request;
-
-               if (!sony_spun_up)
-                       scd_spinup();
-
-               block = req->sector;
-               nblock = req->nr_sectors;
-               pr_debug(PFX "request at block %d, length %d blocks\n",
-                       block, nblock);
-               if (!sony_toc_read) {
-                       printk(KERN_NOTICE PFX "TOC not read\n");
-                       end_request(req, 0);
-                       continue;
-               }
-
-               /* WTF??? */
-               if (!blk_fs_request(req)) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (rq_data_dir(req) == WRITE) {
-                       end_request(req, 0);
-                       continue;
-               }
-
-               /*
-                * If the block address is invalid or the request goes beyond the end of
-                * the media, return an error.
-                */
-               if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) {
-                       printk(KERN_NOTICE PFX "Request past end of media\n");
-                       end_request(req, 0);
-                       continue;
-               }
-
-               if (nblock > 4)
-                       nblock = 4;
-               num_retries = 0;
-
-       try_read_again:
-               while (handle_sony_cd_attention());
-
-               if (!sony_toc_read) {
-                       printk(KERN_NOTICE PFX "TOC not read\n");
-                       end_request(req, 0);
-                       continue;
-               }
-
-               /* If no data is left to be read from the drive, start the
-                  next request. */
-               if (sony_blocks_left == 0) {
-                       if (start_request(block / 4, nblock / 4)) {
-                               end_request(req, 0);
-                               continue;
-                       }
-               }
-               /* If the requested block is not the next one waiting in
-                  the driver, abort the current operation and start a
-                  new one. */
-               else if (block != sony_next_block) {
-                       pr_debug(PFX "Read for block %d, expected %d\n",
-                                block, sony_next_block);
-                       abort_read();
-                       if (!sony_toc_read) {
-                               printk(KERN_NOTICE PFX "TOC not read\n");
-                               end_request(req, 0);
-                               continue;
-                       }
-                       if (start_request(block / 4, nblock / 4)) {
-                               printk(KERN_NOTICE PFX "start request failed\n");
-                               end_request(req, 0);
-                               continue;
-                       }
-               }
-
-               read_data_block(req->buffer, block, nblock, res_reg, &res_size);
-
-               if (res_reg[0] != 0x20) {
-                       if (!end_that_request_first(req, 1, nblock)) {
-                               spin_lock_irq(q->queue_lock);
-                               blkdev_dequeue_request(req);
-                               end_that_request_last(req, 1);
-                               spin_unlock_irq(q->queue_lock);
-                       }
-                       continue;
-               }
-
-               if (num_retries > MAX_CDU31A_RETRIES) {
-                       end_request(req, 0);
-                       continue;
-               }
-
-               num_retries++;
-               if (res_reg[1] == SONY_NOT_SPIN_ERR) {
-                       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
-                                       &res_size);
-               } else {
-                       printk(KERN_NOTICE PFX "%s error for block %d, nblock %d\n",
-                                translate_error(res_reg[1]), block, nblock);
-               }
-               goto try_read_again;
-       }
-      end_do_cdu31a_request:
-#if 0
-       /* After finished, cancel any pending operations. */
-       abort_read();
-#else
-       /* Start a timer to time out after a while to disable
-          the read. */
-       cdu31a_abort_timer.expires = jiffies + 2 * HZ;  /* Wait 2 seconds */
-       add_timer(&cdu31a_abort_timer);
-#endif
-
-       up(&sony_sem);
-       spin_lock_irq(q->queue_lock);
-       pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
-}
-
-
-/*
- * Read the table of contents from the drive and set up TOC if
- * successful.
- */
-static void sony_get_toc(void)
-{
-       unsigned char res_reg[2];
-       unsigned int res_size;
-       unsigned char parms[1];
-       int session;
-       int num_spin_ups;
-       int totaltracks = 0;
-       int mint = 99;
-       int maxt = 0;
-
-       pr_debug(PFX "Entering %s\n", __FUNCTION__);
-
-       num_spin_ups = 0;
-       if (!sony_toc_read) {
-             respinup_on_gettoc:
-               /* Ignore the result, since it might error if spinning already. */
-               do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               /* The drive sometimes returns error 0.  I don't know why, but ignore
-                  it.  It seems to mean the drive has already done the operation. */
-               if ((res_size < 2)
-                   || ((res_reg[0] != 0) && (res_reg[1] != 0))) {
-                       /* If the drive is already playing, it's ok.  */
-                       if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR)
-                           || (res_reg[1] == 0)) {
-                               goto gettoc_drive_spinning;
-                       }
-
-                       /* If the drive says it is not spun up (even though we just did it!)
-                          then retry the operation at least a few times. */
-                       if ((res_reg[1] == SONY_NOT_SPIN_ERR)
-                           && (num_spin_ups < MAX_CDU31A_RETRIES)) {
-                               num_spin_ups++;
-                               goto respinup_on_gettoc;
-                       }
-
-                       printk("cdu31a: Error reading TOC: %x %s\n",
-                              res_reg[0], translate_error(res_reg[1]));
-                       return;
-               }
-
-             gettoc_drive_spinning:
-
-               /* The idea here is we keep asking for sessions until the command
-                  fails.  Then we know what the last valid session on the disk is.
-                  No need to check session 0, since session 0 is the same as session
-                  1; the command returns different information if you give it 0. 
-                */
-#if DEBUG
-               memset(&sony_toc, 0x0e, sizeof(sony_toc));
-               memset(&single_toc, 0x0f, sizeof(single_toc));
-#endif
-               session = 1;
-               while (1) {
-/* This seems to slow things down enough to make it work.  This
- * appears to be a problem in do_sony_cd_cmd.  This printk seems 
- * to address the symptoms...  -Erik */
-                       pr_debug(PFX "Trying session %d\n", session);
-                       parms[0] = session;
-                       do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD,
-                                      parms, 1, res_reg, &res_size);
-
-                       pr_debug(PFX "%2.2x %2.2x\n", res_reg[0], res_reg[1]);
-
-                       if ((res_size < 2)
-                           || ((res_reg[0] & 0xf0) == 0x20)) {
-                               /* An error reading the TOC, this must be past the last session. */
-                               if (session == 1)
-                                       printk
-                                           ("Yikes! Couldn't read any sessions!");
-                               break;
-                       }
-                       pr_debug(PFX "Reading session %d\n", session);
-
-                       parms[0] = session;
-                       do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD,
-                                      parms,
-                                      1,
-                                      (unsigned char *) &single_toc,
-                                      &res_size);
-                       if ((res_size < 2)
-                           || ((single_toc.exec_status[0] & 0xf0) ==
-                               0x20)) {
-                               printk(KERN_ERR PFX "Error reading "
-                                               "session %d: %x %s\n",
-                                    session, single_toc.exec_status[0],
-                                    translate_error(single_toc.
-                                                    exec_status[1]));
-                               /* An error reading the TOC.  Return without sony_toc_read
-                                  set. */
-                               return;
-                       }
-                       pr_debug(PFX "add0 %01x, con0 %01x, poi0 %02x, "
-                                       "1st trk %d, dsktyp %x, dum0 %x\n",
-                            single_toc.address0, single_toc.control0,
-                            single_toc.point0,
-                            bcd_to_int(single_toc.first_track_num),
-                            single_toc.disk_type, single_toc.dummy0);
-                       pr_debug(PFX "add1 %01x, con1 %01x, poi1 %02x, "
-                                       "lst trk %d, dummy1 %x, dum2 %x\n",
-                            single_toc.address1, single_toc.control1,
-                            single_toc.point1,
-                            bcd_to_int(single_toc.last_track_num),
-                            single_toc.dummy1, single_toc.dummy2);
-                       pr_debug(PFX "add2 %01x, con2 %01x, poi2 %02x "
-                               "leadout start min %d, sec %d, frame %d\n",
-                            single_toc.address2, single_toc.control2,
-                            single_toc.point2,
-                            bcd_to_int(single_toc.lead_out_start_msf[0]),
-                            bcd_to_int(single_toc.lead_out_start_msf[1]),
-                            bcd_to_int(single_toc.lead_out_start_msf[2]));
-                       if (res_size > 18 && single_toc.pointb0 > 0xaf)
-                               pr_debug(PFX "addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n"
-                                    "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n",
-                                    single_toc.addressb0,
-                                    single_toc.controlb0,
-                                    single_toc.pointb0,
-                                    bcd_to_int(single_toc.
-                                               next_poss_prog_area_msf
-                                               [0]),
-                                    bcd_to_int(single_toc.
-                                               next_poss_prog_area_msf
-                                               [1]),
-                                    bcd_to_int(single_toc.
-                                               next_poss_prog_area_msf
-                                               [2]),
-                                    single_toc.num_mode_5_pointers,
-                                    bcd_to_int(single_toc.
-                                               max_start_outer_leadout_msf
-                                               [0]),
-                                    bcd_to_int(single_toc.
-                                               max_start_outer_leadout_msf
-                                               [1]),
-                                    bcd_to_int(single_toc.
-                                               max_start_outer_leadout_msf
-                                               [2]));
-                       if (res_size > 27 && single_toc.pointb1 > 0xaf)
-                               pr_debug(PFX "addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n",
-                                    single_toc.addressb1,
-                                    single_toc.controlb1,
-                                    single_toc.pointb1,
-                                    single_toc.dummyb0_1[0],
-                                    single_toc.dummyb0_1[1],
-                                    single_toc.dummyb0_1[2],
-                                    single_toc.dummyb0_1[3],
-                                    single_toc.num_skip_interval_pointers,
-                                    single_toc.num_skip_track_assignments,
-                                    single_toc.dummyb0_2);
-                       if (res_size > 36 && single_toc.pointb2 > 0xaf)
-                               pr_debug(PFX "addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
-                                    single_toc.addressb2,
-                                    single_toc.controlb2,
-                                    single_toc.pointb2,
-                                    single_toc.tracksb2[0],
-                                    single_toc.tracksb2[1],
-                                    single_toc.tracksb2[2],
-                                    single_toc.tracksb2[3],
-                                    single_toc.tracksb2[4],
-                                    single_toc.tracksb2[5],
-                                    single_toc.tracksb2[6]);
-                       if (res_size > 45 && single_toc.pointb3 > 0xaf)
-                               pr_debug(PFX "addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
-                                    single_toc.addressb3,
-                                    single_toc.controlb3,
-                                    single_toc.pointb3,
-                                    single_toc.tracksb3[0],
-                                    single_toc.tracksb3[1],
-                                    single_toc.tracksb3[2],
-                                    single_toc.tracksb3[3],
-                                    single_toc.tracksb3[4],
-                                    single_toc.tracksb3[5],
-                                    single_toc.tracksb3[6]);
-                       if (res_size > 54 && single_toc.pointb4 > 0xaf)
-                               pr_debug(PFX "addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
-                                    single_toc.addressb4,
-                                    single_toc.controlb4,
-                                    single_toc.pointb4,
-                                    single_toc.tracksb4[0],
-                                    single_toc.tracksb4[1],
-                                    single_toc.tracksb4[2],
-                                    single_toc.tracksb4[3],
-                                    single_toc.tracksb4[4],
-                                    single_toc.tracksb4[5],
-                                    single_toc.tracksb4[6]);
-                       if (res_size > 63 && single_toc.pointc0 > 0xaf)
-                               pr_debug(PFX "addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
-                                    single_toc.addressc0,
-                                    single_toc.controlc0,
-                                    single_toc.pointc0,
-                                    single_toc.dummyc0[0],
-                                    single_toc.dummyc0[1],
-                                    single_toc.dummyc0[2],
-                                    single_toc.dummyc0[3],
-                                    single_toc.dummyc0[4],
-                                    single_toc.dummyc0[5],
-                                    single_toc.dummyc0[6]);
-#undef DEBUG
-#define DEBUG 0
-
-                       sony_toc.lead_out_start_msf[0] =
-                           bcd_to_int(single_toc.lead_out_start_msf[0]);
-                       sony_toc.lead_out_start_msf[1] =
-                           bcd_to_int(single_toc.lead_out_start_msf[1]);
-                       sony_toc.lead_out_start_msf[2] =
-                           bcd_to_int(single_toc.lead_out_start_msf[2]);
-                       sony_toc.lead_out_start_lba =
-                           single_toc.lead_out_start_lba =
-                           msf_to_log(sony_toc.lead_out_start_msf);
-
-                       /* For points that do not exist, move the data over them
-                          to the right location. */
-                       if (single_toc.pointb0 != 0xb0) {
-                               memmove(((char *) &single_toc) + 27,
-                                       ((char *) &single_toc) + 18,
-                                       res_size - 18);
-                               res_size += 9;
-                       } else if (res_size > 18) {
-                               sony_toc.lead_out_start_msf[0] =
-                                   bcd_to_int(single_toc.
-                                              max_start_outer_leadout_msf
-                                              [0]);
-                               sony_toc.lead_out_start_msf[1] =
-                                   bcd_to_int(single_toc.
-                                              max_start_outer_leadout_msf
-                                              [1]);
-                               sony_toc.lead_out_start_msf[2] =
-                                   bcd_to_int(single_toc.
-                                              max_start_outer_leadout_msf
-                                              [2]);
-                               sony_toc.lead_out_start_lba =
-                                   msf_to_log(sony_toc.
-                                              lead_out_start_msf);
-                       }
-                       if (single_toc.pointb1 != 0xb1) {
-                               memmove(((char *) &single_toc) + 36,
-                                       ((char *) &single_toc) + 27,
-                                       res_size - 27);
-                               res_size += 9;
-                       }
-                       if (single_toc.pointb2 != 0xb2) {
-                               memmove(((char *) &single_toc) + 45,
-                                       ((char *) &single_toc) + 36,
-                                       res_size - 36);
-                               res_size += 9;
-                       }
-                       if (single_toc.pointb3 != 0xb3) {
-                               memmove(((char *) &single_toc) + 54,
-                                       ((char *) &single_toc) + 45,
-                                       res_size - 45);
-                               res_size += 9;
-                       }
-                       if (single_toc.pointb4 != 0xb4) {
-                               memmove(((char *) &single_toc) + 63,
-                                       ((char *) &single_toc) + 54,
-                                       res_size - 54);
-                               res_size += 9;
-                       }
-                       if (single_toc.pointc0 != 0xc0) {
-                               memmove(((char *) &single_toc) + 72,
-                                       ((char *) &single_toc) + 63,
-                                       res_size - 63);
-                               res_size += 9;
-                       }
-#if DEBUG
-                       printk(PRINT_INFO PFX "start track lba %u,  "
-                                       "leadout start lba %u\n",
-                            single_toc.start_track_lba,
-                            single_toc.lead_out_start_lba);
-                       {
-                               int i;
-                               for (i = 0;
-                                    i <
-                                    1 +
-                                    bcd_to_int(single_toc.last_track_num)
-                                    -
-                                    bcd_to_int(single_toc.
-                                               first_track_num); i++) {
-                                       printk(KERN_INFO PFX "trk %02d: add 0x%01x, con 0x%01x,  track %02d, start min %02d, sec %02d, frame %02d\n",
-                                            i,
-                                            single_toc.tracks[i].address,
-                                            single_toc.tracks[i].control,
-                                            bcd_to_int(single_toc.
-                                                       tracks[i].track),
-                                            bcd_to_int(single_toc.
-                                                       tracks[i].
-                                                       track_start_msf
-                                                       [0]),
-                                            bcd_to_int(single_toc.
-                                                       tracks[i].
-                                                       track_start_msf
-                                                       [1]),
-                                            bcd_to_int(single_toc.
-                                                       tracks[i].
-                                                       track_start_msf
-                                                       [2]));
-                                       if (mint >
-                                           bcd_to_int(single_toc.
-                                                      tracks[i].track))
-                                               mint =
-                                                   bcd_to_int(single_toc.
-                                                              tracks[i].
-                                                              track);
-                                       if (maxt <
-                                           bcd_to_int(single_toc.
-                                                      tracks[i].track))
-                                               maxt =
-                                                   bcd_to_int(single_toc.
-                                                              tracks[i].
-                                                              track);
-                               }
-                               printk(KERN_INFO PFX "min track number %d,  "
-                                               "max track number %d\n",
-                                    mint, maxt);
-                       }
-#endif
-
-                       /* prepare a special table of contents for a CD-I disc. They don't have one. */
-                       if (single_toc.disk_type == 0x10 &&
-                           single_toc.first_track_num == 2 &&
-                           single_toc.last_track_num == 2 /* CD-I */ ) {
-                               sony_toc.tracks[totaltracks].address = 1;
-                               sony_toc.tracks[totaltracks].control = 4;       /* force data tracks */
-                               sony_toc.tracks[totaltracks].track = 1;
-                               sony_toc.tracks[totaltracks].
-                                   track_start_msf[0] = 0;
-                               sony_toc.tracks[totaltracks].
-                                   track_start_msf[1] = 2;
-                               sony_toc.tracks[totaltracks].
-                                   track_start_msf[2] = 0;
-                               mint = maxt = 1;
-                               totaltracks++;
-                       } else
-                               /* gather track entries from this session */
-                       {
-                               int i;
-                               for (i = 0;
-                                    i <
-                                    1 +
-                                    bcd_to_int(single_toc.last_track_num)
-                                    -
-                                    bcd_to_int(single_toc.
-                                               first_track_num);
-                                    i++, totaltracks++) {
-                                       sony_toc.tracks[totaltracks].
-                                           address =
-                                           single_toc.tracks[i].address;
-                                       sony_toc.tracks[totaltracks].
-                                           control =
-                                           single_toc.tracks[i].control;
-                                       sony_toc.tracks[totaltracks].
-                                           track =
-                                           bcd_to_int(single_toc.
-                                                      tracks[i].track);
-                                       sony_toc.tracks[totaltracks].
-                                           track_start_msf[0] =
-                                           bcd_to_int(single_toc.
-                                                      tracks[i].
-                                                      track_start_msf[0]);
-                                       sony_toc.tracks[totaltracks].
-                                           track_start_msf[1] =
-                                           bcd_to_int(single_toc.
-                                                      tracks[i].
-                                                      track_start_msf[1]);
-                                       sony_toc.tracks[totaltracks].
-                                           track_start_msf[2] =
-                                           bcd_to_int(single_toc.
-                                                      tracks[i].
-                                                      track_start_msf[2]);
-                                       if (i == 0)
-                                               single_toc.
-                                                   start_track_lba =
-                                                   msf_to_log(sony_toc.
-                                                              tracks
-                                                              [totaltracks].
-                                                              track_start_msf);
-                                       if (mint >
-                                           sony_toc.tracks[totaltracks].
-                                           track)
-                                               mint =
-                                                   sony_toc.
-                                                   tracks[totaltracks].
-                                                   track;
-                                       if (maxt <
-                                           sony_toc.tracks[totaltracks].
-                                           track)
-                                               maxt =
-                                                   sony_toc.
-                                                   tracks[totaltracks].
-                                                   track;
-                               }
-                       }
-                       sony_toc.first_track_num = mint;
-                       sony_toc.last_track_num = maxt;
-                       /* Disk type of last session wins. For example:
-                          CD-Extra has disk type 0 for the first session, so
-                          a dumb HiFi CD player thinks it is a plain audio CD.
-                          We are interested in the disk type of the last session,
-                          which is 0x20 (XA) for CD-Extra, so we can access the
-                          data track ... */
-                       sony_toc.disk_type = single_toc.disk_type;
-                       sony_toc.sessions = session;
-
-                       /* don't believe everything :-) */
-                       if (session == 1)
-                               single_toc.start_track_lba = 0;
-                       sony_toc.start_track_lba =
-                           single_toc.start_track_lba;
-
-                       if (session > 1 && single_toc.pointb0 == 0xb0 &&
-                           sony_toc.lead_out_start_lba ==
-                           single_toc.lead_out_start_lba) {
-                               break;
-                       }
-
-                       /* Let's not get carried away... */
-                       if (session > 40) {
-                               printk(KERN_NOTICE PFX "too many sessions: "
-                                               "%d\n", session);
-                               break;
-                       }
-                       session++;
-               }
-               sony_toc.track_entries = totaltracks;
-               /* add one entry for the LAST track with track number CDROM_LEADOUT */
-               sony_toc.tracks[totaltracks].address = single_toc.address2;
-               sony_toc.tracks[totaltracks].control = single_toc.control2;
-               sony_toc.tracks[totaltracks].track = CDROM_LEADOUT;
-               sony_toc.tracks[totaltracks].track_start_msf[0] =
-                   sony_toc.lead_out_start_msf[0];
-               sony_toc.tracks[totaltracks].track_start_msf[1] =
-                   sony_toc.lead_out_start_msf[1];
-               sony_toc.tracks[totaltracks].track_start_msf[2] =
-                   sony_toc.lead_out_start_msf[2];
-
-               sony_toc_read = 1;
-
-               pr_debug(PFX "Disk session %d, start track: %d, "
-                               "stop track: %d\n",
-                    session, single_toc.start_track_lba,
-                    single_toc.lead_out_start_lba);
-       }
-       pr_debug(PFX "Leaving %s\n", __FUNCTION__);
-}
-
-
-/*
- * Uniform cdrom interface function
- * return multisession offset and sector information
- */
-static int scd_get_last_session(struct cdrom_device_info *cdi,
-                               struct cdrom_multisession *ms_info)
-{
-       if (ms_info == NULL)
-               return 1;
-
-       if (!sony_toc_read) {
-               if (down_interruptible(&sony_sem))
-                       return -ERESTARTSYS;
-               sony_get_toc();
-               up(&sony_sem);
-       }
-
-       ms_info->addr_format = CDROM_LBA;
-       ms_info->addr.lba = sony_toc.start_track_lba;
-       ms_info->xa_flag = sony_toc.disk_type == SONY_XA_DISK_TYPE ||
-           sony_toc.disk_type == 0x10 /* CDI */ ;
-
-       return 0;
-}
-
-/*
- * Search for a specific track in the table of contents.
- */
-static int find_track(int track)
-{
-       int i;
-
-       for (i = 0; i <= sony_toc.track_entries; i++) {
-               if (sony_toc.tracks[i].track == track) {
-                       return i;
-               }
-       }
-
-       return -1;
-}
-
-
-/*
- * Read the subcode and put it in last_sony_subcode for future use.
- */
-static int read_subcode(void)
-{
-       unsigned int res_size;
-
-
-       do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD,
-                      NULL,
-                      0, (unsigned char *) &last_sony_subcode, &res_size);
-       if ((res_size < 2)
-           || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) {
-               printk(KERN_ERR PFX "Sony CDROM error %s (read_subcode)\n",
-                      translate_error(last_sony_subcode.exec_status[1]));
-               return -EIO;
-       }
-
-       last_sony_subcode.track_num =
-           bcd_to_int(last_sony_subcode.track_num);
-       last_sony_subcode.index_num =
-           bcd_to_int(last_sony_subcode.index_num);
-       last_sony_subcode.abs_msf[0] =
-           bcd_to_int(last_sony_subcode.abs_msf[0]);
-       last_sony_subcode.abs_msf[1] =
-           bcd_to_int(last_sony_subcode.abs_msf[1]);
-       last_sony_subcode.abs_msf[2] =
-           bcd_to_int(last_sony_subcode.abs_msf[2]);
-
-       last_sony_subcode.rel_msf[0] =
-           bcd_to_int(last_sony_subcode.rel_msf[0]);
-       last_sony_subcode.rel_msf[1] =
-           bcd_to_int(last_sony_subcode.rel_msf[1]);
-       last_sony_subcode.rel_msf[2] =
-           bcd_to_int(last_sony_subcode.rel_msf[2]);
-       return 0;
-}
-
-/*
- * Uniform cdrom interface function
- * return the media catalog number found on some older audio cds
- */
-static int
-scd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
-{
-       unsigned char resbuffer[2 + 14];
-       unsigned char *mcnp = mcn->medium_catalog_number;
-       unsigned char *resp = resbuffer + 3;
-       unsigned int res_size;
-
-       memset(mcn->medium_catalog_number, 0, 14);
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD,
-                      NULL, 0, resbuffer, &res_size);
-       up(&sony_sem);
-       if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20));
-       else {
-               /* packed bcd to single ASCII digits */
-               *mcnp++ = (*resp >> 4) + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4) + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4) + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4) + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4) + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4) + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4) + '0';
-       }
-       *mcnp = '\0';
-       return 0;
-}
-
-
-/*
- * Get the subchannel info like the CDROMSUBCHNL command wants to see it.  If
- * the drive is playing, the subchannel needs to be read (since it would be
- * changing).  If the drive is paused or completed, the subcode information has
- * already been stored, just use that.  The ioctl call wants things in decimal
- * (not BCD), so all the conversions are done.
- */
-static int sony_get_subchnl_info(struct cdrom_subchnl *schi)
-{
-       /* Get attention stuff */
-       while (handle_sony_cd_attention());
-
-       sony_get_toc();
-       if (!sony_toc_read) {
-               return -EIO;
-       }
-
-       switch (sony_audio_status) {
-       case CDROM_AUDIO_NO_STATUS:
-       case CDROM_AUDIO_PLAY:
-               if (read_subcode() < 0) {
-                       return -EIO;
-               }
-               break;
-
-       case CDROM_AUDIO_PAUSED:
-       case CDROM_AUDIO_COMPLETED:
-               break;
-
-#if 0
-       case CDROM_AUDIO_NO_STATUS:
-               schi->cdsc_audiostatus = sony_audio_status;
-               return 0;
-               break;
-#endif
-       case CDROM_AUDIO_INVALID:
-       case CDROM_AUDIO_ERROR:
-       default:
-               return -EIO;
-       }
-
-       schi->cdsc_audiostatus = sony_audio_status;
-       schi->cdsc_adr = last_sony_subcode.address;
-       schi->cdsc_ctrl = last_sony_subcode.control;
-       schi->cdsc_trk = last_sony_subcode.track_num;
-       schi->cdsc_ind = last_sony_subcode.index_num;
-       if (schi->cdsc_format == CDROM_MSF) {
-               schi->cdsc_absaddr.msf.minute =
-                   last_sony_subcode.abs_msf[0];
-               schi->cdsc_absaddr.msf.second =
-                   last_sony_subcode.abs_msf[1];
-               schi->cdsc_absaddr.msf.frame =
-                   last_sony_subcode.abs_msf[2];
-
-               schi->cdsc_reladdr.msf.minute =
-                   last_sony_subcode.rel_msf[0];
-               schi->cdsc_reladdr.msf.second =
-                   last_sony_subcode.rel_msf[1];
-               schi->cdsc_reladdr.msf.frame =
-                   last_sony_subcode.rel_msf[2];
-       } else if (schi->cdsc_format == CDROM_LBA) {
-               schi->cdsc_absaddr.lba =
-                   msf_to_log(last_sony_subcode.abs_msf);
-               schi->cdsc_reladdr.lba =
-                   msf_to_log(last_sony_subcode.rel_msf);
-       }
-
-       return 0;
-}
-
-/* Get audio data from the drive.  This is fairly complex because I
-   am looking for status and data at the same time, but if I get status
-   then I just look for data.  I need to get the status immediately so
-   the switch from audio to data tracks will happen quickly. */
-static void
-read_audio_data(char *buffer, unsigned char res_reg[], int *res_size)
-{
-       unsigned long retry_count;
-       int result_read;
-
-
-       res_reg[0] = 0;
-       res_reg[1] = 0;
-       *res_size = 0;
-       result_read = 0;
-
-       /* Wait for the drive to tell us we have something */
-       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-      continue_read_audio_wait:
-       while (time_before(jiffies, retry_count) && !(is_data_ready())
-              && !(is_result_ready() || result_read)) {
-               while (handle_sony_cd_attention());
-
-               sony_sleep();
-       }
-       if (!(is_data_ready())) {
-               if (is_result_ready() && !result_read) {
-                       get_result(res_reg, res_size);
-
-                       /* Read block status and continue waiting for data. */
-                       if ((res_reg[0] & 0xf0) == 0x50) {
-                               result_read = 1;
-                               goto continue_read_audio_wait;
-                       }
-                       /* Invalid data from the drive.  Shut down the operation. */
-                       else if ((res_reg[0] & 0xf0) != 0x20) {
-                               printk(KERN_WARNING PFX "Got result that "
-                                               "should have been error: %d\n",
-                                    res_reg[0]);
-                               res_reg[0] = 0x20;
-                               res_reg[1] = SONY_BAD_DATA_ERR;
-                               *res_size = 2;
-                       }
-                       abort_read();
-               } else {
-                       pr_debug(PFX "timeout out %d\n", __LINE__);
-                       res_reg[0] = 0x20;
-                       res_reg[1] = SONY_TIMEOUT_OP_ERR;
-                       *res_size = 2;
-                       abort_read();
-               }
-       } else {
-               clear_data_ready();
-
-               /* If data block, then get 2340 bytes offset by 12. */
-               if (sony_raw_data_mode) {
-                       insb(sony_cd_read_reg, buffer + CD_XA_HEAD,
-                            CD_FRAMESIZE_RAW1);
-               } else {
-                       /* Audio gets the whole 2352 bytes. */
-                       insb(sony_cd_read_reg, buffer, CD_FRAMESIZE_RAW);
-               }
-
-               /* If I haven't already gotten the result, get it now. */
-               if (!result_read) {
-                       /* Wait for the drive to tell us we have something */
-                       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-                       while (time_before(jiffies, retry_count)
-                              && !(is_result_ready())) {
-                               while (handle_sony_cd_attention());
-
-                               sony_sleep();
-                       }
-
-                       if (!is_result_ready()) {
-                               pr_debug(PFX "timeout out %d\n", __LINE__);
-                               res_reg[0] = 0x20;
-                               res_reg[1] = SONY_TIMEOUT_OP_ERR;
-                               *res_size = 2;
-                               abort_read();
-                               return;
-                       } else {
-                               get_result(res_reg, res_size);
-                       }
-               }
-
-               if ((res_reg[0] & 0xf0) == 0x50) {
-                       if ((res_reg[0] == SONY_NO_CIRC_ERR_BLK_STAT)
-                           || (res_reg[0] == SONY_NO_LECC_ERR_BLK_STAT)
-                           || (res_reg[0] == SONY_RECOV_LECC_ERR_BLK_STAT)
-                           || (res_reg[0] == SONY_NO_ERR_DETECTION_STAT)) {
-                               /* Ok, nothing to do. */
-                       } else {
-                               printk(KERN_ERR PFX "Data block error: 0x%x\n",
-                                      res_reg[0]);
-                               res_reg[0] = 0x20;
-                               res_reg[1] = SONY_BAD_DATA_ERR;
-                               *res_size = 2;
-                       }
-               } else if ((res_reg[0] & 0xf0) != 0x20) {
-                       /* The drive gave me bad status, I don't know what to do.
-                          Reset the driver and return an error. */
-                       printk(KERN_NOTICE PFX "Invalid block status: 0x%x\n",
-                              res_reg[0]);
-                       restart_on_error();
-                       res_reg[0] = 0x20;
-                       res_reg[1] = SONY_BAD_DATA_ERR;
-                       *res_size = 2;
-               }
-       }
-}
-
-/* Perform a raw data read.  This will automatically detect the
-   track type and read the proper data (audio or data). */
-static int read_audio(struct cdrom_read_audio *ra)
-{
-       int retval;
-       unsigned char params[2];
-       unsigned char res_reg[12];
-       unsigned int res_size;
-       unsigned int cframe;
-
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       if (!sony_spun_up)
-               scd_spinup();
-
-       /* Set the drive to do raw operations. */
-       params[0] = SONY_SD_DECODE_PARAM;
-       params[1] = 0x06 | sony_raw_data_mode;
-       do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                      params, 2, res_reg, &res_size);
-       if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-               printk(KERN_ERR PFX "Unable to set decode params: 0x%2.2x\n",
-                      res_reg[1]);
-               retval = -EIO;
-               goto out_up;
-       }
-
-       /* From here down, we have to goto exit_read_audio instead of returning
-          because the drive parameters have to be set back to data before
-          return. */
-
-       retval = 0;
-       if (start_request(ra->addr.lba, ra->nframes)) {
-               retval = -EIO;
-               goto exit_read_audio;
-       }
-
-       /* For every requested frame. */
-       cframe = 0;
-       while (cframe < ra->nframes) {
-               read_audio_data(audio_buffer, res_reg, &res_size);
-               if ((res_reg[0] & 0xf0) == 0x20) {
-                       if (res_reg[1] == SONY_BAD_DATA_ERR) {
-                               printk(KERN_ERR PFX "Data error on audio "
-                                               "sector %d\n",
-                                    ra->addr.lba + cframe);
-                       } else if (res_reg[1] == SONY_ILL_TRACK_R_ERR) {
-                               /* Illegal track type, change track types and start over. */
-                               sony_raw_data_mode =
-                                   (sony_raw_data_mode) ? 0 : 1;
-
-                               /* Set the drive mode. */
-                               params[0] = SONY_SD_DECODE_PARAM;
-                               params[1] = 0x06 | sony_raw_data_mode;
-                               do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                                              params,
-                                              2, res_reg, &res_size);
-                               if ((res_size < 2)
-                                   || ((res_reg[0] & 0xf0) == 0x20)) {
-                                       printk(KERN_ERR PFX "Unable to set "
-                                               "decode params: 0x%2.2x\n",
-                                            res_reg[1]);
-                                       retval = -EIO;
-                                       goto exit_read_audio;
-                               }
-
-                               /* Restart the request on the current frame. */
-                               if (start_request
-                                   (ra->addr.lba + cframe,
-                                    ra->nframes - cframe)) {
-                                       retval = -EIO;
-                                       goto exit_read_audio;
-                               }
-
-                               /* Don't go back to the top because don't want to get into
-                                  and infinite loop.  A lot of code gets duplicated, but
-                                  that's no big deal, I don't guess. */
-                               read_audio_data(audio_buffer, res_reg,
-                                               &res_size);
-                               if ((res_reg[0] & 0xf0) == 0x20) {
-                                       if (res_reg[1] ==
-                                           SONY_BAD_DATA_ERR) {
-                                               printk(KERN_ERR PFX "Data error"
-                                                       " on audio sector %d\n",
-                                                    ra->addr.lba +
-                                                    cframe);
-                                       } else {
-                                               printk(KERN_ERR PFX "Error reading audio data on sector %d: %s\n",
-                                                    ra->addr.lba + cframe,
-                                                    translate_error
-                                                    (res_reg[1]));
-                                               retval = -EIO;
-                                               goto exit_read_audio;
-                                       }
-                               } else if (copy_to_user(ra->buf +
-                                                              (CD_FRAMESIZE_RAW
-                                                               * cframe),
-                                                       audio_buffer,
-                                                       CD_FRAMESIZE_RAW)) {
-                                       retval = -EFAULT;
-                                       goto exit_read_audio;
-                               }
-                       } else {
-                               printk(KERN_ERR PFX "Error reading audio "
-                                               "data on sector %d: %s\n",
-                                    ra->addr.lba + cframe,
-                                    translate_error(res_reg[1]));
-                               retval = -EIO;
-                               goto exit_read_audio;
-                       }
-               } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe),
-                                       (char *)audio_buffer,
-                                       CD_FRAMESIZE_RAW)) {
-                       retval = -EFAULT;
-                       goto exit_read_audio;
-               }
-
-               cframe++;
-       }
-
-       get_result(res_reg, &res_size);
-       if ((res_reg[0] & 0xf0) == 0x20) {
-               printk(KERN_ERR PFX "Error return from audio read: %s\n",
-                      translate_error(res_reg[1]));
-               retval = -EIO;
-               goto exit_read_audio;
-       }
-
-      exit_read_audio:
-
-       /* Set the drive mode back to the proper one for the disk. */
-       params[0] = SONY_SD_DECODE_PARAM;
-       if (!sony_xa_mode) {
-               params[1] = 0x0f;
-       } else {
-               params[1] = 0x07;
-       }
-       do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                      params, 2, res_reg, &res_size);
-       if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
-               printk(KERN_ERR PFX "Unable to reset decode params: 0x%2.2x\n",
-                      res_reg[1]);
-               retval = -EIO;
-       }
-
- out_up:
-       up(&sony_sem);
-
-       return retval;
-}
-
-static int
-do_sony_cd_cmd_chk(const char *name,
-                  unsigned char cmd,
-                  unsigned char *params,
-                  unsigned int num_params,
-                  unsigned char *result_buffer, unsigned int *result_size)
-{
-       do_sony_cd_cmd(cmd, params, num_params, result_buffer,
-                      result_size);
-       if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) {
-               printk(KERN_ERR PFX "Error %s (CDROM%s)\n",
-                      translate_error(result_buffer[1]), name);
-               return -EIO;
-       }
-       return 0;
-}
-
-/*
- * Uniform cdrom interface function
- * open the tray
- */
-static int scd_tray_move(struct cdrom_device_info *cdi, int position)
-{
-       int retval;
-
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       if (position == 1 /* open tray */ ) {
-               unsigned char res_reg[12];
-               unsigned int res_size;
-
-               do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg,
-                              &res_size);
-               do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               sony_audio_status = CDROM_AUDIO_INVALID;
-               retval = do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0,
-                                         res_reg, &res_size);
-       } else {
-               if (0 == scd_spinup())
-                       sony_spun_up = 1;
-               retval = 0;
-       }
-       up(&sony_sem);
-       return retval;
-}
-
-/*
- * The big ugly ioctl handler.
- */
-static int scd_audio_ioctl(struct cdrom_device_info *cdi,
-                          unsigned int cmd, void *arg)
-{
-       unsigned char res_reg[12];
-       unsigned int res_size;
-       unsigned char params[7];
-       int i, retval;
-
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       switch (cmd) {
-       case CDROMSTART:        /* Spin up the drive */
-               retval = do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL,
-                                         0, res_reg, &res_size);
-               break;
-
-       case CDROMSTOP: /* Spin down the drive */
-               do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               /*
-                * Spin the drive down, ignoring the error if the disk was
-                * already not spinning.
-                */
-               sony_audio_status = CDROM_AUDIO_NO_STATUS;
-               retval = do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL,
-                                         0, res_reg, &res_size);
-               break;
-
-       case CDROMPAUSE:        /* Pause the drive */
-               if (do_sony_cd_cmd_chk
-                   ("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg,
-                    &res_size)) {
-                       retval = -EIO;
-                       break;
-               }
-               /* Get the current position and save it for resuming */
-               if (read_subcode() < 0) {
-                       retval = -EIO;
-                       break;
-               }
-               cur_pos_msf[0] = last_sony_subcode.abs_msf[0];
-               cur_pos_msf[1] = last_sony_subcode.abs_msf[1];
-               cur_pos_msf[2] = last_sony_subcode.abs_msf[2];
-               sony_audio_status = CDROM_AUDIO_PAUSED;
-               retval = 0;
-               break;
-
-       case CDROMRESUME:       /* Start the drive after being paused */
-               if (sony_audio_status != CDROM_AUDIO_PAUSED) {
-                       retval = -EINVAL;
-                       break;
-               }
-
-               do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               /* Start the drive at the saved position. */
-               params[1] = int_to_bcd(cur_pos_msf[0]);
-               params[2] = int_to_bcd(cur_pos_msf[1]);
-               params[3] = int_to_bcd(cur_pos_msf[2]);
-               params[4] = int_to_bcd(final_pos_msf[0]);
-               params[5] = int_to_bcd(final_pos_msf[1]);
-               params[6] = int_to_bcd(final_pos_msf[2]);
-               params[0] = 0x03;
-               if (do_sony_cd_cmd_chk
-                   ("RESUME", SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg,
-                    &res_size) < 0) {
-                       retval = -EIO;
-                       break;
-               }
-               sony_audio_status = CDROM_AUDIO_PLAY;
-               retval = 0;
-               break;
-
-       case CDROMPLAYMSF:      /* Play starting at the given MSF address. */
-               do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               /* The parameters are given in int, must be converted */
-               for (i = 1; i < 7; i++) {
-                       params[i] =
-                           int_to_bcd(((unsigned char *) arg)[i - 1]);
-               }
-               params[0] = 0x03;
-               if (do_sony_cd_cmd_chk
-                   ("PLAYMSF", SONY_AUDIO_PLAYBACK_CMD, params, 7,
-                    res_reg, &res_size) < 0) {
-                       retval = -EIO;
-                       break;
-               }
-
-               /* Save the final position for pauses and resumes */
-               final_pos_msf[0] = bcd_to_int(params[4]);
-               final_pos_msf[1] = bcd_to_int(params[5]);
-               final_pos_msf[2] = bcd_to_int(params[6]);
-               sony_audio_status = CDROM_AUDIO_PLAY;
-               retval = 0;
-               break;
-
-       case CDROMREADTOCHDR:   /* Read the table of contents header */
-               {
-                       struct cdrom_tochdr *hdr;
-
-                       sony_get_toc();
-                       if (!sony_toc_read) {
-                               retval = -EIO;
-                               break;
-                       }
-
-                       hdr = (struct cdrom_tochdr *) arg;
-                       hdr->cdth_trk0 = sony_toc.first_track_num;
-                       hdr->cdth_trk1 = sony_toc.last_track_num;
-               }
-               retval = 0;
-               break;
-
-       case CDROMREADTOCENTRY: /* Read a given table of contents entry */
-               {
-                       struct cdrom_tocentry *entry;
-                       int track_idx;
-                       unsigned char *msf_val = NULL;
-
-                       sony_get_toc();
-                       if (!sony_toc_read) {
-                               retval = -EIO;
-                               break;
-                       }
-
-                       entry = (struct cdrom_tocentry *) arg;
-
-                       track_idx = find_track(entry->cdte_track);
-                       if (track_idx < 0) {
-                               retval = -EINVAL;
-                               break;
-                       }
-
-                       entry->cdte_adr =
-                           sony_toc.tracks[track_idx].address;
-                       entry->cdte_ctrl =
-                           sony_toc.tracks[track_idx].control;
-                       msf_val =
-                           sony_toc.tracks[track_idx].track_start_msf;
-
-                       /* Logical buffer address or MSF format requested? */
-                       if (entry->cdte_format == CDROM_LBA) {
-                               entry->cdte_addr.lba = msf_to_log(msf_val);
-                       } else if (entry->cdte_format == CDROM_MSF) {
-                               entry->cdte_addr.msf.minute = *msf_val;
-                               entry->cdte_addr.msf.second =
-                                   *(msf_val + 1);
-                               entry->cdte_addr.msf.frame =
-                                   *(msf_val + 2);
-                       }
-               }
-               retval = 0;
-               break;
-
-       case CDROMPLAYTRKIND:   /* Play a track.  This currently ignores index. */
-               {
-                       struct cdrom_ti *ti = (struct cdrom_ti *) arg;
-                       int track_idx;
-
-                       sony_get_toc();
-                       if (!sony_toc_read) {
-                               retval = -EIO;
-                               break;
-                       }
-
-                       if ((ti->cdti_trk0 < sony_toc.first_track_num)
-                           || (ti->cdti_trk0 > sony_toc.last_track_num)
-                           || (ti->cdti_trk1 < ti->cdti_trk0)) {
-                               retval = -EINVAL;
-                               break;
-                       }
-
-                       track_idx = find_track(ti->cdti_trk0);
-                       if (track_idx < 0) {
-                               retval = -EINVAL;
-                               break;
-                       }
-                       params[1] =
-                           int_to_bcd(sony_toc.tracks[track_idx].
-                                      track_start_msf[0]);
-                       params[2] =
-                           int_to_bcd(sony_toc.tracks[track_idx].
-                                      track_start_msf[1]);
-                       params[3] =
-                           int_to_bcd(sony_toc.tracks[track_idx].
-                                      track_start_msf[2]);
-
-                       /*
-                        * If we want to stop after the last track, use the lead-out
-                        * MSF to do that.
-                        */
-                       if (ti->cdti_trk1 >= sony_toc.last_track_num) {
-                               track_idx = find_track(CDROM_LEADOUT);
-                       } else {
-                               track_idx = find_track(ti->cdti_trk1 + 1);
-                       }
-                       if (track_idx < 0) {
-                               retval = -EINVAL;
-                               break;
-                       }
-                       params[4] =
-                           int_to_bcd(sony_toc.tracks[track_idx].
-                                      track_start_msf[0]);
-                       params[5] =
-                           int_to_bcd(sony_toc.tracks[track_idx].
-                                      track_start_msf[1]);
-                       params[6] =
-                           int_to_bcd(sony_toc.tracks[track_idx].
-                                      track_start_msf[2]);
-                       params[0] = 0x03;
-
-                       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
-                                      &res_size);
-
-                       do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7,
-                                      res_reg, &res_size);
-
-                       if ((res_size < 2)
-                           || ((res_reg[0] & 0xf0) == 0x20)) {
-                               printk(KERN_ERR PFX
-                                       "Params: %x %x %x %x %x %x %x\n",
-                                      params[0], params[1], params[2],
-                                      params[3], params[4], params[5],
-                                      params[6]);
-                               printk(KERN_ERR PFX
-                                       "Error %s (CDROMPLAYTRKIND)\n",
-                                    translate_error(res_reg[1]));
-                               retval = -EIO;
-                               break;
-                       }
-
-                       /* Save the final position for pauses and resumes */
-                       final_pos_msf[0] = bcd_to_int(params[4]);
-                       final_pos_msf[1] = bcd_to_int(params[5]);
-                       final_pos_msf[2] = bcd_to_int(params[6]);
-                       sony_audio_status = CDROM_AUDIO_PLAY;
-                       retval = 0;
-                       break;
-               }
-
-       case CDROMVOLCTRL:      /* Volume control.  What volume does this change, anyway? */
-               {
-                       struct cdrom_volctrl *volctrl =
-                           (struct cdrom_volctrl *) arg;
-
-                       params[0] = SONY_SD_AUDIO_VOLUME;
-                       params[1] = volctrl->channel0;
-                       params[2] = volctrl->channel1;
-                       retval = do_sony_cd_cmd_chk("VOLCTRL",
-                                                 SONY_SET_DRIVE_PARAM_CMD,
-                                                 params, 3, res_reg,
-                                                 &res_size);
-                       break;
-               }
-       case CDROMSUBCHNL:      /* Get subchannel info */
-               retval = sony_get_subchnl_info((struct cdrom_subchnl *) arg);
-               break;
-
-       default:
-               retval = -EINVAL;
-               break;
-       }
-       up(&sony_sem);
-       return retval;
-}
-
-static int scd_read_audio(struct cdrom_device_info *cdi,
-                        unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int retval;
-
-       if (down_interruptible(&sony_sem))
-               return -ERESTARTSYS;
-       switch (cmd) {
-       case CDROMREADAUDIO:    /* Read 2352 byte audio tracks and 2340 byte
-                                  raw data tracks. */
-               {
-                       struct cdrom_read_audio ra;
-
-
-                       sony_get_toc();
-                       if (!sony_toc_read) {
-                               retval = -EIO;
-                               break;
-                       }
-
-                       if (copy_from_user(&ra, argp, sizeof(ra))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       if (ra.nframes == 0) {
-                               retval = 0;
-                               break;
-                       }
-
-                       if (!access_ok(VERIFY_WRITE, ra.buf,
-                                       CD_FRAMESIZE_RAW * ra.nframes))
-                               return -EFAULT;
-
-                       if (ra.addr_format == CDROM_LBA) {
-                               if ((ra.addr.lba >=
-                                    sony_toc.lead_out_start_lba)
-                                   || (ra.addr.lba + ra.nframes >=
-                                       sony_toc.lead_out_start_lba)) {
-                                       retval = -EINVAL;
-                                       break;
-                               }
-                       } else if (ra.addr_format == CDROM_MSF) {
-                               if ((ra.addr.msf.minute >= 75)
-                                   || (ra.addr.msf.second >= 60)
-                                   || (ra.addr.msf.frame >= 75)) {
-                                       retval = -EINVAL;
-                                       break;
-                               }
-
-                               ra.addr.lba = ((ra.addr.msf.minute * 4500)
-                                              + (ra.addr.msf.second * 75)
-                                              + ra.addr.msf.frame);
-                               if ((ra.addr.lba >=
-                                    sony_toc.lead_out_start_lba)
-                                   || (ra.addr.lba + ra.nframes >=
-                                       sony_toc.lead_out_start_lba)) {
-                                       retval = -EINVAL;
-                                       break;
-                               }
-
-                               /* I know, this can go negative on an unsigned.  However,
-                                  the first thing done to the data is to add this value,
-                                  so this should compensate and allow direct msf access. */
-                               ra.addr.lba -= LOG_START_OFFSET;
-                       } else {
-                               retval = -EINVAL;
-                               break;
-                       }
-
-                       retval = read_audio(&ra);
-                       break;
-               }
-               retval = 0;
-               break;
-
-       default:
-               retval = -EINVAL;
-       }
-       up(&sony_sem);
-       return retval;
-}
-
-static int scd_spinup(void)
-{
-       unsigned char res_reg[12];
-       unsigned int res_size;
-       int num_spin_ups;
-
-       num_spin_ups = 0;
-
-      respinup_on_open:
-       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
-
-       /* The drive sometimes returns error 0.  I don't know why, but ignore
-          it.  It seems to mean the drive has already done the operation. */
-       if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) {
-               printk(KERN_ERR PFX "%s error (scd_open, spin up)\n",
-                      translate_error(res_reg[1]));
-               return 1;
-       }
-
-       do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);
-
-       /* The drive sometimes returns error 0.  I don't know why, but ignore
-          it.  It seems to mean the drive has already done the operation. */
-       if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) {
-               /* If the drive is already playing, it's ok.  */
-               if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR)
-                   || (res_reg[1] == 0)) {
-                       return 0;
-               }
-
-               /* If the drive says it is not spun up (even though we just did it!)
-                  then retry the operation at least a few times. */
-               if ((res_reg[1] == SONY_NOT_SPIN_ERR)
-                   && (num_spin_ups < MAX_CDU31A_RETRIES)) {
-                       num_spin_ups++;
-                       goto respinup_on_open;
-               }
-
-               printk(KERN_ERR PFX "Error %s (scd_open, read toc)\n",
-                      translate_error(res_reg[1]));
-               do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg,
-                              &res_size);
-               return 1;
-       }
-       return 0;
-}
-
-/*
- * Open the drive for operations.  Spin the drive up and read the table of
- * contents if these have not already been done.
- */
-static int scd_open(struct cdrom_device_info *cdi, int purpose)
-{
-       unsigned char res_reg[12];
-       unsigned int res_size;
-       unsigned char params[2];
-
-       if (purpose == 1) {
-               /* Open for IOCTLs only - no media check */
-               sony_usage++;
-               return 0;
-       }
-
-       if (sony_usage == 0) {
-               if (scd_spinup() != 0)
-                       return -EIO;
-               sony_get_toc();
-               if (!sony_toc_read) {
-                       do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0,
-                                      res_reg, &res_size);
-                       return -EIO;
-               }
-
-               /* For XA on the CDU31A only, we have to do special reads.
-                  The CDU33A handles XA automagically. */
-               /* if (   (sony_toc.disk_type == SONY_XA_DISK_TYPE) */
-               if ((sony_toc.disk_type != 0x00)
-                   && (!is_double_speed)) {
-                       params[0] = SONY_SD_DECODE_PARAM;
-                       params[1] = 0x07;
-                       do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                                      params, 2, res_reg, &res_size);
-                       if ((res_size < 2)
-                           || ((res_reg[0] & 0xf0) == 0x20)) {
-                               printk(KERN_WARNING PFX "Unable to set "
-                                       "XA params: 0x%2.2x\n", res_reg[1]);
-                       }
-                       sony_xa_mode = 1;
-               }
-               /* A non-XA disk.  Set the parms back if necessary. */
-               else if (sony_xa_mode) {
-                       params[0] = SONY_SD_DECODE_PARAM;
-                       params[1] = 0x0f;
-                       do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                                      params, 2, res_reg, &res_size);
-                       if ((res_size < 2)
-                           || ((res_reg[0] & 0xf0) == 0x20)) {
-                               printk(KERN_WARNING PFX "Unable to reset "
-                                       "XA params: 0x%2.2x\n", res_reg[1]);
-                       }
-                       sony_xa_mode = 0;
-               }
-
-               sony_spun_up = 1;
-       }
-
-       sony_usage++;
-
-       return 0;
-}
-
-
-/*
- * Close the drive.  Spin it down if no task is using it.  The spin
- * down will fail if playing audio, so audio play is OK.
- */
-static void scd_release(struct cdrom_device_info *cdi)
-{
-       if (sony_usage == 1) {
-               unsigned char res_reg[12];
-               unsigned int res_size;
-
-               do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg,
-                              &res_size);
-
-               sony_spun_up = 0;
-       }
-       sony_usage--;
-}
-
-static struct cdrom_device_ops scd_dops = {
-       .open                   = scd_open,
-       .release                = scd_release,
-       .drive_status           = scd_drive_status,
-       .media_changed          = scd_media_changed,
-       .tray_move              = scd_tray_move,
-       .lock_door              = scd_lock_door,
-       .select_speed           = scd_select_speed,
-       .get_last_session       = scd_get_last_session,
-       .get_mcn                = scd_get_mcn,
-       .reset                  = scd_reset,
-       .audio_ioctl            = scd_audio_ioctl,
-       .capability             = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK |
-                                 CDC_SELECT_SPEED | CDC_MULTI_SESSION |
-                                 CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
-                                 CDC_RESET | CDC_DRIVE_STATUS,
-       .n_minors               = 1,
-};
-
-static struct cdrom_device_info scd_info = {
-       .ops            = &scd_dops,
-       .speed          = 2,
-       .capacity       = 1,
-       .name           = "cdu31a"
-};
-
-static int scd_block_open(struct inode *inode, struct file *file)
-{
-       return cdrom_open(&scd_info, inode, file);
-}
-
-static int scd_block_release(struct inode *inode, struct file *file)
-{
-       return cdrom_release(&scd_info, file);
-}
-
-static int scd_block_ioctl(struct inode *inode, struct file *file,
-                               unsigned cmd, unsigned long arg)
-{
-       int retval;
-
-       /* The eject and close commands should be handled by Uniform CD-ROM
-        * driver - but I always got hard lockup instead of eject
-        * until I put this here.
-        */
-       switch (cmd) {
-               case CDROMEJECT:
-                       scd_lock_door(&scd_info, 0);
-                       retval = scd_tray_move(&scd_info, 1);
-                       break;
-               case CDROMCLOSETRAY:
-                       retval = scd_tray_move(&scd_info, 0);
-                       break;
-               case CDROMREADAUDIO:
-                       retval = scd_read_audio(&scd_info, CDROMREADAUDIO, arg);
-                       break;
-               default:
-                       retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg);
-       }
-       return retval;
-}
-
-static int scd_block_media_changed(struct gendisk *disk)
-{
-       return cdrom_media_changed(&scd_info);
-}
-
-static struct block_device_operations scd_bdops =
-{
-       .owner          = THIS_MODULE,
-       .open           = scd_block_open,
-       .release        = scd_block_release,
-       .ioctl          = scd_block_ioctl,
-       .media_changed  = scd_block_media_changed,
-};
-
-static struct gendisk *scd_gendisk;
-
-/* The different types of disc loading mechanisms supported */
-static char *load_mech[] __initdata =
-    { "caddy", "tray", "pop-up", "unknown" };
-
-static int __init
-get_drive_configuration(unsigned short base_io,
-                       unsigned char res_reg[], unsigned int *res_size)
-{
-       unsigned long retry_count;
-
-
-       if (!request_region(base_io, 4, "cdu31a"))
-               return 0;
-
-       /* Set the base address */
-       cdu31a_port = base_io;
-
-       /* Set up all the register locations */
-       sony_cd_cmd_reg = cdu31a_port + SONY_CMD_REG_OFFSET;
-       sony_cd_param_reg = cdu31a_port + SONY_PARAM_REG_OFFSET;
-       sony_cd_write_reg = cdu31a_port + SONY_WRITE_REG_OFFSET;
-       sony_cd_control_reg = cdu31a_port + SONY_CONTROL_REG_OFFSET;
-       sony_cd_status_reg = cdu31a_port + SONY_STATUS_REG_OFFSET;
-       sony_cd_result_reg = cdu31a_port + SONY_RESULT_REG_OFFSET;
-       sony_cd_read_reg = cdu31a_port + SONY_READ_REG_OFFSET;
-       sony_cd_fifost_reg = cdu31a_port + SONY_FIFOST_REG_OFFSET;
-
-       /*
-        * Check to see if anything exists at the status register location.
-        * I don't know if this is a good way to check, but it seems to work
-        * ok for me.
-        */
-       if (read_status_register() != 0xff) {
-               /*
-                * Reset the drive and wait for attention from it (to say it's reset).
-                * If you don't wait, the next operation will probably fail.
-                */
-               reset_drive();
-               retry_count = jiffies + SONY_RESET_TIMEOUT;
-               while (time_before(jiffies, retry_count)
-                      && (!is_attention())) {
-                       sony_sleep();
-               }
-
-#if 0
-               /* If attention is never seen probably not a CDU31a present */
-               if (!is_attention()) {
-                       res_reg[0] = 0x20;
-                       goto out_err;
-               }
-#endif
-
-               /*
-                * Get the drive configuration.
-                */
-               do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD,
-                              NULL,
-                              0, (unsigned char *) res_reg, res_size);
-               if (*res_size <= 2 || (res_reg[0] & 0xf0) != 0)
-                       goto out_err;
-               return 1;
-       }
-
-       /* Return an error */
-       res_reg[0] = 0x20;
-out_err:
-       release_region(cdu31a_port, 4);
-       cdu31a_port = 0;
-       return 0;
-}
-
-#ifndef MODULE
-/*
- * Set up base I/O and interrupts, called from main.c.
- */
-
-static int __init cdu31a_setup(char *strings)
-{
-       int ints[4];
-
-       (void) get_options(strings, ARRAY_SIZE(ints), ints);
-
-       if (ints[0] > 0) {
-               cdu31a_port = ints[1];
-       }
-       if (ints[0] > 1) {
-               cdu31a_irq = ints[2];
-       }
-       if ((strings != NULL) && (*strings != '\0')) {
-               if (strcmp(strings, "PAS") == 0) {
-                       sony_pas_init = 1;
-               } else {
-                       printk(KERN_NOTICE PFX "Unknown interface type: %s\n",
-                              strings);
-               }
-       }
-
-       return 1;
-}
-
-__setup("cdu31a=", cdu31a_setup);
-
-#endif
-
-/*
- * Initialize the driver.
- */
-int __init cdu31a_init(void)
-{
-       struct s_sony_drive_config drive_config;
-       struct gendisk *disk;
-       int deficiency = 0;
-       unsigned int res_size;
-       char msg[255];
-       char buf[40];
-       int i;
-       int tmp_irq;
-
-       /*
-        * According to Alex Freed (freed@europa.orion.adobe.com), this is
-        * required for the Fusion CD-16 package.  If the sound driver is
-        * loaded, it should work fine, but just in case...
-        *
-        * The following turn on the CD-ROM interface for a Fusion CD-16.
-        */
-       if (sony_pas_init) {
-               outb(0xbc, 0x9a01);
-               outb(0xe2, 0x9a01);
-       }
-
-       /* Setting the base I/O address to 0xffff will disable it. */
-       if (cdu31a_port == 0xffff)
-               goto errout3;
-
-       if (cdu31a_port != 0) {
-               /* Need IRQ 0 because we can't sleep here. */
-               tmp_irq = cdu31a_irq;
-               cdu31a_irq = 0;
-               if (!get_drive_configuration(cdu31a_port,
-                                           drive_config.exec_status,
-                                           &res_size))
-                       goto errout3;
-               cdu31a_irq = tmp_irq;
-       } else {
-               cdu31a_irq = 0;
-               for (i = 0; cdu31a_addresses[i].base; i++) {
-                       if (get_drive_configuration(cdu31a_addresses[i].base,
-                                                    drive_config.exec_status,
-                                                    &res_size)) {
-                               cdu31a_irq = cdu31a_addresses[i].int_num;
-                               break;
-                       }
-               }
-               if (!cdu31a_port)
-                       goto errout3;
-       }
-
-       if (register_blkdev(MAJOR_NR, "cdu31a"))
-               goto errout2;
-
-       disk = alloc_disk(1);
-       if (!disk)
-               goto errout1;
-       disk->major = MAJOR_NR;
-       disk->first_minor = 0;
-       sprintf(disk->disk_name, "cdu31a");
-       disk->fops = &scd_bdops;
-       disk->flags = GENHD_FL_CD;
-
-       if (SONY_HWC_DOUBLE_SPEED(drive_config))
-               is_double_speed = 1;
-
-       tmp_irq = cdu31a_irq;   /* Need IRQ 0 because we can't sleep here. */
-       cdu31a_irq = 0;
-
-       sony_speed = is_double_speed; /* Set 2X drives to 2X by default */
-       set_drive_params(sony_speed);
-
-       cdu31a_irq = tmp_irq;
-
-       if (cdu31a_irq > 0) {
-               if (request_irq
-                   (cdu31a_irq, cdu31a_interrupt, IRQF_DISABLED,
-                    "cdu31a", NULL)) {
-                       printk(KERN_WARNING PFX "Unable to grab IRQ%d for "
-                                       "the CDU31A driver\n", cdu31a_irq);
-                       cdu31a_irq = 0;
-               }
-       }
-
-       sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
-               drive_config.vendor_id,
-               drive_config.product_id,
-               drive_config.product_rev_level);
-       sprintf(buf, "  Capabilities: %s",
-               load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]);
-       strcat(msg, buf);
-       if (SONY_HWC_AUDIO_PLAYBACK(drive_config))
-               strcat(msg, ", audio");
-       else
-               deficiency |= CDC_PLAY_AUDIO;
-       if (SONY_HWC_EJECT(drive_config))
-               strcat(msg, ", eject");
-       else
-               deficiency |= CDC_OPEN_TRAY;
-       if (SONY_HWC_LED_SUPPORT(drive_config))
-               strcat(msg, ", LED");
-       if (SONY_HWC_ELECTRIC_VOLUME(drive_config))
-               strcat(msg, ", elec. Vol");
-       if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config))
-               strcat(msg, ", sep. Vol");
-       if (is_double_speed)
-               strcat(msg, ", double speed");
-       else
-               deficiency |= CDC_SELECT_SPEED;
-       if (cdu31a_irq > 0) {
-               sprintf(buf, ", irq %d", cdu31a_irq);
-               strcat(msg, buf);
-       }
-       strcat(msg, "\n");
-       printk(KERN_INFO PFX "%s",msg);
-
-       cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock);
-       if (!cdu31a_queue)
-               goto errout0;
-       blk_queue_hardsect_size(cdu31a_queue, 2048);
-
-       init_timer(&cdu31a_abort_timer);
-       cdu31a_abort_timer.function = handle_abort_timeout;
-
-       scd_info.mask = deficiency;
-       scd_gendisk = disk;
-       if (register_cdrom(&scd_info))
-               goto err;
-       disk->queue = cdu31a_queue;
-       add_disk(disk);
-
-       disk_changed = 1;
-       return 0;
-
-err:
-       blk_cleanup_queue(cdu31a_queue);
-errout0:
-       if (cdu31a_irq)
-               free_irq(cdu31a_irq, NULL);
-       printk(KERN_ERR PFX "Unable to register with Uniform cdrom driver\n");
-       put_disk(disk);
-errout1:
-       if (unregister_blkdev(MAJOR_NR, "cdu31a")) {
-               printk(KERN_WARNING PFX "Can't unregister block device\n");
-       }
-errout2:
-       release_region(cdu31a_port, 4);
-errout3:
-       return -EIO;
-}
-
-
-static void __exit cdu31a_exit(void)
-{
-       del_gendisk(scd_gendisk);
-       put_disk(scd_gendisk);
-       if (unregister_cdrom(&scd_info)) {
-               printk(KERN_WARNING PFX "Can't unregister from Uniform "
-                               "cdrom driver\n");
-               return;
-       }
-       if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) {
-               printk(KERN_WARNING PFX "Can't unregister\n");
-               return;
-       }
-
-       blk_cleanup_queue(cdu31a_queue);
-
-       if (cdu31a_irq > 0)
-               free_irq(cdu31a_irq, NULL);
-
-       release_region(cdu31a_port, 4);
-       printk(KERN_INFO PFX "module released.\n");
-}
-
-#ifdef MODULE
-module_init(cdu31a_init);
-#endif
-module_exit(cdu31a_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(CDU31A_CDROM_MAJOR);
diff --git a/drivers/cdrom/cdu31a.h b/drivers/cdrom/cdu31a.h
deleted file mode 100644 (file)
index 61d4768..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Definitions for a Sony interface CDROM drive.
- *
- * Corey Minyard (minyard@wf-rch.cirr.com)
- *
- *  Copyright (C) 1993  Corey Minyard
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
- * General defines.
- */
-#define SONY_XA_DISK_TYPE 0x20
-
-/*
- * Offsets (from the base address) and bits for the various write registers
- * of the drive.
- */
-#define SONY_CMD_REG_OFFSET     0
-#define SONY_PARAM_REG_OFFSET   1
-#define SONY_WRITE_REG_OFFSET   2
-#define SONY_CONTROL_REG_OFFSET 3
-#       define SONY_ATTN_CLR_BIT        0x01
-#       define SONY_RES_RDY_CLR_BIT     0x02
-#       define SONY_DATA_RDY_CLR_BIT    0x04
-#       define SONY_ATTN_INT_EN_BIT     0x08
-#       define SONY_RES_RDY_INT_EN_BIT  0x10
-#       define SONY_DATA_RDY_INT_EN_BIT 0x20
-#       define SONY_PARAM_CLR_BIT       0x40
-#       define SONY_DRIVE_RESET_BIT     0x80
-
-/*
- * Offsets (from the base address) and bits for the various read registers
- * of the drive.
- */
-#define SONY_STATUS_REG_OFFSET  0
-#       define SONY_ATTN_BIT            0x01
-#       define SONY_RES_RDY_BIT         0x02
-#       define SONY_DATA_RDY_BIT        0x04
-#       define SONY_ATTN_INT_ST_BIT     0x08
-#       define SONY_RES_RDY_INT_ST_BIT  0x10
-#       define SONY_DATA_RDY_INT_ST_BIT 0x20
-#       define SONY_DATA_REQUEST_BIT    0x40
-#       define SONY_BUSY_BIT            0x80
-#define SONY_RESULT_REG_OFFSET  1
-#define SONY_READ_REG_OFFSET    2
-#define SONY_FIFOST_REG_OFFSET  3
-#       define SONY_PARAM_WRITE_RDY_BIT 0x01
-#       define SONY_PARAM_REG_EMPTY_BIT 0x02
-#       define SONY_RES_REG_NOT_EMP_BIT 0x04
-#       define SONY_RES_REG_FULL_BIT    0x08
-
-#define LOG_START_OFFSET        150     /* Offset of first logical sector */
-
-#define SONY_DETECT_TIMEOUT    (8*HZ/10) /* Maximum amount of time
-                                           that drive detection code
-                                           will wait for response
-                                           from drive (in 1/100th's
-                                           of seconds). */
-#define SONY_JIFFIES_TIMEOUT    (10*HZ)        /* Maximum number of times the
-                                           drive will wait/try for an
-                                           operation */
-#define SONY_RESET_TIMEOUT      HZ     /* Maximum number of times the
-                                           drive will wait/try a reset
-                                           operation */
-#define SONY_READY_RETRIES      20000   /* How many times to retry a
-                                           spin waiting for a register
-                                           to come ready */
-
-#define MAX_CDU31A_RETRIES      3       /* How many times to retry an
-                                           operation */
-
-/* Commands to request or set drive control parameters and disc information */
-#define SONY_REQ_DRIVE_CONFIG_CMD       0x00    /* Returns s_sony_drive_config */
-#define SONY_REQ_DRIVE_MODE_CMD         0x01
-#define SONY_REQ_DRIVE_PARAM_CMD        0x02
-#define SONY_REQ_MECH_STATUS_CMD        0x03
-#define SONY_REQ_AUDIO_STATUS_CMD       0x04
-#define SONY_SET_DRIVE_PARAM_CMD        0x10
-#define SONY_REQ_TOC_DATA_CMD           0x20    /* Returns s_sony_toc */
-#define SONY_REQ_SUBCODE_ADDRESS_CMD    0x21    /* Returns s_sony_subcode */
-#define SONY_REQ_UPC_EAN_CMD            0x22
-#define SONY_REQ_ISRC_CMD               0x23
-#define SONY_REQ_TOC_DATA_SPEC_CMD      0x24    /* Returns s_sony_session_toc */
-
-/* Commands to request information from the drive */
-#define SONY_READ_TOC_CMD               0x30    /* let the drive firmware grab the TOC */
-#define SONY_SEEK_CMD                   0x31
-#define SONY_READ_CMD                   0x32
-#define SONY_READ_BLKERR_STAT_CMD       0x34
-#define SONY_ABORT_CMD                  0x35
-#define SONY_READ_TOC_SPEC_CMD          0x36
-
-/* Commands to control audio */
-#define SONY_AUDIO_PLAYBACK_CMD         0x40
-#define SONY_AUDIO_STOP_CMD             0x41
-#define SONY_AUDIO_SCAN_CMD             0x42
-
-/* Miscellaneous control commands */
-#define SONY_EJECT_CMD                  0x50
-#define SONY_SPIN_UP_CMD                0x51
-#define SONY_SPIN_DOWN_CMD              0x52
-
-/* Diagnostic commands */
-#define SONY_WRITE_BUFFER_CMD           0x60
-#define SONY_READ_BUFFER_CMD            0x61
-#define SONY_DIAGNOSTICS_CMD            0x62
-
-
-/*
- * The following are command parameters for the set drive parameter command
- */
-#define SONY_SD_DECODE_PARAM            0x00
-#define SONY_SD_INTERFACE_PARAM         0x01
-#define SONY_SD_BUFFERING_PARAM         0x02
-#define SONY_SD_AUDIO_PARAM             0x03
-#define SONY_SD_AUDIO_VOLUME            0x04
-#define SONY_SD_MECH_CONTROL            0x05
-#define SONY_SD_AUTO_SPIN_DOWN_TIME     0x06
-
-/*
- * The following are parameter bits for the mechanical control command
- */
-#define SONY_AUTO_SPIN_UP_BIT           0x01
-#define SONY_AUTO_EJECT_BIT             0x02
-#define SONY_DOUBLE_SPEED_BIT           0x04
-
-/*
- * The following extract information from the drive configuration about
- * the drive itself.
- */
-#define SONY_HWC_GET_LOAD_MECH(c)       (c.hw_config[0] & 0x03)
-#define SONY_HWC_EJECT(c)               (c.hw_config[0] & 0x04)
-#define SONY_HWC_LED_SUPPORT(c)         (c.hw_config[0] & 0x08)
-#define SONY_HWC_DOUBLE_SPEED(c)        (c.hw_config[0] & 0x10)
-#define SONY_HWC_GET_BUF_MEM_SIZE(c)    ((c.hw_config[0] & 0xc0) >> 6)
-#define SONY_HWC_AUDIO_PLAYBACK(c)      (c.hw_config[1] & 0x01)
-#define SONY_HWC_ELECTRIC_VOLUME(c)     (c.hw_config[1] & 0x02)
-#define SONY_HWC_ELECTRIC_VOLUME_CTL(c) (c.hw_config[1] & 0x04)
-
-#define SONY_HWC_CADDY_LOAD_MECH        0x00
-#define SONY_HWC_TRAY_LOAD_MECH         0x01
-#define SONY_HWC_POPUP_LOAD_MECH        0x02
-#define SONY_HWC_UNKWN_LOAD_MECH        0x03
-
-#define SONY_HWC_8KB_BUFFER             0x00
-#define SONY_HWC_32KB_BUFFER            0x01
-#define SONY_HWC_64KB_BUFFER            0x02
-#define SONY_HWC_UNKWN_BUFFER           0x03
-
-/*
- * This is the complete status returned from the drive configuration request
- * command.
- */
-struct s_sony_drive_config
-{
-   unsigned char exec_status[2];
-   char vendor_id[8];
-   char product_id[16];
-   char product_rev_level[8];
-   unsigned char hw_config[2];
-};
-
-/* The following is returned from the request subcode address command */
-struct s_sony_subcode
-{
-   unsigned char exec_status[2];
-   unsigned char address        :4;
-   unsigned char control        :4;
-   unsigned char track_num;
-   unsigned char index_num;
-   unsigned char rel_msf[3];
-   unsigned char reserved1;
-   unsigned char abs_msf[3];
-};
-
-#define MAX_TRACKS 100 /* The maximum tracks a disk may have. */
-/*
- * The following is returned from the request TOC (Table Of Contents) command.
- * (last_track_num-first_track_num+1) values are valid in tracks.
- */
-struct s_sony_toc
-{
-   unsigned char exec_status[2];
-   unsigned char address0       :4;
-   unsigned char control0       :4;
-   unsigned char point0;
-   unsigned char first_track_num;
-   unsigned char disk_type;
-   unsigned char dummy0;
-   unsigned char address1       :4;
-   unsigned char control1       :4;
-   unsigned char point1;
-   unsigned char last_track_num;
-   unsigned char dummy1;
-   unsigned char dummy2;
-   unsigned char address2       :4;
-   unsigned char control2       :4;
-   unsigned char point2;
-   unsigned char lead_out_start_msf[3];
-   struct
-   {
-      unsigned char address     :4;
-      unsigned char control     :4;
-      unsigned char track;
-      unsigned char track_start_msf[3];
-   } tracks[MAX_TRACKS];
-
-   unsigned int lead_out_start_lba;
-};
-
-struct s_sony_session_toc
-{
-   unsigned char exec_status[2];
-   unsigned char session_number;
-   unsigned char address0       :4;
-   unsigned char control0       :4;
-   unsigned char point0;
-   unsigned char first_track_num;
-   unsigned char disk_type;
-   unsigned char dummy0;
-   unsigned char address1       :4;
-   unsigned char control1       :4;
-   unsigned char point1;
-   unsigned char last_track_num;
-   unsigned char dummy1;
-   unsigned char dummy2;
-   unsigned char address2       :4;
-   unsigned char control2       :4;
-   unsigned char point2;
-   unsigned char lead_out_start_msf[3];
-   unsigned char addressb0      :4;
-   unsigned char controlb0      :4;
-   unsigned char pointb0;
-   unsigned char next_poss_prog_area_msf[3];
-   unsigned char num_mode_5_pointers;
-   unsigned char max_start_outer_leadout_msf[3];
-   unsigned char addressb1      :4;
-   unsigned char controlb1      :4;
-   unsigned char pointb1;
-   unsigned char dummyb0_1[4];
-   unsigned char num_skip_interval_pointers;
-   unsigned char num_skip_track_assignments;
-   unsigned char dummyb0_2;
-   unsigned char addressb2      :4;
-   unsigned char controlb2      :4;
-   unsigned char pointb2;
-   unsigned char tracksb2[7];
-   unsigned char addressb3      :4;
-   unsigned char controlb3      :4;
-   unsigned char pointb3;
-   unsigned char tracksb3[7];
-   unsigned char addressb4      :4;
-   unsigned char controlb4      :4;
-   unsigned char pointb4;
-   unsigned char tracksb4[7];
-   unsigned char addressc0      :4;
-   unsigned char controlc0      :4;
-   unsigned char pointc0;
-   unsigned char dummyc0[7];
-   struct
-   {
-      unsigned char address     :4;
-      unsigned char control     :4;
-      unsigned char track;
-      unsigned char track_start_msf[3];
-   } tracks[MAX_TRACKS];
-
-   unsigned int start_track_lba;
-   unsigned int lead_out_start_lba;
-   unsigned int mint;
-   unsigned int maxt;
-};
-
-struct s_all_sessions_toc
-{
-   unsigned char sessions;
-   unsigned int track_entries;
-   unsigned char first_track_num;
-   unsigned char last_track_num;
-   unsigned char disk_type;
-   unsigned char lead_out_start_msf[3];
-   struct
-   {
-      unsigned char address     :4;
-      unsigned char control     :4;
-      unsigned char track;
-      unsigned char track_start_msf[3];
-   } tracks[MAX_TRACKS];
-
-   unsigned int start_track_lba;
-   unsigned int lead_out_start_lba;
-};
-
-
-/*
- * The following are errors returned from the drive.
- */
-
-/* Command error group */
-#define SONY_ILL_CMD_ERR                0x10
-#define SONY_ILL_PARAM_ERR              0x11
-
-/* Mechanism group */
-#define SONY_NOT_LOAD_ERR               0x20
-#define SONY_NO_DISK_ERR                0x21
-#define SONY_NOT_SPIN_ERR               0x22
-#define SONY_SPIN_ERR                   0x23
-#define SONY_SPINDLE_SERVO_ERR          0x25
-#define SONY_FOCUS_SERVO_ERR            0x26
-#define SONY_EJECT_MECH_ERR             0x29
-#define SONY_AUDIO_PLAYING_ERR          0x2a
-#define SONY_EMERGENCY_EJECT_ERR        0x2c
-
-/* Seek error group */
-#define SONY_FOCUS_ERR                  0x30
-#define SONY_FRAME_SYNC_ERR             0x31
-#define SONY_SUBCODE_ADDR_ERR           0x32
-#define SONY_BLOCK_SYNC_ERR             0x33
-#define SONY_HEADER_ADDR_ERR            0x34
-
-/* Read error group */
-#define SONY_ILL_TRACK_R_ERR            0x40
-#define SONY_MODE_0_R_ERR               0x41
-#define SONY_ILL_MODE_R_ERR             0x42
-#define SONY_ILL_BLOCK_SIZE_R_ERR       0x43
-#define SONY_MODE_R_ERR                 0x44
-#define SONY_FORM_R_ERR                 0x45
-#define SONY_LEAD_OUT_R_ERR             0x46
-#define SONY_BUFFER_OVERRUN_R_ERR       0x47
-
-/* Data error group */
-#define SONY_UNREC_CIRC_ERR             0x53
-#define SONY_UNREC_LECC_ERR             0x57
-
-/* Subcode error group */
-#define SONY_NO_TOC_ERR                 0x60
-#define SONY_SUBCODE_DATA_NVAL_ERR      0x61
-#define SONY_FOCUS_ON_TOC_READ_ERR      0x63
-#define SONY_FRAME_SYNC_ON_TOC_READ_ERR 0x64
-#define SONY_TOC_DATA_ERR               0x65
-
-/* Hardware failure group */
-#define SONY_HW_FAILURE_ERR             0x70
-#define SONY_LEAD_IN_A_ERR              0x91
-#define SONY_LEAD_OUT_A_ERR             0x92
-#define SONY_DATA_TRACK_A_ERR           0x93
-
-/*
- * The following are returned from the Read With Block Error Status command.
- * They are not errors but information (Errors from the 0x5x group above may
- * also be returned
- */
-#define SONY_NO_CIRC_ERR_BLK_STAT       0x50
-#define SONY_NO_LECC_ERR_BLK_STAT       0x54
-#define SONY_RECOV_LECC_ERR_BLK_STAT    0x55
-#define SONY_NO_ERR_DETECTION_STAT      0x59
-
-/* 
- * The following is not an error returned by the drive, but by the code
- * that talks to the drive.  It is returned because of a timeout.
- */
-#define SONY_TIMEOUT_OP_ERR             0x01
-#define SONY_SIGNAL_OP_ERR              0x02
-#define SONY_BAD_DATA_ERR               0x03
-
-
-/*
- * The following are attention code for asynchronous events from the drive.
- */
-
-/* Standard attention group */
-#define SONY_EMER_EJECT_ATTN            0x2c
-#define SONY_HW_FAILURE_ATTN            0x70
-#define SONY_MECH_LOADED_ATTN           0x80
-#define SONY_EJECT_PUSHED_ATTN          0x81
-
-/* Audio attention group */
-#define SONY_AUDIO_PLAY_DONE_ATTN       0x90
-#define SONY_LEAD_IN_ERR_ATTN           0x91
-#define SONY_LEAD_OUT_ERR_ATTN          0x92
-#define SONY_DATA_TRACK_ERR_ATTN        0x93
-#define SONY_AUDIO_PLAYBACK_ERR_ATTN    0x94
-
-/* Auto spin up group */
-#define SONY_SPIN_UP_COMPLETE_ATTN      0x24
-#define SONY_SPINDLE_SERVO_ERR_ATTN     0x25
-#define SONY_FOCUS_SERVO_ERR_ATTN       0x26
-#define SONY_TOC_READ_DONE_ATTN         0x62
-#define SONY_FOCUS_ON_TOC_READ_ERR_ATTN 0x63
-#define SONY_SYNC_ON_TOC_READ_ERR_ATTN  0x65
-
-/* Auto eject group */
-#define SONY_SPIN_DOWN_COMPLETE_ATTN    0x27
-#define SONY_EJECT_COMPLETE_ATTN        0x28
-#define SONY_EJECT_MECH_ERR_ATTN        0x29
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
deleted file mode 100644 (file)
index 2301311..0000000
+++ /dev/null
@@ -1,1594 +0,0 @@
-/* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card.
-   Copyright (c) 1995--1997 David A. van Leeuwen.
-   $Id: cm206.c,v 1.5 1997/12/26 11:02:51 david Exp $
-   
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-     
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-     GNU General Public License for more details.
-     
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-History:
- Started 25 jan 1994. Waiting for documentation...
- 22 feb 1995: 0.1a first reasonably safe polling driver.
-             Two major bugs, one in read_sector and one in 
-             do_cm206_request, happened to cancel!
- 25 feb 1995: 0.2a first reasonable interrupt driven version of above.
-              uart writes are still done in polling mode. 
- 25 feb 1995: 0.21a writes also in interrupt mode, still some
-             small bugs to be found... Larger buffer. 
-  2 mrt 1995: 0.22 Bug found (cd-> nowhere, interrupt was called in
-              initialization), read_ahead of 16. Timeouts implemented.
-             unclear if they do something...
-  7 mrt 1995: 0.23 Start of background read-ahead.
- 18 mrt 1995: 0.24 Working background read-ahead. (still problems)
- 26 mrt 1995: 0.25 Multi-session ioctl added (kernel v1.2).
-              Statistics implemented, though separate stats206.h.
-             Accessible through ioctl 0x1000 (just a number).
-             Hard to choose between v1.2 development and 1.1.75.
-             Bottom-half doesn't work with 1.2...
-             0.25a: fixed... typo. Still problems...
-  1 apr 1995: 0.26 Module support added. Most bugs found. Use kernel 1.2.n.
-  5 apr 1995: 0.27 Auto-probe for the adapter card base address.
-              Auto-probe for the adaptor card irq line.
-  7 apr 1995: 0.28 Added lilo setup support for base address and irq.
-              Use major number 32 (not in this source), officially
-             assigned to this driver.
-  9 apr 1995: 0.29 Added very limited audio support. Toc_header, stop, pause,
-              resume, eject. Play_track ignores track info, because we can't 
-             read a table-of-contents entry. Toc_entry is implemented
-             as a `placebo' function: always returns start of disc. 
-  3 may 1995: 0.30 Audio support completed. The get_toc_entry function
-              is implemented as a binary search. 
- 15 may 1995: 0.31 More work on audio stuff. Workman is not easy to 
-              satisfy; changed binary search into linear search.
-             Auto-probe for base address somewhat relaxed.
-  1 jun 1995: 0.32 Removed probe_irq_on/off for module version.
- 10 jun 1995: 0.33 Workman still behaves funny, but you should be
-              able to eject and substitute another disc.
-
- An adaptation of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg
-
- 18 jul 1995: 0.34 Patch by Heiko Eissfeldt included, mainly considering 
-              verify_area's in the ioctls. Some bugs introduced by 
-             EM considering the base port and irq fixed. 
-
- 18 dec 1995: 0.35 Add some code for error checking... no luck...
-
- We jump to reach our goal: version 1.0 in the next stable linux kernel.
-
- 19 mar 1996: 0.95 Different implementation of CDROM_GET_UPC, on
-             request of Thomas Quinot. 
- 25 mar 1996: 0.96 Interpretation of opening with O_WRONLY or O_RDWR:
-             open only for ioctl operation, e.g., for operation of
-             tray etc.
- 4 apr 1996:  0.97 First implementation of layer between VFS and cdrom
-              driver, a generic interface. Much of the functionality
-             of cm206_open() and cm206_ioctl() is transferred to a
-             new file cdrom.c and its header ucdrom.h. 
-
-             Upgrade to Linux kernel 1.3.78. 
-
- 11 apr 1996  0.98 Upgrade to Linux kernel 1.3.85
-              More code moved to cdrom.c
-             0.99 Some more small changes to decrease number
-             of oopses at module load; 
- 27 jul 1996  0.100 Many hours of debugging, kernel change from 1.2.13
-             to 2.0.7 seems to have introduced some weird behavior
-             in (interruptible_)sleep_on(&cd->data): the process
-             seems to be woken without any explicit wake_up in my own
-             code. Patch to try 100x in case such untriggered wake_up's 
-             occur. 
-
- 28 jul 1996  0.101 Rewriting of the code that receives the command echo,
-             using a fifo to store echoed bytes. 
-
-             Branch from 0.99:
-             0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t
-             (emoenke) various typos found by others.  extra
-             module-load oops protection.
-             0.99.1.1 Initialization constant cdrom_dops.speed
-             changed from float (2.0) to int (2); Cli()-sti() pair
-             around cm260_reset() in module initialization code.
-             0.99.1.2 Changes literally as proposed by Scott Snyder
-             <snyder@d0sgif.fnal.gov> for the 2.1 kernel line, which
-             have to do mainly with the poor minor support i had. The
-             major new concept is to change a cdrom driver's
-             operations struct from the capabilities struct. This
-             reflects the fact that there is one major for a driver,
-             whilst there can be many minors whith completely
-             different capabilities.
-
-             0.99.1.3 More changes for operations/info separation.
-
-             0.99.1.4 Added speed selection (someone had to do this
-             first).
-
-  23 jan 1997 0.99.1.5 MODULE_PARMS call added.
-
-  23 jan 1997 0.100.1.2--0.100.1.5 following similar lines as 
-             0.99.1.1--0.99.1.5. I get too many complaints about the
-             drive making read errors. What't wrong with the 2.0+
-             kernel line? Why get i (and othe cm206 owners) weird
-             results? Why were things good in the good old 1.1--1.2 
-             era? Why don't i throw away the drive?
-
- 2 feb 1997   0.102 Added `volatile' to values in cm206_struct. Seems to 
-             reduce many of the problems. Rewrote polling routines
-             to use fixed delays between polls. 
-             0.103 Changed printk behavior. 
-             0.104 Added a 0.100 -> 0.100.1.1 change
-
-11 feb 1997   0.105 Allow auto_probe during module load, disable
-              with module option "auto_probe=0". Moved some debugging
-             statements to lower priority. Implemented select_speed()
-             function. 
-
-13 feb 1997   1.0 Final version for 2.0 kernel line. 
-
-             All following changes will be for the 2.1 kernel line. 
-
-15 feb 1997   1.1 Keep up with kernel 2.1.26, merge in changes from 
-              cdrom.c 0.100.1.1--1.0. Add some more MODULE_PARMS. 
-
-14 sep 1997   1.2 Upgrade to Linux 2.1.55.  Added blksize_size[], patch
-              sent by James Bottomley <James.Bottomley@columbiasc.ncr.com>.
-
-21 dec 1997   1.4 Upgrade to Linux 2.1.72.  
-
-24 jan 1998   Removed the cm206_disc_status() function, as it was now dead
-              code.  The Uniform CDROM driver now provides this functionality.
-             
-9 Nov. 1999   Make kernel-parameter implementation work with 2.3.x 
-             Removed init_module & cleanup_module in favor of 
-             module_init & module_exit.
-             Torben Mathiasen <tmm@image.dk>
- * 
- * Parts of the code are based upon lmscd.c written by Kai Petzke,
- * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin
- * Harriss, but any off-the-shelf dynamic programming algorithm won't
- * be able to find them.
- *
- * The cm206 drive interface and the cm260 adapter card seem to be 
- * sufficiently different from their cm205/cm250 counterparts
- * in order to write a complete new driver.
- * 
- * I call all routines connected to the Linux kernel something
- * with `cm206' in it, as this stuff is too series-dependent. 
- * 
- * Currently, my limited knowledge is based on:
- * - The Linux Kernel Hacker's guide, v. 0.5, by Michael K. Johnson
- * - Linux Kernel Programmierung, by Michael Beck and others
- * - Philips/LMS cm206 and cm226 product specification
- * - Philips/LMS cm260 product specification
- *
- * David van Leeuwen, david@tm.tno.nl.  */
-#define REVISION "$Revision: 1.5 $"
-
-#include <linux/module.h>
-
-#include <linux/errno.h>       /* These include what we really need */
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-/* #include <linux/ucdrom.h> */
-
-#include <asm/io.h>
-
-#define MAJOR_NR CM206_CDROM_MAJOR
-
-#include <linux/blkdev.h>
-
-#undef DEBUG
-#define STATISTICS             /* record times and frequencies of events */
-#define AUTO_PROBE_MODULE
-#define USE_INSW
-
-#include "cm206.h"
-
-/* This variable defines whether or not to probe for adapter base port 
-   address and interrupt request. It can be overridden by the boot 
-   parameter `auto'.
-*/
-static int auto_probe = 1;     /* Yes, why not? */
-
-static int cm206_base = CM206_BASE;
-static int cm206_irq = CM206_IRQ;
-#ifdef MODULE
-static int cm206[2] = { 0, 0 };        /* for compatible `insmod' parameter passing */
-module_param_array(cm206, int, NULL, 0);       /* base,irq or irq,base */
-#endif
-
-module_param(cm206_base, int, 0);      /* base */
-module_param(cm206_irq, int, 0);       /* irq */
-module_param(auto_probe, bool, 0);     /* auto probe base and irq */
-MODULE_LICENSE("GPL");
-
-#define POLLOOP 100            /* milliseconds */
-#define READ_AHEAD 1           /* defines private buffer, waste! */
-#define BACK_AHEAD 1           /* defines adapter-read ahead */
-#define DATA_TIMEOUT (3*HZ)    /* measured in jiffies (10 ms) */
-#define UART_TIMEOUT (5*HZ/100)
-#define DSB_TIMEOUT (7*HZ)     /* time for the slowest command to finish */
-#define UR_SIZE 4              /* uart receive buffer fifo size */
-
-#define LINUX_BLOCK_SIZE 512   /* WHERE is this defined? */
-#define RAW_SECTOR_SIZE 2352   /* ok, is also defined in cdrom.h */
-#define ISO_SECTOR_SIZE 2048
-#define BLOCKS_ISO (ISO_SECTOR_SIZE/LINUX_BLOCK_SIZE)  /* 4 */
-#define CD_SYNC_HEAD 16                /* CD_SYNC + CD_HEAD */
-
-#ifdef STATISTICS              /* keep track of errors in counters */
-#define stats(i) { ++cd->stats[st_ ## i]; \
-                    cd->last_stat[st_ ## i] = cd->stat_counter++; \
-                }
-#else
-#define stats(i) (void) 0;
-#endif
-
-#define Debug(a) {printk (KERN_DEBUG); printk a;}
-#ifdef DEBUG
-#define debug(a) Debug(a)
-#else
-#define debug(a) (void) 0;
-#endif
-
-typedef unsigned char uch;     /* 8-bits */
-typedef unsigned short ush;    /* 16-bits */
-
-struct toc_struct {            /* private copy of Table of Contents */
-       uch track, fsm[3], q0;
-};
-
-struct cm206_struct {
-       volatile ush intr_ds;   /* data status read on last interrupt */
-       volatile ush intr_ls;   /* uart line status read on last interrupt */
-       volatile uch ur[UR_SIZE];       /* uart receive buffer fifo */
-       volatile uch ur_w, ur_r;        /* write/read buffer index */
-       volatile uch dsb, cc;   /* drive status byte and condition (error) code */
-       int command;            /* command to be written to the uart */
-       int openfiles;
-       ush sector[READ_AHEAD * RAW_SECTOR_SIZE / 2];   /* buffered cd-sector */
-       int sector_first, sector_last;  /* range of these sectors */
-       wait_queue_head_t uart; /* wait queues for interrupt */
-       wait_queue_head_t data;
-       struct timer_list timer;        /* time-out */
-       char timed_out;
-       signed char max_sectors;        /* number of sectors that fit in adapter mem */
-       char wait_back;         /* we're waiting for a background-read */
-       char background;        /* is a read going on in the background? */
-       int adapter_first;      /* if so, that's the starting sector */
-       int adapter_last;
-       char fifo_overflowed;
-       uch disc_status[7];     /* result of get_disc_status command */
-#ifdef STATISTICS
-       int stats[NR_STATS];
-       int last_stat[NR_STATS];        /* `time' at which stat was stat */
-       int stat_counter;
-#endif
-       struct toc_struct toc[101];     /* The whole table of contents + lead-out */
-       uch q[10];              /* Last read q-channel info */
-       uch audio_status[5];    /* last read position on pause */
-       uch media_changed;      /* record if media changed */
-};
-
-#define DISC_STATUS cd->disc_status[0]
-#define FIRST_TRACK cd->disc_status[1]
-#define LAST_TRACK cd->disc_status[2]
-#define PAUSED cd->audio_status[0]     /* misuse this memory byte! */
-#define PLAY_TO cd->toc[0]     /* toc[0] records end-time in play */
-
-static struct cm206_struct *cd;        /* the main memory structure */
-static struct request_queue *cm206_queue;
-static DEFINE_SPINLOCK(cm206_lock);
-
-/* First, we define some polling functions. These are actually
-   only being used in the initialization. */
-
-static void send_command_polled(int command)
-{
-       int loop = POLLOOP;
-       while (!(inw(r_line_status) & ls_transmitter_buffer_empty)
-              && loop > 0) {
-               mdelay(1);      /* one millisec delay */
-               --loop;
-       }
-       outw(command, r_uart_transmit);
-}
-
-static uch receive_echo_polled(void)
-{
-       int loop = POLLOOP;
-       while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) {
-               mdelay(1);
-               --loop;
-       }
-       return ((uch) inw(r_uart_receive));
-}
-
-static uch send_receive_polled(int command)
-{
-       send_command_polled(command);
-       return receive_echo_polled();
-}
-
-static inline void clear_ur(void)
-{
-       if (cd->ur_r != cd->ur_w) {
-               debug(("Deleting bytes from fifo:"));
-               for (; cd->ur_r != cd->ur_w;
-                    cd->ur_r++, cd->ur_r %= UR_SIZE)
-                       debug((" 0x%x", cd->ur[cd->ur_r]));
-               debug(("\n"));
-       }
-}
-
-static struct tasklet_struct cm206_tasklet;
-
-/* The interrupt handler. When the cm260 generates an interrupt, very
-   much care has to be taken in reading out the registers in the right
-   order; in case of a receive_buffer_full interrupt, first the
-   uart_receive must be read, and then the line status again to
-   de-assert the interrupt line. It took me a couple of hours to find
-   this out:-( 
-
-   The function reset_cm206 appears to cause an interrupt, because
-   pulling up the INIT line clears both the uart-write-buffer /and/
-   the uart-write-buffer-empty mask. We call this a `lost interrupt,'
-   as there seems so reason for this to happen.
-*/
-
-static irqreturn_t cm206_interrupt(int sig, void *dev_id)
-{
-       volatile ush fool;
-       cd->intr_ds = inw(r_data_status);       /* resets data_ready, data_error,
-                                                  crc_error, sync_error, toc_ready 
-                                                  interrupts */
-       cd->intr_ls = inw(r_line_status);       /* resets overrun bit */
-       debug(("Intr, 0x%x 0x%x, %d\n", cd->intr_ds, cd->intr_ls,
-              cd->background));
-       if (cd->intr_ls & ls_attention)
-               stats(attention);
-       /* receive buffer full? */
-       if (cd->intr_ls & ls_receive_buffer_full) {
-               cd->ur[cd->ur_w] = inb(r_uart_receive); /* get order right! */
-               cd->intr_ls = inw(r_line_status);       /* resets rbf interrupt */
-               debug(("receiving #%d: 0x%x\n", cd->ur_w,
-                      cd->ur[cd->ur_w]));
-               cd->ur_w++;
-               cd->ur_w %= UR_SIZE;
-               if (cd->ur_w == cd->ur_r)
-                       debug(("cd->ur overflow!\n"));
-               if (waitqueue_active(&cd->uart) && cd->background < 2) {
-                       del_timer(&cd->timer);
-                       wake_up_interruptible(&cd->uart);
-               }
-       }
-       /* data ready in fifo? */
-       else if (cd->intr_ds & ds_data_ready) {
-               if (cd->background)
-                       ++cd->adapter_last;
-               if (waitqueue_active(&cd->data)
-                   && (cd->wait_back || !cd->background)) {
-                       del_timer(&cd->timer);
-                       wake_up_interruptible(&cd->data);
-               }
-               stats(data_ready);
-       }
-       /* ready to issue a write command? */
-       else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) {
-               outw(dc_normal | (inw(r_data_status) & 0x7f),
-                    r_data_control);
-               outw(cd->command, r_uart_transmit);
-               cd->command = 0;
-               if (!cd->background)
-                       wake_up_interruptible(&cd->uart);
-       }
-       /* now treat errors (at least, identify them for debugging) */
-       else if (cd->intr_ds & ds_fifo_overflow) {
-               debug(("Fifo overflow at sectors 0x%x\n",
-                      cd->sector_first));
-               fool = inw(r_fifo_output_buffer);       /* de-assert the interrupt */
-               cd->fifo_overflowed = 1;        /* signal one word less should be read */
-               stats(fifo_overflow);
-       } else if (cd->intr_ds & ds_data_error) {
-               debug(("Data error at sector 0x%x\n", cd->sector_first));
-               stats(data_error);
-       } else if (cd->intr_ds & ds_crc_error) {
-               debug(("CRC error at sector 0x%x\n", cd->sector_first));
-               stats(crc_error);
-       } else if (cd->intr_ds & ds_sync_error) {
-               debug(("Sync at sector 0x%x\n", cd->sector_first));
-               stats(sync_error);
-       } else if (cd->intr_ds & ds_toc_ready) {
-               /* do something appropriate */
-       }
-       /* couldn't see why this interrupt, maybe due to init */
-       else {
-               outw(dc_normal | READ_AHEAD, r_data_control);
-               stats(lost_intr);
-       }
-       if (cd->background
-           && (cd->adapter_last - cd->adapter_first == cd->max_sectors
-               || cd->fifo_overflowed))
-               tasklet_schedule(&cm206_tasklet);       /* issue a stop read command */
-       stats(interrupt);
-       return IRQ_HANDLED;
-}
-
-/* we have put the address of the wait queue in who */
-static void cm206_timeout(unsigned long who)
-{
-       cd->timed_out = 1;
-       debug(("Timing out\n"));
-       wake_up_interruptible((wait_queue_head_t *) who);
-}
-
-/* This function returns 1 if a timeout occurred, 0 if an interrupt
-   happened */
-static int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
-{
-       cd->timed_out = 0;
-       init_timer(&cd->timer);
-       cd->timer.data = (unsigned long) wait;
-       cd->timer.expires = jiffies + timeout;
-       add_timer(&cd->timer);
-       debug(("going to sleep\n"));
-       interruptible_sleep_on(wait);
-       del_timer(&cd->timer);
-       if (cd->timed_out) {
-               cd->timed_out = 0;
-               return 1;
-       } else
-               return 0;
-}
-
-static void send_command(int command)
-{
-       debug(("Sending 0x%x\n", command));
-       if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) {
-               cd->command = command;
-               cli();          /* don't interrupt before sleep */
-               outw(dc_mask_sync_error | dc_no_stop_on_error |
-                    (inw(r_data_status) & 0x7f), r_data_control);
-               /* interrupt routine sends command */
-               if (sleep_or_timeout(&cd->uart, UART_TIMEOUT)) {
-                       debug(("Time out on write-buffer\n"));
-                       stats(write_timeout);
-                       outw(command, r_uart_transmit);
-               }
-               debug(("Write commmand delayed\n"));
-       } else
-               outw(command, r_uart_transmit);
-}
-
-static uch receive_byte(int timeout)
-{
-       uch ret;
-       cli();
-       debug(("cli\n"));
-       ret = cd->ur[cd->ur_r];
-       if (cd->ur_r != cd->ur_w) {
-               sti();
-               debug(("returning #%d: 0x%x\n", cd->ur_r,
-                      cd->ur[cd->ur_r]));
-               cd->ur_r++;
-               cd->ur_r %= UR_SIZE;
-               return ret;
-       } else if (sleep_or_timeout(&cd->uart, timeout)) {      /* does sti() */
-               debug(("Time out on receive-buffer\n"));
-#ifdef STATISTICS
-               if (timeout == UART_TIMEOUT)
-                       stats(receive_timeout)  /* no `;'! */
-                           else
-                       stats(dsb_timeout);
-#endif
-               return 0xda;
-       }
-       ret = cd->ur[cd->ur_r];
-       debug(("slept; returning #%d: 0x%x\n", cd->ur_r,
-              cd->ur[cd->ur_r]));
-       cd->ur_r++;
-       cd->ur_r %= UR_SIZE;
-       return ret;
-}
-
-static inline uch receive_echo(void)
-{
-       return receive_byte(UART_TIMEOUT);
-}
-
-static inline uch send_receive(int command)
-{
-       send_command(command);
-       return receive_echo();
-}
-
-static inline uch wait_dsb(void)
-{
-       return receive_byte(DSB_TIMEOUT);
-}
-
-static int type_0_command(int command, int expect_dsb)
-{
-       int e;
-       clear_ur();
-       if (command != (e = send_receive(command))) {
-               debug(("command 0x%x echoed as 0x%x\n", command, e));
-               stats(echo);
-               return -1;
-       }
-       if (expect_dsb) {
-               cd->dsb = wait_dsb();   /* wait for command to finish */
-       }
-       return 0;
-}
-
-static int type_1_command(int command, int bytes, uch * status)
-{                              /* returns info */
-       int i;
-       if (type_0_command(command, 0))
-               return -1;
-       for (i = 0; i < bytes; i++)
-               status[i] = send_receive(c_gimme);
-       return 0;
-}
-
-/* This function resets the adapter card. We'd better not do this too
- * often, because it tends to generate `lost interrupts.' */
-static void reset_cm260(void)
-{
-       outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control);
-       udelay(10);             /* 3.3 mu sec minimum */
-       outw(dc_normal | READ_AHEAD, r_data_control);
-}
-
-/* fsm: frame-sec-min from linear address; one of many */
-static void fsm(int lba, uch * fsm)
-{
-       fsm[0] = lba % 75;
-       lba /= 75;
-       lba += 2;
-       fsm[1] = lba % 60;
-       fsm[2] = lba / 60;
-}
-
-static inline int fsm2lba(uch * fsm)
-{
-       return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]);
-}
-
-static inline int f_s_m2lba(uch f, uch s, uch m)
-{
-       return f + 75 * (s - 2 + 60 * m);
-}
-
-static int start_read(int start)
-{
-       uch read_sector[4] = { c_read_data, };
-       int i, e;
-
-       fsm(start, &read_sector[1]);
-       clear_ur();
-       for (i = 0; i < 4; i++)
-               if (read_sector[i] != (e = send_receive(read_sector[i]))) {
-                       debug(("read_sector: %x echoes %x\n",
-                              read_sector[i], e));
-                       stats(echo);
-                       if (e == 0xff) {        /* this seems to happen often */
-                               e = receive_echo();
-                               debug(("Second try %x\n", e));
-                               if (e != read_sector[i])
-                                       return -1;
-                       }
-               }
-       return 0;
-}
-
-static int stop_read(void)
-{
-       int e;
-       type_0_command(c_stop, 0);
-       if ((e = receive_echo()) != 0xff) {
-               debug(("c_stop didn't send 0xff, but 0x%x\n", e));
-               stats(stop_0xff);
-               return -1;
-       }
-       return 0;
-}
-
-/* This function starts to read sectors in adapter memory, the
-   interrupt routine should stop the read. In fact, the bottom_half
-   routine takes care of this. Set a flag `background' in the cd
-   struct to indicate the process. */
-
-static int read_background(int start, int reading)
-{
-       if (cd->background)
-               return -1;      /* can't do twice */
-       outw(dc_normal | BACK_AHEAD, r_data_control);
-       if (!reading && start_read(start))
-               return -2;
-       cd->adapter_first = cd->adapter_last = start;
-       cd->background = 1;     /* flag a read is going on */
-       return 0;
-}
-
-#ifdef USE_INSW
-#define transport_data insw
-#else
-/* this routine implements insw(,,). There was a time i had the
-   impression that there would be any difference in error-behaviour. */
-void transport_data(int port, ush * dest, int count)
-{
-       int i;
-       ush *d;
-       for (i = 0, d = dest; i < count; i++, d++)
-               *d = inw(port);
-}
-#endif
-
-
-#define MAX_TRIES 100
-static int read_sector(int start)
-{
-       int tries = 0;
-       if (cd->background) {
-               cd->background = 0;
-               cd->adapter_last = -1;  /* invalidate adapter memory */
-               stop_read();
-       }
-       cd->fifo_overflowed = 0;
-       reset_cm260();          /* empty fifo etc. */
-       if (start_read(start))
-               return -1;
-       do {
-               if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) {
-                       debug(("Read timed out sector 0x%x\n", start));
-                       stats(read_timeout);
-                       stop_read();
-                       return -3;
-               }
-               tries++;
-       } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES);
-       if (tries > 1)
-               debug(("Took me some tries\n"))
-                   else
-       if (tries == MAX_TRIES)
-               debug(("MAX_TRIES tries for read sector\n"));
-       transport_data(r_fifo_output_buffer, cd->sector,
-                      READ_AHEAD * RAW_SECTOR_SIZE / 2);
-       if (read_background(start + READ_AHEAD, 1))
-               stats(read_background);
-       cd->sector_first = start;
-       cd->sector_last = start + READ_AHEAD;
-       stats(read_restarted);
-       return 0;
-}
-
-/* The function of bottom-half is to send a stop command to the drive
-   This isn't easy because the routine is not `owned' by any process;
-   we can't go to sleep! The variable cd->background gives the status:
-   0 no read pending
-   1 a read is pending
-   2 c_stop waits for write_buffer_empty
-   3 c_stop waits for receive_buffer_full: echo
-   4 c_stop waits for receive_buffer_full: 0xff
-*/
-
-static void cm206_tasklet_func(unsigned long ignore)
-{
-       debug(("bh: %d\n", cd->background));
-       switch (cd->background) {
-       case 1:
-               stats(bh);
-               if (!(cd->intr_ls & ls_transmitter_buffer_empty)) {
-                       cd->command = c_stop;
-                       outw(dc_mask_sync_error | dc_no_stop_on_error |
-                            (inw(r_data_status) & 0x7f), r_data_control);
-                       cd->background = 2;
-                       break;  /* we'd better not time-out here! */
-               } else
-                       outw(c_stop, r_uart_transmit);
-               /* fall into case 2: */
-       case 2:
-               /* the write has been satisfied by interrupt routine */
-               cd->background = 3;
-               break;
-       case 3:
-               if (cd->ur_r != cd->ur_w) {
-                       if (cd->ur[cd->ur_r] != c_stop) {
-                               debug(("cm206_bh: c_stop echoed 0x%x\n",
-                                      cd->ur[cd->ur_r]));
-                               stats(echo);
-                       }
-                       cd->ur_r++;
-                       cd->ur_r %= UR_SIZE;
-               }
-               cd->background++;
-               break;
-       case 4:
-               if (cd->ur_r != cd->ur_w) {
-                       if (cd->ur[cd->ur_r] != 0xff) {
-                               debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r]));
-                               stats(stop_0xff);
-                       }
-                       cd->ur_r++;
-                       cd->ur_r %= UR_SIZE;
-               }
-               cd->background = 0;
-       }
-}
-
-static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0);
-
-/* This command clears the dsb_possible_media_change flag, so we must 
- * retain it.
- */
-static void get_drive_status(void)
-{
-       uch status[2];
-       type_1_command(c_drive_status, 2, status);      /* this might be done faster */
-       cd->dsb = status[0];
-       cd->cc = status[1];
-       cd->media_changed |=
-           !!(cd->dsb & (dsb_possible_media_change |
-                         dsb_drive_not_ready | dsb_tray_not_closed));
-}
-
-static void get_disc_status(void)
-{
-       if (type_1_command(c_disc_status, 7, cd->disc_status)) {
-               debug(("get_disc_status: error\n"));
-       }
-}
-
-/* The new open. The real opening strategy is defined in cdrom.c. */
-
-static int cm206_open(struct cdrom_device_info *cdi, int purpose)
-{
-       if (!cd->openfiles) {   /* reset only first time */
-               cd->background = 0;
-               reset_cm260();
-               cd->adapter_last = -1;  /* invalidate adapter memory */
-               cd->sector_last = -1;
-       }
-       ++cd->openfiles;
-       stats(open);
-       return 0;
-}
-
-static void cm206_release(struct cdrom_device_info *cdi)
-{
-       if (cd->openfiles == 1) {
-               if (cd->background) {
-                       cd->background = 0;
-                       stop_read();
-               }
-               cd->sector_last = -1;   /* Make our internal buffer invalid */
-               FIRST_TRACK = 0;        /* No valid disc status */
-       }
-       --cd->openfiles;
-}
-
-/* Empty buffer empties $sectors$ sectors of the adapter card buffer,
- * and then reads a sector in kernel memory.  */
-static void empty_buffer(int sectors)
-{
-       while (sectors >= 0) {
-               transport_data(r_fifo_output_buffer,
-                              cd->sector + cd->fifo_overflowed,
-                              RAW_SECTOR_SIZE / 2 - cd->fifo_overflowed);
-               --sectors;
-               ++cd->adapter_first;    /* update the current adapter sector */
-               cd->fifo_overflowed = 0;        /* reset overflow bit */
-               stats(sector_transferred);
-       }
-       cd->sector_first = cd->adapter_first - 1;
-       cd->sector_last = cd->adapter_first;    /* update the buffer sector */
-}
-
-/* try_adapter. This function determines if the requested sector is
-   in adapter memory, or will appear there soon. Returns 0 upon
-   success */
-static int try_adapter(int sector)
-{
-       if (cd->adapter_first <= sector && sector < cd->adapter_last) {
-               /* sector is in adapter memory */
-               empty_buffer(sector - cd->adapter_first);
-               return 0;
-       } else if (cd->background == 1 && cd->adapter_first <= sector
-                  && sector < cd->adapter_first + cd->max_sectors) {
-               /* a read is going on, we can wait for it */
-               cd->wait_back = 1;
-               while (sector >= cd->adapter_last) {
-                       if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) {
-                               debug(("Timed out during background wait: %d %d %d %d\n", sector, cd->adapter_last, cd->adapter_first, cd->background));
-                               stats(back_read_timeout);
-                               cd->wait_back = 0;
-                               return -1;
-                       }
-               }
-               cd->wait_back = 0;
-               empty_buffer(sector - cd->adapter_first);
-               return 0;
-       } else
-               return -2;
-}
-
-/* This is not a very smart implementation. We could optimize for 
-   consecutive block numbers. I'm not convinced this would really
-   bring down the processor load. */
-static void do_cm206_request(request_queue_t * q)
-{
-       long int i, cd_sec_no;
-       int quarter, error;
-       uch *source, *dest;
-       struct request *req;
-
-       while (1) {     /* repeat until all requests have been satisfied */
-               req = elv_next_request(q);
-               if (!req)
-                       return;
-
-               if (req->cmd != READ) {
-                       debug(("Non-read command %d on cdrom\n", req->cmd));
-                       end_request(req, 0);
-                       continue;
-               }
-               spin_unlock_irq(q->queue_lock);
-               error = 0;
-               for (i = 0; i < req->nr_sectors; i++) {
-                       int e1, e2;
-                       cd_sec_no = (req->sector + i) / BLOCKS_ISO;     /* 4 times 512 bytes */
-                       quarter = (req->sector + i) % BLOCKS_ISO;
-                       dest = req->buffer + i * LINUX_BLOCK_SIZE;
-                       /* is already in buffer memory? */
-                       if (cd->sector_first <= cd_sec_no
-                           && cd_sec_no < cd->sector_last) {
-                               source =
-                                   ((uch *) cd->sector) + 16 +
-                                   quarter * LINUX_BLOCK_SIZE +
-                                   (cd_sec_no -
-                                    cd->sector_first) * RAW_SECTOR_SIZE;
-                               memcpy(dest, source, LINUX_BLOCK_SIZE);
-                       } else if (!(e1 = try_adapter(cd_sec_no)) ||
-                                  !(e2 = read_sector(cd_sec_no))) {
-                               source =
-                                   ((uch *) cd->sector) + 16 +
-                                   quarter * LINUX_BLOCK_SIZE;
-                               memcpy(dest, source, LINUX_BLOCK_SIZE);
-                       } else {
-                               error = 1;
-                               debug(("cm206_request: %d %d\n", e1, e2));
-                       }
-               }
-               spin_lock_irq(q->queue_lock);
-               end_request(req, !error);
-       }
-}
-
-/* Audio support. I've tried very hard, but the cm206 drive doesn't 
-   seem to have a get_toc (table-of-contents) function, while i'm
-   pretty sure it must read the toc upon disc insertion. Therefore
-   this function has been implemented through a binary search 
-   strategy. All track starts that happen to be found are stored in
-   cd->toc[], for future use. 
-
-   I've spent a whole day on a bug that only shows under Workman---
-   I don't get it. Tried everything, nothing works. If workman asks
-   for track# 0xaa, it'll get the wrong time back. Any other program
-   receives the correct value. I'm stymied.
-*/
-
-/* seek seeks to address lba. It does wait to arrive there. */
-static void seek(int lba)
-{
-       int i;
-       uch seek_command[4] = { c_seek, };
-
-       fsm(lba, &seek_command[1]);
-       for (i = 0; i < 4; i++)
-               type_0_command(seek_command[i], 0);
-       cd->dsb = wait_dsb();
-}
-
-static uch bcdbin(unsigned char bcd)
-{                              /* stolen from mcd.c! */
-       return (bcd >> 4) * 10 + (bcd & 0xf);
-}
-
-static inline uch normalize_track(uch track)
-{
-       if (track < 1)
-               return 1;
-       if (track > LAST_TRACK)
-               return LAST_TRACK + 1;
-       return track;
-}
-
-/* This function does a binary search for track start. It records all
- * tracks seen in the process. Input $track$ must be between 1 and
- * #-of-tracks+1.  Note that the start of the disc must be in toc[1].fsm. 
- */
-static int get_toc_lba(uch track)
-{
-       int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm);
-       int i, lba, l, old_lba = 0;
-       uch *q = cd->q;
-       uch ct;                 /* current track */
-       int binary = 0;
-       const int skip = 3 * 60 * 75;   /* 3 minutes */
-
-       for (i = track; i > 0; i--)
-               if (cd->toc[i].track) {
-                       min = fsm2lba(cd->toc[i].fsm);
-                       break;
-               }
-       lba = min + skip;
-       do {
-               seek(lba);
-               type_1_command(c_read_current_q, 10, q);
-               ct = normalize_track(q[1]);
-               if (!cd->toc[ct].track) {
-                       l = q[9] - bcdbin(q[5]) + 75 * (q[8] -
-                                                       bcdbin(q[4]) - 2 +
-                                                       60 * (q[7] -
-                                                             bcdbin(q
-                                                                    [3])));
-                       cd->toc[ct].track = q[1];       /* lead out still 0xaa */
-                       fsm(l, cd->toc[ct].fsm);
-                       cd->toc[ct].q0 = q[0];  /* contains adr and ctrl info */
-                       if (ct == track)
-                               return l;
-               }
-               old_lba = lba;
-               if (binary) {
-                       if (ct < track)
-                               min = lba;
-                       else
-                               max = lba;
-                       lba = (min + max) / 2;
-               } else {
-                       if (ct < track)
-                               lba += skip;
-                       else {
-                               binary = 1;
-                               max = lba;
-                               min = lba - skip;
-                               lba = (min + max) / 2;
-                       }
-               }
-       } while (lba != old_lba);
-       return lba;
-}
-
-static void update_toc_entry(uch track)
-{
-       track = normalize_track(track);
-       if (!cd->toc[track].track)
-               get_toc_lba(track);
-}
-
-/* return 0 upon success */
-static int read_toc_header(struct cdrom_tochdr *hp)
-{
-       if (!FIRST_TRACK)
-               get_disc_status();
-       if (hp) {
-               int i;
-               hp->cdth_trk0 = FIRST_TRACK;
-               hp->cdth_trk1 = LAST_TRACK;
-               /* fill in first track position */
-               for (i = 0; i < 3; i++)
-                       cd->toc[1].fsm[i] = cd->disc_status[3 + i];
-               update_toc_entry(LAST_TRACK + 1);       /* find most entries */
-               return 0;
-       }
-       return -1;
-}
-
-static void play_from_to_msf(struct cdrom_msf *msfp)
-{
-       uch play_command[] = { c_play,
-               msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0,
-               msfp->cdmsf_frame1, msfp->cdmsf_sec1, msfp->cdmsf_min1, 2,
-                   2
-       };
-       int i;
-       for (i = 0; i < 9; i++)
-               type_0_command(play_command[i], 0);
-       for (i = 0; i < 3; i++)
-               PLAY_TO.fsm[i] = play_command[i + 4];
-       PLAY_TO.track = 0;      /* say no track end */
-       cd->dsb = wait_dsb();
-}
-
-static void play_from_to_track(int from, int to)
-{
-       uch play_command[8] = { c_play, };
-       int i;
-
-       if (from == 0) {        /* continue paused play */
-               for (i = 0; i < 3; i++) {
-                       play_command[i + 1] = cd->audio_status[i + 2];
-                       play_command[i + 4] = PLAY_TO.fsm[i];
-               }
-       } else {
-               update_toc_entry(from);
-               update_toc_entry(to + 1);
-               for (i = 0; i < 3; i++) {
-                       play_command[i + 1] = cd->toc[from].fsm[i];
-                       PLAY_TO.fsm[i] = play_command[i + 4] =
-                           cd->toc[to + 1].fsm[i];
-               }
-               PLAY_TO.track = to;
-       }
-       for (i = 0; i < 7; i++)
-               type_0_command(play_command[i], 0);
-       for (i = 0; i < 2; i++)
-               type_0_command(0x2, 0); /* volume */
-       cd->dsb = wait_dsb();
-}
-
-static int get_current_q(struct cdrom_subchnl *qp)
-{
-       int i;
-       uch *q = cd->q;
-       if (type_1_command(c_read_current_q, 10, q))
-               return 0;
-/*  q[0] = bcdbin(q[0]); Don't think so! */
-       for (i = 2; i < 6; i++)
-               q[i] = bcdbin(q[i]);
-       qp->cdsc_adr = q[0] & 0xf;
-       qp->cdsc_ctrl = q[0] >> 4;      /* from mcd.c */
-       qp->cdsc_trk = q[1];
-       qp->cdsc_ind = q[2];
-       if (qp->cdsc_format == CDROM_MSF) {
-               qp->cdsc_reladdr.msf.minute = q[3];
-               qp->cdsc_reladdr.msf.second = q[4];
-               qp->cdsc_reladdr.msf.frame = q[5];
-               qp->cdsc_absaddr.msf.minute = q[7];
-               qp->cdsc_absaddr.msf.second = q[8];
-               qp->cdsc_absaddr.msf.frame = q[9];
-       } else {
-               qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]);
-               qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]);
-       }
-       get_drive_status();
-       if (cd->dsb & dsb_play_in_progress)
-               qp->cdsc_audiostatus = CDROM_AUDIO_PLAY;
-       else if (PAUSED)
-               qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED;
-       else
-               qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS;
-       return 0;
-}
-
-static void invalidate_toc(void)
-{
-       memset(cd->toc, 0, sizeof(cd->toc));
-       memset(cd->disc_status, 0, sizeof(cd->disc_status));
-}
-
-/* cdrom.c guarantees that cdte_format == CDROM_MSF */
-static void get_toc_entry(struct cdrom_tocentry *ep)
-{
-       uch track = normalize_track(ep->cdte_track);
-       update_toc_entry(track);
-       ep->cdte_addr.msf.frame = cd->toc[track].fsm[0];
-       ep->cdte_addr.msf.second = cd->toc[track].fsm[1];
-       ep->cdte_addr.msf.minute = cd->toc[track].fsm[2];
-       ep->cdte_adr = cd->toc[track].q0 & 0xf;
-       ep->cdte_ctrl = cd->toc[track].q0 >> 4;
-       ep->cdte_datamode = 0;
-}
-
-/* Audio ioctl.  Ioctl commands connected to audio are in such an
- * idiosyncratic i/o format, that we leave these untouched. Return 0
- * upon success. Memory checking has been done by cdrom_ioctl(), the
- * calling function, as well as LBA/MSF sanitization.
-*/
-static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-                            void *arg)
-{
-       switch (cmd) {
-       case CDROMREADTOCHDR:
-               return read_toc_header((struct cdrom_tochdr *) arg);
-       case CDROMREADTOCENTRY:
-               get_toc_entry((struct cdrom_tocentry *) arg);
-               return 0;
-       case CDROMPLAYMSF:
-               play_from_to_msf((struct cdrom_msf *) arg);
-               return 0;
-       case CDROMPLAYTRKIND:   /* admittedly, not particularly beautiful */
-               play_from_to_track(((struct cdrom_ti *) arg)->cdti_trk0,
-                                  ((struct cdrom_ti *) arg)->cdti_trk1);
-               return 0;
-       case CDROMSTOP:
-               PAUSED = 0;
-               if (cd->dsb & dsb_play_in_progress)
-                       return type_0_command(c_stop, 1);
-               else
-                       return 0;
-       case CDROMPAUSE:
-               get_drive_status();
-               if (cd->dsb & dsb_play_in_progress) {
-                       type_0_command(c_stop, 1);
-                       type_1_command(c_audio_status, 5,
-                                      cd->audio_status);
-                       PAUSED = 1;     /* say we're paused */
-               }
-               return 0;
-       case CDROMRESUME:
-               if (PAUSED)
-                       play_from_to_track(0, 0);
-               PAUSED = 0;
-               return 0;
-       case CDROMSTART:
-       case CDROMVOLCTRL:
-               return 0;
-       case CDROMSUBCHNL:
-               return get_current_q((struct cdrom_subchnl *) arg);
-       default:
-               return -EINVAL;
-       }
-}
-
-static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-{
-       if (cd != NULL) {
-               int r;
-               get_drive_status();     /* ensure cd->media_changed OK */
-               r = cd->media_changed;
-               cd->media_changed = 0;  /* clear bit */
-               return r;
-       } else
-               return -EIO;
-}
-
-/* The new generic cdrom support. Routines should be concise, most of
-   the logic should be in cdrom.c */
-
-
-/* controls tray movement */
-static int cm206_tray_move(struct cdrom_device_info *cdi, int position)
-{
-       if (position) {         /* 1: eject */
-               type_0_command(c_open_tray, 1);
-               invalidate_toc();
-       } else
-               type_0_command(c_close_tray, 1);        /* 0: close */
-       return 0;
-}
-
-/* gives current state of the drive */
-static int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
-       get_drive_status();
-       if (cd->dsb & dsb_tray_not_closed)
-               return CDS_TRAY_OPEN;
-       if (!(cd->dsb & dsb_disc_present))
-               return CDS_NO_DISC;
-       if (cd->dsb & dsb_drive_not_ready)
-               return CDS_DRIVE_NOT_READY;
-       return CDS_DISC_OK;
-}
-
-/* locks or unlocks door lock==1: lock; return 0 upon success */
-static int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
-{
-       uch command = (lock) ? c_lock_tray : c_unlock_tray;
-       type_0_command(command, 1);     /* wait and get dsb */
-       /* the logic calculates the success, 0 means successful */
-       return lock ^ ((cd->dsb & dsb_tray_locked) != 0);
-}
-
-/* Although a session start should be in LBA format, we return it in 
-   MSF format because it is slightly easier, and the new generic ioctl
-   will take care of the necessary conversion. */
-static int cm206_get_last_session(struct cdrom_device_info *cdi,
-                                 struct cdrom_multisession *mssp)
-{
-       if (!FIRST_TRACK)
-               get_disc_status();
-       if (mssp != NULL) {
-               if (DISC_STATUS & cds_multi_session) {  /* multi-session */
-                       mssp->addr.msf.frame = cd->disc_status[3];
-                       mssp->addr.msf.second = cd->disc_status[4];
-                       mssp->addr.msf.minute = cd->disc_status[5];
-                       mssp->addr_format = CDROM_MSF;
-                       mssp->xa_flag = 1;
-               } else {
-                       mssp->xa_flag = 0;
-               }
-               return 1;
-       }
-       return 0;
-}
-
-static int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
-{
-       uch upc[10];
-       char *ret = mcn->medium_catalog_number;
-       int i;
-
-       if (type_1_command(c_read_upc, 10, upc))
-               return -EIO;
-       for (i = 0; i < 13; i++) {
-               int w = i / 2 + 1, r = i % 2;
-               if (r)
-                       ret[i] = 0x30 | (upc[w] & 0x0f);
-               else
-                       ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f);
-       }
-       ret[13] = '\0';
-       return 0;
-}
-
-static int cm206_reset(struct cdrom_device_info *cdi)
-{
-       stop_read();
-       reset_cm260();
-       outw(dc_normal | dc_break | READ_AHEAD, r_data_control);
-       mdelay(1);              /* 750 musec minimum */
-       outw(dc_normal | READ_AHEAD, r_data_control);
-       cd->sector_last = -1;   /* flag no data buffered */
-       cd->adapter_last = -1;
-       invalidate_toc();
-       return 0;
-}
-
-static int cm206_select_speed(struct cdrom_device_info *cdi, int speed)
-{
-       int r;
-       switch (speed) {
-       case 0:
-               r = type_0_command(c_auto_mode, 1);
-               break;
-       case 1:
-               r = type_0_command(c_force_1x, 1);
-               break;
-       case 2:
-               r = type_0_command(c_force_2x, 1);
-               break;
-       default:
-               return -1;
-       }
-       if (r < 0)
-               return r;
-       else
-               return 1;
-}
-
-static struct cdrom_device_ops cm206_dops = {
-       .open                   = cm206_open,
-       .release                = cm206_release,
-       .drive_status           = cm206_drive_status,
-       .media_changed          = cm206_media_changed,
-       .tray_move              = cm206_tray_move,
-       .lock_door              = cm206_lock_door,
-       .select_speed           = cm206_select_speed,
-       .get_last_session       = cm206_get_last_session,
-       .get_mcn                = cm206_get_upc,
-       .reset                  = cm206_reset,
-       .audio_ioctl            = cm206_audio_ioctl,
-       .capability             = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
-                                 CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
-                                 CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED |
-                                 CDC_DRIVE_STATUS,
-       .n_minors               = 1,
-};
-
-
-static struct cdrom_device_info cm206_info = {
-       .ops            = &cm206_dops,
-       .speed          = 2,
-       .capacity       = 1,
-       .name           = "cm206",
-};
-
-static int cm206_block_open(struct inode *inode, struct file *file)
-{
-       return cdrom_open(&cm206_info, inode, file);
-}
-
-static int cm206_block_release(struct inode *inode, struct file *file)
-{
-       return cdrom_release(&cm206_info, file);
-}
-
-static int cm206_block_ioctl(struct inode *inode, struct file *file,
-                               unsigned cmd, unsigned long arg)
-{
-       switch (cmd) {
-#ifdef STATISTICS
-       case CM206CTL_GET_STAT:
-               if (arg >= NR_STATS)
-                       return -EINVAL;
-               return cd->stats[arg];
-       case CM206CTL_GET_LAST_STAT:
-               if (arg >= NR_STATS)
-                       return -EINVAL;
-               return cd->last_stat[arg];
-#endif
-       default:
-               break;
-       }
-
-       return cdrom_ioctl(file, &cm206_info, inode, cmd, arg);
-}
-
-static int cm206_block_media_changed(struct gendisk *disk)
-{
-       return cdrom_media_changed(&cm206_info);
-}
-
-static struct block_device_operations cm206_bdops =
-{
-       .owner          = THIS_MODULE,
-       .open           = cm206_block_open,
-       .release        = cm206_block_release,
-       .ioctl          = cm206_block_ioctl,
-       .media_changed  = cm206_block_media_changed,
-};
-
-static struct gendisk *cm206_gendisk;
-
-/* This function probes for the adapter card. It returns the base
-   address if it has found the adapter card. One can specify a base 
-   port to probe specifically, or 0 which means span all possible
-   bases. 
-
-   Linus says it is too dangerous to use writes for probing, so we
-   stick with pure reads for a while. Hope that 8 possible ranges,
-   request_region, 15 bits of one port and 6 of another make things
-   likely enough to accept the region on the first hit...
- */
-static int __init probe_base_port(int base)
-{
-       int b = 0x300, e = 0x370;       /* this is the range of start addresses */
-       volatile int fool, i;
-
-       if (base)
-               b = e = base;
-       for (base = b; base <= e; base += 0x10) {
-               if (!request_region(base, 0x10,"cm206"))
-                       continue;
-               for (i = 0; i < 3; i++)
-                       fool = inw(base + 2);   /* empty possibly uart_receive_buffer */
-               if ((inw(base + 6) & 0xffef) != 0x0001 ||       /* line_status */
-                   (inw(base) & 0xad00) != 0)  { /* data status */
-                       release_region(base,0x10);
-                       continue;
-               }
-               return (base);
-       }
-       return 0;
-}
-
-#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
-/* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-static int __init probe_irq(int nr)
-{
-       int irqs, irq;
-       outw(dc_normal | READ_AHEAD, r_data_control);   /* disable irq-generation */
-       sti();
-       irqs = probe_irq_on();
-       reset_cm260();          /* causes interrupt */
-       udelay(100);            /* wait for it */
-       irq = probe_irq_off(irqs);
-       outw(dc_normal | READ_AHEAD, r_data_control);   /* services interrupt */
-       if (nr && irq != nr && irq > 0)
-               return 0;       /* wrong interrupt happened */
-       else
-               return irq;
-}
-#endif
-
-int __init cm206_init(void)
-{
-       uch e = 0;
-       long int size = sizeof(struct cm206_struct);
-       struct gendisk *disk;
-
-       printk(KERN_INFO "cm206 cdrom driver " REVISION);
-       cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
-       if (!cm206_base) {
-               printk(" can't find adapter!\n");
-               return -EIO;
-       }
-       printk(" adapter at 0x%x", cm206_base);
-       cd = kmalloc(size, GFP_KERNEL);
-       if (!cd)
-               goto out_base;
-       /* Now we have found the adaptor card, try to reset it. As we have
-        * found out earlier, this process generates an interrupt as well,
-        * so we might just exploit that fact for irq probing! */
-#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
-       cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq);
-       if (cm206_irq <= 0) {
-               printk("can't find IRQ!\n");
-               goto out_probe;
-       } else
-               printk(" IRQ %d found\n", cm206_irq);
-#else
-       cli();
-       reset_cm260();
-       /* Now, the problem here is that reset_cm260 can generate an
-          interrupt. It seems that this can cause a kernel oops some time
-          later. So we wait a while and `service' this interrupt. */
-       mdelay(1);
-       outw(dc_normal | READ_AHEAD, r_data_control);
-       sti();
-       printk(" using IRQ %d\n", cm206_irq);
-#endif
-       if (send_receive_polled(c_drive_configuration) !=
-           c_drive_configuration) {
-               printk(KERN_INFO " drive not there\n");
-               goto out_probe;
-       }
-       e = send_receive_polled(c_gimme);
-       printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code);
-       if (e & dcf_transfer_rate)
-               printk(" double");
-       else
-               printk(" single");
-       printk(" speed drive");
-       if (e & dcf_motorized_tray)
-               printk(", motorized tray");
-       if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206", NULL)) {
-               printk("\nUnable to reserve IRQ---aborted\n");
-               goto out_probe;
-       }
-       printk(".\n");
-
-       if (register_blkdev(MAJOR_NR, "cm206"))
-               goto out_blkdev;
-
-       disk = alloc_disk(1);
-       if (!disk)
-               goto out_disk;
-       disk->major = MAJOR_NR;
-       disk->first_minor = 0;
-       sprintf(disk->disk_name, "cm206cd");
-       disk->fops = &cm206_bdops;
-       disk->flags = GENHD_FL_CD;
-       cm206_gendisk = disk;
-       if (register_cdrom(&cm206_info) != 0) {
-               printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR);
-               goto out_cdrom;
-       }
-       cm206_queue = blk_init_queue(do_cm206_request, &cm206_lock);
-       if (!cm206_queue)
-               goto out_queue;
-               
-       blk_queue_hardsect_size(cm206_queue, 2048);
-       disk->queue = cm206_queue;
-       add_disk(disk);
-
-       memset(cd, 0, sizeof(*cd));     /* give'm some reasonable value */
-       cd->sector_last = -1;   /* flag no data buffered */
-       cd->adapter_last = -1;
-       init_timer(&cd->timer);
-       cd->timer.function = cm206_timeout;
-       cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97;
-       printk(KERN_INFO "%d kB adapter memory available, "
-              " %ld bytes kernel memory used.\n", cd->max_sectors * 2,
-              size);
-       return 0;
-
-out_queue:
-       unregister_cdrom(&cm206_info);
-out_cdrom:
-       put_disk(disk);
-out_disk:
-       unregister_blkdev(MAJOR_NR, "cm206");
-out_blkdev:
-       free_irq(cm206_irq, NULL);
-out_probe:
-       kfree(cd);
-out_base:
-       release_region(cm206_base, 16);
-       return -EIO;
-}
-
-#ifdef MODULE
-
-
-static void __init parse_options(void)
-{
-       int i;
-       for (i = 0; i < 2; i++) {
-               if (0x300 <= cm206[i] && i <= 0x370
-                   && cm206[i] % 0x10 == 0) {
-                       cm206_base = cm206[i];
-                       auto_probe = 0;
-               } else if (3 <= cm206[i] && cm206[i] <= 15) {
-                       cm206_irq = cm206[i];
-                       auto_probe = 0;
-               }
-       }
-}
-
-static int __init __cm206_init(void)
-{
-       parse_options();
-#if !defined(AUTO_PROBE_MODULE)
-       auto_probe = 0;
-#endif
-       return cm206_init();
-}
-
-static void __exit cm206_exit(void)
-{
-       del_gendisk(cm206_gendisk);
-       put_disk(cm206_gendisk);
-       if (unregister_cdrom(&cm206_info)) {
-               printk("Can't unregister cdrom cm206\n");
-               return;
-       }
-       if (unregister_blkdev(MAJOR_NR, "cm206")) {
-               printk("Can't unregister major cm206\n");
-               return;
-       }
-       blk_cleanup_queue(cm206_queue);
-       free_irq(cm206_irq, NULL);
-       kfree(cd);
-       release_region(cm206_base, 16);
-       printk(KERN_INFO "cm206 removed\n");
-}
-
-module_init(__cm206_init);
-module_exit(cm206_exit);
-
-#else                          /* !MODULE */
-
-/* This setup function accepts either `auto' or numbers in the range
- * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */
-
-static int __init cm206_setup(char *s)
-{
-       int i, p[4];
-
-       (void) get_options(s, ARRAY_SIZE(p), p);
-
-       if (!strcmp(s, "auto"))
-               auto_probe = 1;
-       for (i = 1; i <= p[0]; i++) {
-               if (0x300 <= p[i] && i <= 0x370 && p[i] % 0x10 == 0) {
-                       cm206_base = p[i];
-                       auto_probe = 0;
-               } else if (3 <= p[i] && p[i] <= 15) {
-                       cm206_irq = p[i];
-                       auto_probe = 0;
-               }
-       }
-       return 1;
-}
-
-__setup("cm206=", cm206_setup);
-
-#endif                         /* !MODULE */
-MODULE_ALIAS_BLOCKDEV_MAJOR(CM206_CDROM_MAJOR);
-
diff --git a/drivers/cdrom/cm206.h b/drivers/cdrom/cm206.h
deleted file mode 100644 (file)
index 0ae51c1..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/* cm206.h Header file for cm206.c.
-   Copyright (c) 1995 David van Leeuwen 
-*/
-
-#ifndef LINUX_CM206_H
-#define LINUX_CM206_H
-
-#include <linux/ioctl.h>
-
-/* First, the cm260 stuff */
-/* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined
-   below, the values are not used unless autoprobing is turned off and 
-   no LILO boot options or module command line options are given. Change
-   these values to your own as last resort if autoprobing and options
-   don't work. */
-
-#define CM206_BASE 0x340
-#define CM206_IRQ 11
-
-#define r_data_status (cm206_base)
-#define r_uart_receive (cm206_base+0x2)
-#define r_fifo_output_buffer (cm206_base+0x4)
-#define r_line_status (cm206_base+0x6)
-#define r_data_control (cm206_base+0x8)
-#define r_uart_transmit (cm206_base+0xa)
-#define r_test_clock (cm206_base+0xc)
-#define r_test_control (cm206_base+0xe)
-
-/* the data_status flags */
-#define ds_ram_size 0x4000
-#define ds_toc_ready 0x2000
-#define ds_fifo_empty 0x1000
-#define ds_sync_error 0x800
-#define ds_crc_error 0x400
-#define ds_data_error 0x200
-#define ds_fifo_overflow 0x100
-#define ds_data_ready 0x80
-
-/* the line_status flags */
-#define ls_attention 0x10
-#define ls_parity_error 0x8
-#define ls_overrun 0x4
-#define ls_receive_buffer_full 0x2
-#define ls_transmitter_buffer_empty 0x1
-
-/* the data control register flags */
-#define dc_read_q_channel 0x4000
-#define dc_mask_sync_error 0x2000
-#define dc_toc_enable 0x1000
-#define dc_no_stop_on_error 0x800
-#define dc_break 0x400
-#define dc_initialize 0x200
-#define dc_mask_transmit_ready 0x100
-#define dc_flag_enable 0x80
-
-/* Define the default data control register flags here */
-#define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \
-                  dc_mask_transmit_ready)
-
-/* now some constants related to the cm206 */
-/* another drive status byte, echoed by the cm206 on most commands */
-
-#define dsb_error_condition 0x1
-#define dsb_play_in_progress 0x4
-#define dsb_possible_media_change 0x8
-#define dsb_disc_present 0x10
-#define dsb_drive_not_ready 0x20
-#define dsb_tray_locked 0x40
-#define dsb_tray_not_closed 0x80
-
-#define dsb_not_useful (dsb_drive_not_ready | dsb_tray_not_closed)
-
-/* the cm206 command set */
-
-#define c_close_tray 0
-#define c_lock_tray 0x01
-#define c_unlock_tray 0x04
-#define c_open_tray 0x05
-#define c_seek 0x10
-#define c_read_data 0x20
-#define c_force_1x 0x21
-#define c_force_2x 0x22
-#define c_auto_mode 0x23
-#define c_play 0x30
-#define c_set_audio_mode 0x31
-#define c_read_current_q 0x41
-#define c_stream_q 0x42
-#define c_drive_status 0x50
-#define c_disc_status 0x51
-#define c_audio_status 0x52
-#define c_drive_configuration 0x53
-#define c_read_upc 0x60
-#define c_stop 0x70
-#define c_calc_checksum 0xe5
-
-#define c_gimme 0xf8
-
-/* finally, the (error) condition that the drive can be in      *
- * OK, this is not always an error, but let's prefix it with e_ */
-
-#define e_none 0
-#define e_illegal_command 0x01
-#define e_sync 0x02
-#define e_seek 0x03
-#define e_parity 0x04
-#define e_focus 0x05
-#define e_header_sync 0x06
-#define e_code_incompatibility 0x07
-#define e_reset_done 0x08
-#define e_bad_parameter 0x09
-#define e_radial 0x0a
-#define e_sub_code 0x0b
-#define e_no_data_track 0x0c
-#define e_scan 0x0d
-#define e_tray_open 0x0f
-#define e_no_disc 0x10
-#define e_tray stalled 0x11
-
-/* drive configuration masks */
-
-#define dcf_revision_code 0x7
-#define dcf_transfer_rate 0x60
-#define dcf_motorized_tray 0x80
-
-/* disc status byte */
-
-#define cds_multi_session 0x2
-#define cds_all_audio 0x8
-#define cds_xa_mode 0xf0
-
-/* finally some ioctls for the driver */
-
-#define CM206CTL_GET_STAT _IO( 0x20, 0 )
-#define CM206CTL_GET_LAST_STAT _IO( 0x20, 1 )
-
-#ifdef STATISTICS
-
-/* This is an ugly way to guarantee that the names of the statistics
- * are the same in the code and in the diagnostics program.  */
-
-#ifdef __KERNEL__
-#define x(a) st_ ## a
-#define y enum
-#else
-#define x(a) #a
-#define y char * stats_name[] = 
-#endif
-
-y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error),
-     x(crc_error), x(sync_error), x(lost_intr), x(echo),
-     x(write_timeout), x(receive_timeout), x(read_timeout),
-     x(dsb_timeout), x(stop_0xff), x(back_read_timeout),
-     x(sector_transferred), x(read_restarted), x(read_background),
-     x(bh), x(open), x(ioctl_multisession), x(attention)
-#ifdef __KERNEL__
-     , x(last_entry)
-#endif
- };
-
-#ifdef __KERNEL__
-#define NR_STATS st_last_entry
-#else
-#define NR_STATS (sizeof(stats_name)/sizeof(char*))
-#endif
-
-#undef y
-#undef x
-
-#endif /* STATISTICS */
-
-#endif /* LINUX_CM206_H */
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
deleted file mode 100644 (file)
index b3ab6e9..0000000
+++ /dev/null
@@ -1,1029 +0,0 @@
-#define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"
-
-/*
-       linux/drivers/block/gscd.c - GoldStar R420 CDROM driver
-
-        Copyright (C) 1995  Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>
-        based upon pre-works by   Eberhard Moenkeberg <emoenke@gwdg.de>
-        
-
-        For all kind of other information about the GoldStar CDROM
-        and this Linux device driver I installed a WWW-URL:
-        http://linux.rz.fh-hannover.de/~raupach        
-
-
-             If you are the editor of a Linux CD, you should
-             enable gscd.c within your boot floppy kernel and
-             send me one of your CDs for free.
-
-
-        --------------------------------------------------------------------
-       This program is free software; you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation; either version 2, or (at your option)
-       any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU General Public License for more details.
-
-       You should have received a copy of the GNU General Public License
-       along with this program; if not, write to the Free Software
-       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-       
-       --------------------------------------------------------------------
-       
-       9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
-                          Removed init_module & cleanup_module in favor of 
-                          module_init & module_exit.
-                          Torben Mathiasen <tmm@image.dk>
-
-*/
-
-/* These settings are for various debug-level. Leave they untouched ... */
-#define  NO_GSCD_DEBUG
-#define  NO_IOCTL_DEBUG
-#define  NO_MODULE_DEBUG
-#define  NO_FUTURE_WORK
-/*------------------------*/
-
-#include <linux/module.h>
-
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR GOLDSTAR_CDROM_MAJOR
-#include <linux/blkdev.h>
-#include "gscd.h"
-
-static int gscdPresent = 0;
-
-static unsigned char gscd_buf[2048];   /* buffer for block size conversion */
-static int gscd_bn = -1;
-static short gscd_port = GSCD_BASE_ADDR;
-module_param_named(gscd, gscd_port, short, 0);
-
-/* Kommt spaeter vielleicht noch mal dran ...
- *    static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
- */
-
-static void gscd_read_cmd(struct request *req);
-static void gscd_hsg2msf(long hsg, struct msf *msf);
-static void gscd_bin2bcd(unsigned char *p);
-
-/* Schnittstellen zum Kern/FS */
-
-static void __do_gscd_request(unsigned long dummy);
-static int gscd_ioctl(struct inode *, struct file *, unsigned int,
-                     unsigned long);
-static int gscd_open(struct inode *, struct file *);
-static int gscd_release(struct inode *, struct file *);
-static int check_gscd_med_chg(struct gendisk *disk);
-
-/*      GoldStar Funktionen    */
-
-static void cmd_out(int, char *, char *, int);
-static void cmd_status(void);
-static void init_cd_drive(int);
-
-static int get_status(void);
-static void clear_Audio(void);
-static void cc_invalidate(void);
-
-/* some things for the next version */
-#ifdef FUTURE_WORK
-static void update_state(void);
-static long gscd_msf2hsg(struct msf *mp);
-static int gscd_bcd2bin(unsigned char bcd);
-#endif
-
-
-/*      lo-level cmd-Funktionen    */
-
-static void cmd_info_in(char *, int);
-static void cmd_end(void);
-static void cmd_read_b(char *, int, int);
-static void cmd_read_w(char *, int, int);
-static int cmd_unit_alive(void);
-static void cmd_write_cmd(char *);
-
-
-/*      GoldStar Variablen     */
-
-static int curr_drv_state;
-static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static int drv_mode;
-static int disk_state;
-static int speed;
-static int ndrives;
-
-static unsigned char drv_num_read;
-static unsigned char f_dsk_valid;
-static unsigned char current_drive;
-static unsigned char f_drv_ok;
-
-
-static char f_AudioPlay;
-static char f_AudioPause;
-static int AudioStart_m;
-static int AudioStart_f;
-static int AudioEnd_m;
-static int AudioEnd_f;
-
-static DEFINE_TIMER(gscd_timer, NULL, 0, 0);
-static DEFINE_SPINLOCK(gscd_lock);
-static struct request_queue *gscd_queue;
-
-static struct block_device_operations gscd_fops = {
-       .owner          = THIS_MODULE,
-       .open           = gscd_open,
-       .release        = gscd_release,
-       .ioctl          = gscd_ioctl,
-       .media_changed  = check_gscd_med_chg,
-};
-
-/* 
- * Checking if the media has been changed
- * (not yet implemented)
- */
-static int check_gscd_med_chg(struct gendisk *disk)
-{
-#ifdef GSCD_DEBUG
-       printk("gscd: check_med_change\n");
-#endif
-       return 0;
-}
-
-
-#ifndef MODULE
-/* Using new interface for kernel-parameters */
-
-static int __init gscd_setup(char *str)
-{
-       int ints[2];
-       (void) get_options(str, ARRAY_SIZE(ints), ints);
-
-       if (ints[0] > 0) {
-               gscd_port = ints[1];
-       }
-       return 1;
-}
-
-__setup("gscd=", gscd_setup);
-
-#endif
-
-static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
-                     unsigned long arg)
-{
-       unsigned char to_do[10];
-       unsigned char dummy;
-
-
-       switch (cmd) {
-       case CDROMSTART:        /* Spin up the drive */
-               /* Don't think we can do this.  Even if we could,
-                * I think the drive times out and stops after a while
-                * anyway.  For now, ignore it.
-                */
-               return 0;
-
-       case CDROMRESUME:       /* keine Ahnung was das ist */
-               return 0;
-
-
-       case CDROMEJECT:
-               cmd_status();
-               to_do[0] = CMD_TRAY_CTL;
-               cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
-
-               return 0;
-
-       default:
-               return -EINVAL;
-       }
-
-}
-
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-
-static void gscd_transfer(struct request *req)
-{
-       while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) {
-               long offs = (req->sector & 3) * 512;
-               memcpy(req->buffer, gscd_buf + offs, 512);
-               req->nr_sectors--;
-               req->sector++;
-               req->buffer += 512;
-       }
-}
-
-
-/*
- * I/O request routine called from Linux kernel.
- */
-
-static void do_gscd_request(request_queue_t * q)
-{
-       __do_gscd_request(0);
-}
-
-static void __do_gscd_request(unsigned long dummy)
-{
-       struct request *req;
-       unsigned int block;
-       unsigned int nsect;
-
-repeat:
-       req = elv_next_request(gscd_queue);
-       if (!req)
-               return;
-
-       block = req->sector;
-       nsect = req->nr_sectors;
-
-       if (req->sector == -1)
-               goto out;
-
-       if (req->cmd != READ) {
-               printk("GSCD: bad cmd %u\n", rq_data_dir(req));
-               end_request(req, 0);
-               goto repeat;
-       }
-
-       gscd_transfer(req);
-
-       /* if we satisfied the request from the buffer, we're done. */
-
-       if (req->nr_sectors == 0) {
-               end_request(req, 1);
-               goto repeat;
-       }
-#ifdef GSCD_DEBUG
-       printk("GSCD: block %d, nsect %d\n", block, nsect);
-#endif
-       gscd_read_cmd(req);
-out:
-       return;
-}
-
-
-
-/*
- * Check the result of the set-mode command.  On success, send the
- * read-data command.
- */
-
-static void gscd_read_cmd(struct request *req)
-{
-       long block;
-       struct gscd_Play_msf gscdcmd;
-       char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */
-
-       cmd_status();
-       if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) {
-               printk("GSCD: no disk or door open\n");
-               end_request(req, 0);
-       } else {
-               if (disk_state & ST_INVALID) {
-                       printk("GSCD: disk invalid\n");
-                       end_request(req, 0);
-               } else {
-                       gscd_bn = -1;   /* purge our buffer */
-                       block = req->sector / 4;
-                       gscd_hsg2msf(block, &gscdcmd.start);    /* cvt to msf format */
-
-                       cmd[2] = gscdcmd.start.min;
-                       cmd[3] = gscdcmd.start.sec;
-                       cmd[4] = gscdcmd.start.frame;
-
-#ifdef GSCD_DEBUG
-                       printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3],
-                              cmd[4]);
-#endif
-                       cmd_out(TYPE_DATA, (char *) &cmd,
-                               (char *) &gscd_buf[0], 1);
-
-                       gscd_bn = req->sector / 4;
-                       gscd_transfer(req);
-                       end_request(req, 1);
-               }
-       }
-       SET_TIMER(__do_gscd_request, 1);
-}
-
-
-/*
- * Open the device special file.  Check that a disk is in.
- */
-
-static int gscd_open(struct inode *ip, struct file *fp)
-{
-       int st;
-
-#ifdef GSCD_DEBUG
-       printk("GSCD: open\n");
-#endif
-
-       if (gscdPresent == 0)
-               return -ENXIO;  /* no hardware */
-
-       get_status();
-       st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN);
-       if (st) {
-               printk("GSCD: no disk or door open\n");
-               return -ENXIO;
-       }
-
-/*     if (updateToc() < 0)
-               return -EIO;
-*/
-
-       return 0;
-}
-
-
-/*
- * On close, we flush all gscd blocks from the buffer cache.
- */
-
-static int gscd_release(struct inode *inode, struct file *file)
-{
-
-#ifdef GSCD_DEBUG
-       printk("GSCD: release\n");
-#endif
-
-       gscd_bn = -1;
-
-       return 0;
-}
-
-
-static int get_status(void)
-{
-       int status;
-
-       cmd_status();
-       status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01);
-
-       if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) {
-               cc_invalidate();
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-
-static void cc_invalidate(void)
-{
-       drv_num_read = 0xFF;
-       f_dsk_valid = 0xFF;
-       current_drive = 0xFF;
-       f_drv_ok = 0xFF;
-
-       clear_Audio();
-
-}
-
-static void clear_Audio(void)
-{
-
-       f_AudioPlay = 0;
-       f_AudioPause = 0;
-       AudioStart_m = 0;
-       AudioStart_f = 0;
-       AudioEnd_m = 0;
-       AudioEnd_f = 0;
-
-}
-
-/*
- *   waiting ?  
- */
-
-static int wait_drv_ready(void)
-{
-       int found, read;
-
-       do {
-               found = inb(GSCDPORT(0));
-               found &= 0x0f;
-               read = inb(GSCDPORT(0));
-               read &= 0x0f;
-       } while (read != found);
-
-#ifdef GSCD_DEBUG
-       printk("Wait for: %d\n", read);
-#endif
-
-       return read;
-}
-
-static void cc_Ident(char *respons)
-{
-       char to_do[] = { CMD_IDENT, 0, 0 };
-
-       cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E);
-
-}
-
-static void cc_SetSpeed(void)
-{
-       char to_do[] = { CMD_SETSPEED, 0, 0 };
-       char dummy;
-
-       if (speed > 0) {
-               to_do[1] = speed & 0x0F;
-               cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
-       }
-}
-
-static void cc_Reset(void)
-{
-       char to_do[] = { CMD_RESET, 0 };
-       char dummy;
-
-       cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
-}
-
-static void cmd_status(void)
-{
-       char to_do[] = { CMD_STATUS, 0 };
-       char dummy;
-
-       cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
-
-#ifdef GSCD_DEBUG
-       printk("GSCD: Status: %d\n", disk_state);
-#endif
-
-}
-
-static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count)
-{
-       int result;
-
-
-       result = wait_drv_ready();
-       if (result != drv_mode) {
-               unsigned long test_loops = 0xFFFF;
-               int i, dummy;
-
-               outb(curr_drv_state, GSCDPORT(0));
-
-               /* LOCLOOP_170 */
-               do {
-                       result = wait_drv_ready();
-                       test_loops--;
-               } while ((result != drv_mode) && (test_loops > 0));
-
-               if (result != drv_mode) {
-                       disk_state = ST_x08 | ST_x04 | ST_INVALID;
-                       return;
-               }
-
-               /* ...and waiting */
-               for (i = 1, dummy = 1; i < 0xFFFF; i++) {
-                       dummy *= i;
-               }
-       }
-
-       /* LOC_172 */
-       /* check the unit */
-       /* and wake it up */
-       if (cmd_unit_alive() != 0x08) {
-               /* LOC_174 */
-               /* game over for this unit */
-               disk_state = ST_x08 | ST_x04 | ST_INVALID;
-               return;
-       }
-
-       /* LOC_176 */
-#ifdef GSCD_DEBUG
-       printk("LOC_176 ");
-#endif
-       if (drv_mode == 0x09) {
-               /* magic... */
-               printk("GSCD: magic ...\n");
-               outb(result, GSCDPORT(2));
-       }
-
-       /* write the command to the drive */
-       cmd_write_cmd(cmd);
-
-       /* LOC_178 */
-       for (;;) {
-               result = wait_drv_ready();
-               if (result != drv_mode) {
-                       /* LOC_179 */
-                       if (result == 0x04) {   /* Mode 4 */
-                               /* LOC_205 */
-#ifdef GSCD_DEBUG
-                               printk("LOC_205 ");
-#endif
-                               disk_state = inb(GSCDPORT(2));
-
-                               do {
-                                       result = wait_drv_ready();
-                               } while (result != drv_mode);
-                               return;
-
-                       } else {
-                               if (result == 0x06) {   /* Mode 6 */
-                                       /* LOC_181 */
-#ifdef GSCD_DEBUG
-                                       printk("LOC_181 ");
-#endif
-
-                                       if (cmd_type == TYPE_DATA) {
-                                               /* read data */
-                                               /* LOC_184 */
-                                               if (drv_mode == 9) {
-                                                       /* read the data to the buffer (word) */
-
-                                                       /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
-                                                       cmd_read_w
-                                                           (respo_buf,
-                                                            respo_count,
-                                                            CD_FRAMESIZE /
-                                                            2);
-                                                       return;
-                                               } else {
-                                                       /* read the data to the buffer (byte) */
-
-                                                       /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW)    */
-                                                       cmd_read_b
-                                                           (respo_buf,
-                                                            respo_count,
-                                                            CD_FRAMESIZE);
-                                                       return;
-                                               }
-                                       } else {
-                                               /* read the info to the buffer */
-                                               cmd_info_in(respo_buf,
-                                                           respo_count);
-                                               return;
-                                       }
-
-                                       return;
-                               }
-                       }
-
-               } else {
-                       disk_state = ST_x08 | ST_x04 | ST_INVALID;
-                       return;
-               }
-       }                       /* for (;;) */
-
-
-#ifdef GSCD_DEBUG
-       printk("\n");
-#endif
-}
-
-
-static void cmd_write_cmd(char *pstr)
-{
-       int i, j;
-
-       /* LOC_177 */
-#ifdef GSCD_DEBUG
-       printk("LOC_177 ");
-#endif
-
-       /* calculate the number of parameter */
-       j = *pstr & 0x0F;
-
-       /* shift it out */
-       for (i = 0; i < j; i++) {
-               outb(*pstr, GSCDPORT(2));
-               pstr++;
-       }
-}
-
-
-static int cmd_unit_alive(void)
-{
-       int result;
-       unsigned long max_test_loops;
-
-
-       /* LOC_172 */
-#ifdef GSCD_DEBUG
-       printk("LOC_172 ");
-#endif
-
-       outb(curr_drv_state, GSCDPORT(0));
-       max_test_loops = 0xFFFF;
-
-       do {
-               result = wait_drv_ready();
-               max_test_loops--;
-       } while ((result != 0x08) && (max_test_loops > 0));
-
-       return result;
-}
-
-
-static void cmd_info_in(char *pb, int count)
-{
-       int result;
-       char read;
-
-
-       /* read info */
-       /* LOC_182 */
-#ifdef GSCD_DEBUG
-       printk("LOC_182 ");
-#endif
-
-       do {
-               read = inb(GSCDPORT(2));
-               if (count > 0) {
-                       *pb = read;
-                       pb++;
-                       count--;
-               }
-
-               /* LOC_183 */
-               do {
-                       result = wait_drv_ready();
-               } while (result == 0x0E);
-       } while (result == 6);
-
-       cmd_end();
-       return;
-}
-
-
-static void cmd_read_b(char *pb, int count, int size)
-{
-       int result;
-       int i;
-
-
-       /* LOC_188 */
-       /* LOC_189 */
-#ifdef GSCD_DEBUG
-       printk("LOC_189 ");
-#endif
-
-       do {
-               do {
-                       result = wait_drv_ready();
-               } while (result != 6 || result == 0x0E);
-
-               if (result != 6) {
-                       cmd_end();
-                       return;
-               }
-#ifdef GSCD_DEBUG
-               printk("LOC_191 ");
-#endif
-
-               for (i = 0; i < size; i++) {
-                       *pb = inb(GSCDPORT(2));
-                       pb++;
-               }
-               count--;
-       } while (count > 0);
-
-       cmd_end();
-       return;
-}
-
-
-static void cmd_end(void)
-{
-       int result;
-
-
-       /* LOC_204 */
-#ifdef GSCD_DEBUG
-       printk("LOC_204 ");
-#endif
-
-       do {
-               result = wait_drv_ready();
-               if (result == drv_mode) {
-                       return;
-               }
-       } while (result != 4);
-
-       /* LOC_205 */
-#ifdef GSCD_DEBUG
-       printk("LOC_205 ");
-#endif
-
-       disk_state = inb(GSCDPORT(2));
-
-       do {
-               result = wait_drv_ready();
-       } while (result != drv_mode);
-       return;
-
-}
-
-
-static void cmd_read_w(char *pb, int count, int size)
-{
-       int result;
-       int i;
-
-
-#ifdef GSCD_DEBUG
-       printk("LOC_185 ");
-#endif
-
-       do {
-               /* LOC_185 */
-               do {
-                       result = wait_drv_ready();
-               } while (result != 6 || result == 0x0E);
-
-               if (result != 6) {
-                       cmd_end();
-                       return;
-               }
-
-               for (i = 0; i < size; i++) {
-                       /* na, hier muss ich noch mal drueber nachdenken */
-                       *pb = inw(GSCDPORT(2));
-                       pb++;
-               }
-               count--;
-       } while (count > 0);
-
-       cmd_end();
-       return;
-}
-
-static int __init find_drives(void)
-{
-       int *pdrv;
-       int drvnum;
-       int subdrv;
-       int i;
-
-       speed = 0;
-       pdrv = (int *) &drv_states;
-       curr_drv_state = 0xFE;
-       subdrv = 0;
-       drvnum = 0;
-
-       for (i = 0; i < 8; i++) {
-               subdrv++;
-               cmd_status();
-               disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01;
-               if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) {
-                       /* LOC_240 */
-                       *pdrv = curr_drv_state;
-                       init_cd_drive(drvnum);
-                       pdrv++;
-                       drvnum++;
-               } else {
-                       if (subdrv < 2) {
-                               continue;
-                       } else {
-                               subdrv = 0;
-                       }
-               }
-
-/*       curr_drv_state<<1;         <-- das geht irgendwie nicht */
-/* muss heissen:    curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
-               curr_drv_state *= 2;
-               curr_drv_state |= 1;
-#ifdef GSCD_DEBUG
-               printk("DriveState: %d\n", curr_drv_state);
-#endif
-       }
-
-       ndrives = drvnum;
-       return drvnum;
-}
-
-static void __init init_cd_drive(int num)
-{
-       char resp[50];
-       int i;
-
-       printk("GSCD: init unit %d\n", num);
-       cc_Ident((char *) &resp);
-
-       printk("GSCD: identification: ");
-       for (i = 0; i < 0x1E; i++) {
-               printk("%c", resp[i]);
-       }
-       printk("\n");
-
-       cc_SetSpeed();
-
-}
-
-#ifdef FUTURE_WORK
-/* return_done */
-static void update_state(void)
-{
-       unsigned int AX;
-
-
-       if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) {
-               if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) {
-                       AX = ST_INVALID;
-               }
-
-               if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01))
-                   == 0) {
-                       invalidate();
-                       f_drv_ok = 0;
-               }
-
-               AX |= 0x8000;
-       }
-
-       if (disk_state & ST_PLAYING) {
-               AX |= 0x200;
-       }
-
-       AX |= 0x100;
-       /* pkt_esbx = AX; */
-
-       disk_state = 0;
-
-}
-#endif
-
-static struct gendisk *gscd_disk;
-
-static void __exit gscd_exit(void)
-{
-       CLEAR_TIMER;
-
-       del_gendisk(gscd_disk);
-       put_disk(gscd_disk);
-       if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) {
-               printk("What's that: can't unregister GoldStar-module\n");
-               return;
-       }
-       blk_cleanup_queue(gscd_queue);
-       release_region(gscd_port, GSCD_IO_EXTENT);
-       printk(KERN_INFO "GoldStar-module released.\n");
-}
-
-/* This is the common initialisation for the GoldStar drive. */
-/* It is called at boot time AND for module init.           */
-static int __init gscd_init(void)
-{
-       int i;
-       int result;
-       int ret=0;
-
-       printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION);
-       printk(KERN_INFO
-              "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n",
-              gscd_port);
-
-       if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) {
-               printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already"
-                      " in use.\n", gscd_port);
-               return -EIO;
-       }
-
-
-       /* check for card */
-       result = wait_drv_ready();
-       if (result == 0x09) {
-               printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n");
-               ret = -EIO;
-               goto err_out1;
-       }
-
-       if (result == 0x0b) {
-               drv_mode = result;
-               i = find_drives();
-               if (i == 0) {
-                       printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is"
-                              " not found.\n");
-                       ret = -EIO;
-                       goto err_out1;
-               }
-       }
-
-       if ((result != 0x0b) && (result != 0x09)) {
-               printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not "
-                      "exist or H/W error\n");
-               ret = -EIO;
-               goto err_out1;
-       }
-
-       /* reset all drives */
-       i = 0;
-       while (drv_states[i] != 0) {
-               curr_drv_state = drv_states[i];
-               printk(KERN_INFO "GSCD: Reset unit %d ... ", i);
-               cc_Reset();
-               printk("done\n");
-               i++;
-       }
-
-       gscd_disk = alloc_disk(1);
-       if (!gscd_disk)
-               goto err_out1;
-       gscd_disk->major = MAJOR_NR;
-       gscd_disk->first_minor = 0;
-       gscd_disk->fops = &gscd_fops;
-       sprintf(gscd_disk->disk_name, "gscd");
-
-       if (register_blkdev(MAJOR_NR, "gscd")) {
-               ret = -EIO;
-               goto err_out2;
-       }
-
-       gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock);
-       if (!gscd_queue) {
-               ret = -ENOMEM;
-               goto err_out3;
-       }
-
-       disk_state = 0;
-       gscdPresent = 1;
-
-       gscd_disk->queue = gscd_queue;
-       add_disk(gscd_disk);
-
-       printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
-       return 0;
-
-err_out3:
-       unregister_blkdev(MAJOR_NR, "gscd");
-err_out2:
-       put_disk(gscd_disk);
-err_out1:
-       release_region(gscd_port, GSCD_IO_EXTENT);
-       return ret;
-}
-
-static void gscd_hsg2msf(long hsg, struct msf *msf)
-{
-       hsg += CD_MSF_OFFSET;
-       msf->min = hsg / (CD_FRAMES * CD_SECS);
-       hsg %= CD_FRAMES * CD_SECS;
-       msf->sec = hsg / CD_FRAMES;
-       msf->frame = hsg % CD_FRAMES;
-
-       gscd_bin2bcd(&msf->min);        /* convert to BCD */
-       gscd_bin2bcd(&msf->sec);
-       gscd_bin2bcd(&msf->frame);
-}
-
-
-static void gscd_bin2bcd(unsigned char *p)
-{
-       int u, t;
-
-       u = *p % 10;
-       t = *p / 10;
-       *p = u | (t << 4);
-}
-
-
-#ifdef FUTURE_WORK
-static long gscd_msf2hsg(struct msf *mp)
-{
-       return gscd_bcd2bin(mp->frame)
-           + gscd_bcd2bin(mp->sec) * CD_FRAMES
-           + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET;
-}
-
-static int gscd_bcd2bin(unsigned char bcd)
-{
-       return (bcd >> 4) * 10 + (bcd & 0xF);
-}
-#endif
-
-MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
-MODULE_LICENSE("GPL");
-module_init(gscd_init);
-module_exit(gscd_exit);
-MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR);
diff --git a/drivers/cdrom/gscd.h b/drivers/cdrom/gscd.h
deleted file mode 100644 (file)
index a41e64b..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Definitions for a GoldStar R420 CD-ROM interface
- *
- *   Copyright (C) 1995  Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>
- *                       Eberhard Moenkeberg <emoenke@gwdg.de>
- *
- *  Published under the GPL.
- *
- */
-
-
-/* The Interface Card default address is 0x340. This will work for most
-   applications. Address selection is accomplished by jumpers PN801-1 to
-   PN801-4 on the GoldStar Interface Card.
-   Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360
-   0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0             */
-
-/* insert here the I/O port address and extent */
-#define GSCD_BASE_ADDR         0x340
-#define GSCD_IO_EXTENT          4
-
-
-/************** nothing to set up below here *********************/
-
-/* port access macro */
-#define GSCDPORT(x)            (gscd_port + (x))
-
-/*
- * commands
- * the lower nibble holds the command length
- */
-#define CMD_STATUS     0x01
-#define CMD_READSUBQ   0x02 /* 1: ?, 2: UPC, 5: ? */
-#define CMD_SEEK       0x05 /* read_mode M-S-F */
-#define CMD_READ       0x07 /* read_mode M-S-F nsec_h nsec_l */
-#define CMD_RESET      0x11
-#define CMD_SETMODE    0x15
-#define CMD_PLAY       0x17 /* M-S-F M-S-F */
-#define CMD_LOCK_CTL   0x22 /* 0: unlock, 1: lock */
-#define CMD_IDENT      0x31
-#define CMD_SETSPEED   0x32 /* 0: auto */ /* ??? */
-#define CMD_GETMODE    0x41
-#define CMD_PAUSE      0x51
-#define CMD_READTOC    0x61
-#define CMD_DISKINFO   0x71
-#define CMD_TRAY_CTL   0x81
-
-/*
- * disk_state:
- */
-#define ST_PLAYING     0x80
-#define ST_UNLOCKED    0x40
-#define ST_NO_DISK     0x20
-#define ST_DOOR_OPEN   0x10
-#define ST_x08  0x08
-#define ST_x04 0x04
-#define ST_INVALID     0x02
-#define ST_x01 0x01
-
-/*
- * cmd_type:
- */
-#define TYPE_INFO      0x01
-#define TYPE_DATA      0x02
-
-/*
- * read_mode:
- */
-#define MOD_POLLED     0x80
-#define MOD_x08        0x08
-#define MOD_RAW        0x04
-
-#define READ_DATA(port, buf, nr) insb(port, buf, nr)
-
-#define SET_TIMER(func, jifs) \
-       ((mod_timer(&gscd_timer, jiffies + jifs)), \
-       (gscd_timer.function = func))
-
-#define CLEAR_TIMER            del_timer_sync(&gscd_timer)
-
-#define MAX_TRACKS             104
-
-struct msf {
-       unsigned char   min;
-       unsigned char   sec;
-       unsigned char   frame;
-};
-
-struct gscd_Play_msf {
-       struct msf      start;
-       struct msf      end;
-};
-
-struct gscd_DiskInfo {
-       unsigned char   first;
-       unsigned char   last;
-       struct msf      diskLength;
-       struct msf      firstTrack;
-};
-
-struct gscd_Toc {
-       unsigned char   ctrl_addr;
-       unsigned char   track;
-       unsigned char   pointIndex;
-       struct msf      trackTime;
-       struct msf      diskTime;
-};
-
diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c
deleted file mode 100644 (file)
index db0fd9a..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/* -- ISP16 cdrom detection and configuration
- *
- *    Copyright (c) 1995,1996 Eric van der Maarel <H.T.M.v.d.Maarel@marin.nl>
- *
- *    Version 0.6
- *
- *    History:
- *    0.5 First release.
- *        Was included in the sjcd and optcd cdrom drivers.
- *    0.6 First "stand-alone" version.
- *        Removed sound configuration.
- *        Added "module" support.
- *
- *      9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                        Removed init_module & cleanup_module in favor of 
- *                        module_init & module_exit.
- *                        Torben Mathiasen <tmm@image.dk>
- *
- *     19 June 2004     -- check_region() converted to request_region()
- *                         and return statement cleanups.
- *                          - Jesper Juhl
- *
- *    Detect cdrom interface on ISP16 sound card.
- *    Configure cdrom interface.
- *
- *    Algorithm for the card with OPTi 82C928 taken
- *    from the CDSETUP.SYS driver for MSDOS,
- *    by OPTi Computers, version 2.03.
- *    Algorithm for the card with OPTi 82C929 as communicated
- *    to me by Vadim Model and Leo Spiekman.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#define ISP16_VERSION_MAJOR 0
-#define ISP16_VERSION_MINOR 6
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include "isp16.h"
-
-static short isp16_detect(void);
-static short isp16_c928__detect(void);
-static short isp16_c929__detect(void);
-static short isp16_cdi_config(int base, u_char drive_type, int irq,
-                             int dma);
-static short isp16_type;       /* dependent on type of interface card */
-static u_char isp16_ctrl;
-static u_short isp16_enable_port;
-
-static int isp16_cdrom_base = ISP16_CDROM_IO_BASE;
-static int isp16_cdrom_irq = ISP16_CDROM_IRQ;
-static int isp16_cdrom_dma = ISP16_CDROM_DMA;
-static char *isp16_cdrom_type = ISP16_CDROM_TYPE;
-
-module_param(isp16_cdrom_base, int, 0);
-module_param(isp16_cdrom_irq, int, 0);
-module_param(isp16_cdrom_dma, int, 0);
-module_param(isp16_cdrom_type, charp, 0);
-
-#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
-#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
-
-#ifndef MODULE
-
-static int
-__init isp16_setup(char *str)
-{
-       int ints[4];
-
-       (void) get_options(str, ARRAY_SIZE(ints), ints);
-       if (ints[0] > 0)
-               isp16_cdrom_base = ints[1];
-       if (ints[0] > 1)
-               isp16_cdrom_irq = ints[2];
-       if (ints[0] > 2)
-               isp16_cdrom_dma = ints[3];
-       if (str)
-               isp16_cdrom_type = str;
-
-       return 1;
-}
-
-__setup("isp16=", isp16_setup);
-
-#endif                         /* MODULE */
-
-/*
- *  ISP16 initialisation.
- *
- */
-static int __init isp16_init(void)
-{
-       u_char expected_drive;
-
-       printk(KERN_INFO
-              "ISP16: configuration cdrom interface, version %d.%d.\n",
-              ISP16_VERSION_MAJOR, ISP16_VERSION_MINOR);
-
-       if (!strcmp(isp16_cdrom_type, "noisp16")) {
-               printk("ISP16: no cdrom interface configured.\n");
-               return 0;
-       }
-
-       if (!request_region(ISP16_IO_BASE, ISP16_IO_SIZE, "isp16")) {
-               printk("ISP16: i/o ports already in use.\n");
-               goto out;
-       }
-
-       if ((isp16_type = isp16_detect()) < 0) {
-               printk("ISP16: no cdrom interface found.\n");
-               goto cleanup_out;
-       }
-
-       printk(KERN_INFO
-              "ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n",
-              (isp16_type == 2) ? 9 : 8);
-
-       if (!strcmp(isp16_cdrom_type, "Sanyo"))
-               expected_drive =
-                   (isp16_type ? ISP16_SANYO1 : ISP16_SANYO0);
-       else if (!strcmp(isp16_cdrom_type, "Sony"))
-               expected_drive = ISP16_SONY;
-       else if (!strcmp(isp16_cdrom_type, "Panasonic"))
-               expected_drive =
-                   (isp16_type ? ISP16_PANASONIC1 : ISP16_PANASONIC0);
-       else if (!strcmp(isp16_cdrom_type, "Mitsumi"))
-               expected_drive = ISP16_MITSUMI;
-       else {
-               printk("ISP16: %s not supported by cdrom interface.\n",
-                      isp16_cdrom_type);
-               goto cleanup_out;
-       }
-
-       if (isp16_cdi_config(isp16_cdrom_base, expected_drive,
-                            isp16_cdrom_irq, isp16_cdrom_dma) < 0) {
-               printk
-                   ("ISP16: cdrom interface has not been properly configured.\n");
-               goto cleanup_out;
-       }
-       printk(KERN_INFO
-              "ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d,"
-              " type %s.\n", isp16_cdrom_base, isp16_cdrom_irq,
-              isp16_cdrom_dma, isp16_cdrom_type);
-       return 0;
-
-cleanup_out:
-       release_region(ISP16_IO_BASE, ISP16_IO_SIZE);
-out:
-       return -EIO;
-}
-
-static short __init isp16_detect(void)
-{
-
-       if (isp16_c929__detect() >= 0)
-               return 2;
-       else
-               return (isp16_c928__detect());
-}
-
-static short __init isp16_c928__detect(void)
-{
-       u_char ctrl;
-       u_char enable_cdrom;
-       u_char io;
-       short i = -1;
-
-       isp16_ctrl = ISP16_C928__CTRL;
-       isp16_enable_port = ISP16_C928__ENABLE_PORT;
-
-       /* read' and write' are a special read and write, respectively */
-
-       /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
-       ctrl = ISP16_IN(ISP16_CTRL_PORT) & 0xFC;
-       ISP16_OUT(ISP16_CTRL_PORT, ctrl);
-
-       /* read' 3,4 and 5-bit from the cdrom enable port */
-       enable_cdrom = ISP16_IN(ISP16_C928__ENABLE_PORT) & 0x38;
-
-       if (!(enable_cdrom & 0x20)) {   /* 5-bit not set */
-               /* read' last 2 bits of ISP16_IO_SET_PORT */
-               io = ISP16_IN(ISP16_IO_SET_PORT) & 0x03;
-               if (((io & 0x01) << 1) == (io & 0x02)) {        /* bits are the same */
-                       if (io == 0) {  /* ...the same and 0 */
-                               i = 0;
-                               enable_cdrom |= 0x20;
-                       } else {        /* ...the same and 1 *//* my card, first time 'round */
-                               i = 1;
-                               enable_cdrom |= 0x28;
-                       }
-                       ISP16_OUT(ISP16_C928__ENABLE_PORT, enable_cdrom);
-               } else {        /* bits are not the same */
-                       ISP16_OUT(ISP16_CTRL_PORT, ctrl);
-                       return i;       /* -> not detected: possibly incorrect conclusion */
-               }
-       } else if (enable_cdrom == 0x20)
-               i = 0;
-       else if (enable_cdrom == 0x28)  /* my card, already initialised */
-               i = 1;
-
-       ISP16_OUT(ISP16_CTRL_PORT, ctrl);
-
-       return i;
-}
-
-static short __init isp16_c929__detect(void)
-{
-       u_char ctrl;
-       u_char tmp;
-
-       isp16_ctrl = ISP16_C929__CTRL;
-       isp16_enable_port = ISP16_C929__ENABLE_PORT;
-
-       /* read' and write' are a special read and write, respectively */
-
-       /* read' ISP16_CTRL_PORT and save */
-       ctrl = ISP16_IN(ISP16_CTRL_PORT);
-
-       /* write' zero to the ctrl port and get response */
-       ISP16_OUT(ISP16_CTRL_PORT, 0);
-       tmp = ISP16_IN(ISP16_CTRL_PORT);
-
-       if (tmp != 2)           /* isp16 with 82C929 not detected */
-               return -1;
-
-       /* restore ctrl port value */
-       ISP16_OUT(ISP16_CTRL_PORT, ctrl);
-
-       return 2;
-}
-
-static short __init
-isp16_cdi_config(int base, u_char drive_type, int irq, int dma)
-{
-       u_char base_code;
-       u_char irq_code;
-       u_char dma_code;
-       u_char i;
-
-       if ((drive_type == ISP16_MITSUMI) && (dma != 0))
-               printk("ISP16: Mitsumi cdrom drive has no dma support.\n");
-
-       switch (base) {
-       case 0x340:
-               base_code = ISP16_BASE_340;
-               break;
-       case 0x330:
-               base_code = ISP16_BASE_330;
-               break;
-       case 0x360:
-               base_code = ISP16_BASE_360;
-               break;
-       case 0x320:
-               base_code = ISP16_BASE_320;
-               break;
-       default:
-               printk
-                   ("ISP16: base address 0x%03X not supported by cdrom interface.\n",
-                    base);
-               return -1;
-       }
-       switch (irq) {
-       case 0:
-               irq_code = ISP16_IRQ_X;
-               break;          /* disable irq */
-       case 5:
-               irq_code = ISP16_IRQ_5;
-               printk("ISP16: irq 5 shouldn't be used by cdrom interface,"
-                      " due to possible conflicts with the sound card.\n");
-               break;
-       case 7:
-               irq_code = ISP16_IRQ_7;
-               printk("ISP16: irq 7 shouldn't be used by cdrom interface,"
-                      " due to possible conflicts with the sound card.\n");
-               break;
-       case 3:
-               irq_code = ISP16_IRQ_3;
-               break;
-       case 9:
-               irq_code = ISP16_IRQ_9;
-               break;
-       case 10:
-               irq_code = ISP16_IRQ_10;
-               break;
-       case 11:
-               irq_code = ISP16_IRQ_11;
-               break;
-       default:
-               printk("ISP16: irq %d not supported by cdrom interface.\n",
-                      irq);
-               return -1;
-       }
-       switch (dma) {
-       case 0:
-               dma_code = ISP16_DMA_X;
-               break;          /* disable dma */
-       case 1:
-               printk("ISP16: dma 1 cannot be used by cdrom interface,"
-                      " due to conflict with the sound card.\n");
-               return -1;
-               break;
-       case 3:
-               dma_code = ISP16_DMA_3;
-               break;
-       case 5:
-               dma_code = ISP16_DMA_5;
-               break;
-       case 6:
-               dma_code = ISP16_DMA_6;
-               break;
-       case 7:
-               dma_code = ISP16_DMA_7;
-               break;
-       default:
-               printk("ISP16: dma %d not supported by cdrom interface.\n",
-                      dma);
-               return -1;
-       }
-
-       if (drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
-           drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
-           drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
-           drive_type != ISP16_DRIVE_X) {
-               printk
-                   ("ISP16: drive type (code 0x%02X) not supported by cdrom"
-                    " interface.\n", drive_type);
-               return -1;
-       }
-
-       /* set type of interface */
-       i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK;      /* clear some bits */
-       ISP16_OUT(ISP16_DRIVE_SET_PORT, i | drive_type);
-
-       /* enable cdrom on interface with 82C929 chip */
-       if (isp16_type > 1)
-               ISP16_OUT(isp16_enable_port, ISP16_ENABLE_CDROM);
-
-       /* set base address, irq and dma */
-       i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK;    /* keep some bits */
-       ISP16_OUT(ISP16_IO_SET_PORT, i | base_code | irq_code | dma_code);
-
-       return 0;
-}
-
-static void __exit isp16_exit(void)
-{
-       release_region(ISP16_IO_BASE, ISP16_IO_SIZE);
-       printk(KERN_INFO "ISP16: module released.\n");
-}
-
-module_init(isp16_init);
-module_exit(isp16_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/cdrom/isp16.h b/drivers/cdrom/isp16.h
deleted file mode 100644 (file)
index 5bd22c8..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -- isp16.h
- *
- *  Header for detection and initialisation of cdrom interface (only) on
- *  ISP16 (MAD16, Mozart) sound card.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* These are the default values */
-#define ISP16_CDROM_TYPE "Sanyo"
-#define ISP16_CDROM_IO_BASE 0x340
-#define ISP16_CDROM_IRQ 0
-#define ISP16_CDROM_DMA 0
-
-/* Some (Media)Magic */
-/* define types of drive the interface on an ISP16 card may be looking at */
-#define ISP16_DRIVE_X 0x00
-#define ISP16_SONY  0x02
-#define ISP16_PANASONIC0 0x02
-#define ISP16_SANYO0 0x02
-#define ISP16_MITSUMI  0x04
-#define ISP16_PANASONIC1 0x06
-#define ISP16_SANYO1 0x06
-#define ISP16_DRIVE_NOT_USED 0x08  /* not used */
-#define ISP16_DRIVE_SET_MASK 0xF1  /* don't change 0-bit or 4-7-bits*/
-/* ...for port */
-#define ISP16_DRIVE_SET_PORT 0xF8D
-/* set io parameters */
-#define ISP16_BASE_340  0x00
-#define ISP16_BASE_330  0x40
-#define ISP16_BASE_360  0x80
-#define ISP16_BASE_320  0xC0
-#define ISP16_IRQ_X  0x00
-#define ISP16_IRQ_5  0x04  /* shouldn't be used to avoid sound card conflicts */
-#define ISP16_IRQ_7  0x08  /* shouldn't be used to avoid sound card conflicts */
-#define ISP16_IRQ_3  0x0C
-#define ISP16_IRQ_9  0x10
-#define ISP16_IRQ_10  0x14
-#define ISP16_IRQ_11  0x18
-#define ISP16_DMA_X  0x03
-#define ISP16_DMA_3  0x00
-#define ISP16_DMA_5  0x00
-#define ISP16_DMA_6  0x01
-#define ISP16_DMA_7  0x02
-#define ISP16_IO_SET_MASK  0x20  /* don't change 5-bit */
-/* ...for port */
-#define ISP16_IO_SET_PORT  0xF8E
-/* enable the card */
-#define ISP16_C928__ENABLE_PORT  0xF90  /* ISP16 with OPTi 82C928 chip */
-#define ISP16_C929__ENABLE_PORT  0xF91  /* ISP16 with OPTi 82C929 chip */
-#define ISP16_ENABLE_CDROM  0x80  /* seven bit */
-
-/* the magic stuff */
-#define ISP16_CTRL_PORT  0xF8F
-#define ISP16_C928__CTRL  0xE2  /* ISP16 with OPTi 82C928 chip */
-#define ISP16_C929__CTRL  0xE3  /* ISP16 with OPTi 82C929 chip */
-
-#define ISP16_IO_BASE 0xF8D
-#define ISP16_IO_SIZE 5  /* ports used from 0xF8D up to 0xF91 */
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
deleted file mode 100644 (file)
index 4310cc8..0000000
+++ /dev/null
@@ -1,1943 +0,0 @@
-/*
- * The Mitsumi CDROM interface
- * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 2.14(hs)
- *
- * ... anyway, I'm back again, thanks to Marcin, he adopted
- * large portions of my code (at least the parts containing
- * my main thoughts ...)
- *
- ****************** H E L P *********************************
- * If you ever plan to update your CD ROM drive and perhaps
- * want to sell or simply give away your Mitsumi FX-001[DS]
- * -- Please --
- * mail me (heiko@lotte.sax.de).  When my last drive goes
- * ballistic no more driver support will be available from me!
- *************************************************************
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Thanks to
- *  The Linux Community at all and ...
- *  Martin Harriss (he wrote the first Mitsumi Driver)
- *  Eberhard Moenkeberg (he gave me much support and the initial kick)
- *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
- *      improved the original driver)
- *  Jon Tombs, Bjorn Ekwall (module support)
- *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
- *  Gerd Knorr (he lent me his PhotoCD)
- *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
- *  Andreas Kies (testing the mysterious hang-ups)
- *  Heiko Eissfeldt (VERIFY_READ/WRITE)
- *  Marcin Dalecki (improved performance, shortened code)
- *  ... somebody forgotten?
- *
- *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                    Removed init_module & cleanup_module in favor of 
- *                    module_init & module_exit.
- *                    Torben Mathiasen <tmm@image.dk>
- */
-
-
-#ifdef RCS
-static const char *mcdx_c_version
-    = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
-#endif
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/current.h>
-#include <asm/uaccess.h>
-
-#include <linux/major.h>
-#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
-#include <linux/blkdev.h>
-
-#include "mcdx.h"
-
-#ifndef HZ
-#error HZ not defined
-#endif
-
-#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
-
-#if !MCDX_QUIET
-#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
-#else
-#define xinfo(fmt, args...) { ; }
-#endif
-
-#if MCDX_DEBUG
-#define xtrace(lvl, fmt, args...) \
-               { if (lvl > 0) \
-                       { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
-#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
-#else
-#define xtrace(lvl, fmt, args...) { ; }
-#define xdebug(fmt, args...) { ; }
-#endif
-
-/* CONSTANTS *******************************************************/
-
-/* Following are the number of sectors we _request_ from the drive
-   every time an access outside the already requested range is done.
-   The _direct_ size is the number of sectors we're allowed to skip
-   directly (performing a read instead of requesting the new sector
-   needed */
-static const int REQUEST_SIZE = 800;   /* should be less then 255 * 4 */
-static const int DIRECT_SIZE = 400;    /* should be less then REQUEST_SIZE */
-
-enum drivemodes { TOC, DATA, RAW, COOKED };
-enum datamodes { MODE0, MODE1, MODE2 };
-enum resetmodes { SOFT, HARD };
-
-static const int SINGLE = 0x01;                /* single speed drive (FX001S, LU) */
-static const int DOUBLE = 0x02;                /* double speed drive (FX001D, ..? */
-static const int DOOR = 0x04;          /* door locking capability */
-static const int MULTI = 0x08;         /* multi session capability */
-
-static const unsigned char READ1X = 0xc0;
-static const unsigned char READ2X = 0xc1;
-
-
-/* DECLARATIONS ****************************************************/
-struct s_subqcode {
-       unsigned char control;
-       unsigned char tno;
-       unsigned char index;
-       struct cdrom_msf0 tt;
-       struct cdrom_msf0 dt;
-};
-
-struct s_diskinfo {
-       unsigned int n_first;
-       unsigned int n_last;
-       struct cdrom_msf0 msf_leadout;
-       struct cdrom_msf0 msf_first;
-};
-
-struct s_multi {
-       unsigned char multi;
-       struct cdrom_msf0 msf_last;
-};
-
-struct s_version {
-       unsigned char code;
-       unsigned char ver;
-};
-
-/* Per drive/controller stuff **************************************/
-
-struct s_drive_stuff {
-       /* waitqueues */
-       wait_queue_head_t busyq;
-       wait_queue_head_t lockq;
-       wait_queue_head_t sleepq;
-
-       /* flags */
-       volatile int introk;    /* status of last irq operation */
-       volatile int busy;      /* drive performs an operation */
-       volatile int lock;      /* exclusive usage */
-
-       /* cd infos */
-       struct s_diskinfo di;
-       struct s_multi multi;
-       struct s_subqcode *toc; /* first entry of the toc array */
-       struct s_subqcode start;
-       struct s_subqcode stop;
-       int xa;                 /* 1 if xa disk */
-       int audio;              /* 1 if audio disk */
-       int audiostatus;
-
-       /* `buffer' control */
-       volatile int valid;     /* pending, ..., values are valid */
-       volatile int pending;   /* next sector to be read */
-       volatile int low_border;        /* first sector not to be skipped direct */
-       volatile int high_border;       /* first sector `out of area' */
-#ifdef AK2
-       volatile int int_err;
-#endif                         /* AK2 */
-
-       /* adds and odds */
-       unsigned wreg_data;     /* w data */
-       unsigned wreg_reset;    /* w hardware reset */
-       unsigned wreg_hcon;     /* w hardware conf */
-       unsigned wreg_chn;      /* w channel */
-       unsigned rreg_data;     /* r data */
-       unsigned rreg_status;   /* r status */
-
-       int irq;                /* irq used by this drive */
-       int present;            /* drive present and its capabilities */
-       unsigned char readcmd;  /* read cmd depends on single/double speed */
-       unsigned char playcmd;  /* play should always be single speed */
-       unsigned int xxx;       /* set if changed, reset while open */
-       unsigned int yyy;       /* set if changed, reset by media_changed */
-       int users;              /* keeps track of open/close */
-       int lastsector;         /* last block accessible */
-       int status;             /* last operation's error / status */
-       int readerrs;           /* # of blocks read w/o error */
-       struct cdrom_device_info info;
-       struct gendisk *disk;
-};
-
-
-/* Prototypes ******************************************************/
-
-/*     The following prototypes are already declared elsewhere.  They are
-       repeated here to show what's going on.  And to sense, if they're
-       changed elsewhere. */
-
-static int mcdx_init(void);
-
-static int mcdx_block_open(struct inode *inode, struct file *file)
-{
-       struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_open(&p->info, inode, file);
-}
-
-static int mcdx_block_release(struct inode *inode, struct file *file)
-{
-       struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_release(&p->info, file);
-}
-
-static int mcdx_block_ioctl(struct inode *inode, struct file *file,
-                               unsigned cmd, unsigned long arg)
-{
-       struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_ioctl(file, &p->info, inode, cmd, arg);
-}
-
-static int mcdx_block_media_changed(struct gendisk *disk)
-{
-       struct s_drive_stuff *p = disk->private_data;
-       return cdrom_media_changed(&p->info);
-}
-
-static struct block_device_operations mcdx_bdops =
-{
-       .owner          = THIS_MODULE,
-       .open           = mcdx_block_open,
-       .release        = mcdx_block_release,
-       .ioctl          = mcdx_block_ioctl,
-       .media_changed  = mcdx_block_media_changed,
-};
-
-
-/*     Indirect exported functions. These functions are exported by their
-       addresses, such as mcdx_open and mcdx_close in the
-       structure mcdx_dops. */
-
-/* exported by file_ops */
-static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
-static void mcdx_close(struct cdrom_device_info *cdi);
-static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
-static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
-static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
-static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
-                           unsigned int cmd, void *arg);
-
-/* misc internal support functions */
-static void log2msf(unsigned int, struct cdrom_msf0 *);
-static unsigned int msf2log(const struct cdrom_msf0 *);
-static unsigned int uint2bcd(unsigned int);
-static unsigned int bcd2uint(unsigned char);
-static unsigned port(int *);
-static int irq(int *);
-static void mcdx_delay(struct s_drive_stuff *, long jifs);
-static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
-                        int nr_sectors);
-static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
-                    int nr_sectors);
-
-static int mcdx_config(struct s_drive_stuff *, int);
-static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
-                              int);
-static int mcdx_stop(struct s_drive_stuff *, int);
-static int mcdx_hold(struct s_drive_stuff *, int);
-static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
-static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
-static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
-static int mcdx_requestsubqcode(struct s_drive_stuff *,
-                               struct s_subqcode *, int);
-static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
-                                    struct s_multi *, int);
-static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
-                              int);
-static int mcdx_getstatus(struct s_drive_stuff *, int);
-static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
-static int mcdx_talk(struct s_drive_stuff *,
-                    const unsigned char *cmd, size_t,
-                    void *buffer, size_t size, unsigned int timeout, int);
-static int mcdx_readtoc(struct s_drive_stuff *);
-static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
-static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
-static int mcdx_setattentuator(struct s_drive_stuff *,
-                              struct cdrom_volctrl *, int);
-
-/* static variables ************************************************/
-
-static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
-static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
-static DEFINE_SPINLOCK(mcdx_lock);
-static struct request_queue *mcdx_queue;
-
-/* You can only set the first two pairs, from old MODULE_PARM code.  */
-static int mcdx_set(const char *val, struct kernel_param *kp)
-{
-       get_options((char *)val, 4, (int *)mcdx_drive_map);
-       return 0;
-}
-module_param_call(mcdx, mcdx_set, NULL, NULL, 0);
-
-static struct cdrom_device_ops mcdx_dops = {
-       .open           = mcdx_open,
-       .release        = mcdx_close,
-       .media_changed  = mcdx_media_changed,
-       .tray_move      = mcdx_tray_move,
-       .lock_door      = mcdx_lockdoor,
-       .audio_ioctl    = mcdx_audio_ioctl,
-       .capability     = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
-                         CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
-};
-
-/* KERNEL INTERFACE FUNCTIONS **************************************/
-
-
-static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
-                           unsigned int cmd, void *arg)
-{
-       struct s_drive_stuff *stuffp = cdi->handle;
-
-       if (!stuffp->present)
-               return -ENXIO;
-
-       if (stuffp->xxx) {
-               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
-                       stuffp->lastsector = -1;
-               } else {
-                       stuffp->lastsector = (CD_FRAMESIZE / 512)
-                           * msf2log(&stuffp->di.msf_leadout) - 1;
-               }
-
-               if (stuffp->toc) {
-                       kfree(stuffp->toc);
-                       stuffp->toc = NULL;
-                       if (-1 == mcdx_readtoc(stuffp))
-                               return -1;
-               }
-
-               stuffp->xxx = 0;
-       }
-
-       switch (cmd) {
-       case CDROMSTART:{
-                       xtrace(IOCTL, "ioctl() START\n");
-                       /* Spin up the drive.  Don't think we can do this.
-                          * For now, ignore it.
-                        */
-                       return 0;
-               }
-
-       case CDROMSTOP:{
-                       xtrace(IOCTL, "ioctl() STOP\n");
-                       stuffp->audiostatus = CDROM_AUDIO_INVALID;
-                       if (-1 == mcdx_stop(stuffp, 1))
-                               return -EIO;
-                       return 0;
-               }
-
-       case CDROMPLAYTRKIND:{
-                       struct cdrom_ti *ti = (struct cdrom_ti *) arg;
-
-                       xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
-                       if ((ti->cdti_trk0 < stuffp->di.n_first)
-                           || (ti->cdti_trk0 > stuffp->di.n_last)
-                           || (ti->cdti_trk1 < stuffp->di.n_first))
-                               return -EINVAL;
-                       if (ti->cdti_trk1 > stuffp->di.n_last)
-                               ti->cdti_trk1 = stuffp->di.n_last;
-                       xtrace(PLAYTRK, "ioctl() track %d to %d\n",
-                              ti->cdti_trk0, ti->cdti_trk1);
-                       return mcdx_playtrk(stuffp, ti);
-               }
-
-       case CDROMPLAYMSF:{
-                       struct cdrom_msf *msf = (struct cdrom_msf *) arg;
-
-                       xtrace(IOCTL, "ioctl() PLAYMSF\n");
-
-                       if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
-                           && (-1 == mcdx_hold(stuffp, 1)))
-                               return -EIO;
-
-                       msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
-                       msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
-                       msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
-
-                       msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
-                       msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
-                       msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
-
-                       stuffp->stop.dt.minute = msf->cdmsf_min1;
-                       stuffp->stop.dt.second = msf->cdmsf_sec1;
-                       stuffp->stop.dt.frame = msf->cdmsf_frame1;
-
-                       return mcdx_playmsf(stuffp, msf);
-               }
-
-       case CDROMRESUME:{
-                       xtrace(IOCTL, "ioctl() RESUME\n");
-                       return mcdx_playtrk(stuffp, NULL);
-               }
-
-       case CDROMREADTOCENTRY:{
-                       struct cdrom_tocentry *entry =
-                           (struct cdrom_tocentry *) arg;
-                       struct s_subqcode *tp = NULL;
-                       xtrace(IOCTL, "ioctl() READTOCENTRY\n");
-
-                       if (-1 == mcdx_readtoc(stuffp))
-                               return -1;
-                       if (entry->cdte_track == CDROM_LEADOUT)
-                               tp = &stuffp->toc[stuffp->di.n_last -
-                                                 stuffp->di.n_first + 1];
-                       else if (entry->cdte_track > stuffp->di.n_last
-                                || entry->cdte_track < stuffp->di.n_first)
-                               return -EINVAL;
-                       else
-                               tp = &stuffp->toc[entry->cdte_track -
-                                                 stuffp->di.n_first];
-
-                       if (NULL == tp)
-                               return -EIO;
-                       entry->cdte_adr = tp->control;
-                       entry->cdte_ctrl = tp->control >> 4;
-                       /* Always return stuff in MSF, and let the Uniform cdrom driver
-                          worry about what the user actually wants */
-                       entry->cdte_addr.msf.minute =
-                           bcd2uint(tp->dt.minute);
-                       entry->cdte_addr.msf.second =
-                           bcd2uint(tp->dt.second);
-                       entry->cdte_addr.msf.frame =
-                           bcd2uint(tp->dt.frame);
-                       return 0;
-               }
-
-       case CDROMSUBCHNL:{
-                       struct cdrom_subchnl *sub =
-                           (struct cdrom_subchnl *) arg;
-                       struct s_subqcode q;
-
-                       xtrace(IOCTL, "ioctl() SUBCHNL\n");
-
-                       if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
-                               return -EIO;
-
-                       xtrace(SUBCHNL, "audiostatus: %x\n",
-                              stuffp->audiostatus);
-                       sub->cdsc_audiostatus = stuffp->audiostatus;
-                       sub->cdsc_adr = q.control;
-                       sub->cdsc_ctrl = q.control >> 4;
-                       sub->cdsc_trk = bcd2uint(q.tno);
-                       sub->cdsc_ind = bcd2uint(q.index);
-
-                       xtrace(SUBCHNL, "trk %d, ind %d\n",
-                              sub->cdsc_trk, sub->cdsc_ind);
-                       /* Always return stuff in MSF, and let the Uniform cdrom driver
-                          worry about what the user actually wants */
-                       sub->cdsc_absaddr.msf.minute =
-                           bcd2uint(q.dt.minute);
-                       sub->cdsc_absaddr.msf.second =
-                           bcd2uint(q.dt.second);
-                       sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
-                       sub->cdsc_reladdr.msf.minute =
-                           bcd2uint(q.tt.minute);
-                       sub->cdsc_reladdr.msf.second =
-                           bcd2uint(q.tt.second);
-                       sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
-                       xtrace(SUBCHNL,
-                              "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
-                              sub->cdsc_absaddr.msf.minute,
-                              sub->cdsc_absaddr.msf.second,
-                              sub->cdsc_absaddr.msf.frame,
-                              sub->cdsc_reladdr.msf.minute,
-                              sub->cdsc_reladdr.msf.second,
-                              sub->cdsc_reladdr.msf.frame);
-
-                       return 0;
-               }
-
-       case CDROMREADTOCHDR:{
-                       struct cdrom_tochdr *toc =
-                           (struct cdrom_tochdr *) arg;
-
-                       xtrace(IOCTL, "ioctl() READTOCHDR\n");
-                       toc->cdth_trk0 = stuffp->di.n_first;
-                       toc->cdth_trk1 = stuffp->di.n_last;
-                       xtrace(TOCHDR,
-                              "ioctl() track0 = %d, track1 = %d\n",
-                              stuffp->di.n_first, stuffp->di.n_last);
-                       return 0;
-               }
-
-       case CDROMPAUSE:{
-                       xtrace(IOCTL, "ioctl() PAUSE\n");
-                       if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
-                               return -EINVAL;
-                       if (-1 == mcdx_stop(stuffp, 1))
-                               return -EIO;
-                       stuffp->audiostatus = CDROM_AUDIO_PAUSED;
-                       if (-1 ==
-                           mcdx_requestsubqcode(stuffp, &stuffp->start,
-                                                1))
-                               return -EIO;
-                       return 0;
-               }
-
-       case CDROMMULTISESSION:{
-                       struct cdrom_multisession *ms =
-                           (struct cdrom_multisession *) arg;
-                       xtrace(IOCTL, "ioctl() MULTISESSION\n");
-                       /* Always return stuff in LBA, and let the Uniform cdrom driver
-                          worry about what the user actually wants */
-                       ms->addr.lba = msf2log(&stuffp->multi.msf_last);
-                       ms->xa_flag = !!stuffp->multi.multi;
-                       xtrace(MS,
-                              "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
-                              ms->xa_flag, ms->addr.lba,
-                              stuffp->multi.msf_last.minute,
-                              stuffp->multi.msf_last.second,
-                              stuffp->multi.msf_last.frame);
-
-                       return 0;
-               }
-
-       case CDROMEJECT:{
-                       xtrace(IOCTL, "ioctl() EJECT\n");
-                       if (stuffp->users > 1)
-                               return -EBUSY;
-                       return (mcdx_tray_move(cdi, 1));
-               }
-
-       case CDROMCLOSETRAY:{
-                       xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
-                       return (mcdx_tray_move(cdi, 0));
-               }
-
-       case CDROMVOLCTRL:{
-                       struct cdrom_volctrl *volctrl =
-                           (struct cdrom_volctrl *) arg;
-                       xtrace(IOCTL, "ioctl() VOLCTRL\n");
-
-#if 0                          /* not tested! */
-                       /* adjust for the weirdness of workman (md) */
-                       /* can't test it (hs) */
-                       volctrl.channel2 = volctrl.channel1;
-                       volctrl.channel1 = volctrl.channel3 = 0x00;
-#endif
-                       return mcdx_setattentuator(stuffp, volctrl, 2);
-               }
-
-       default:
-               return -EINVAL;
-       }
-}
-
-static void do_mcdx_request(request_queue_t * q)
-{
-       struct s_drive_stuff *stuffp;
-       struct request *req;
-
-      again:
-
-       req = elv_next_request(q);
-       if (!req)
-               return;
-
-       stuffp = req->rq_disk->private_data;
-
-       if (!stuffp->present) {
-               xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
-               xtrace(REQUEST, "end_request(0): bad device\n");
-               end_request(req, 0);
-               return;
-       }
-
-       if (stuffp->audio) {
-               xwarn("do_request() attempt to read from audio cd\n");
-               xtrace(REQUEST, "end_request(0): read from audio\n");
-               end_request(req, 0);
-               return;
-       }
-
-       xtrace(REQUEST, "do_request() (%lu + %lu)\n",
-              req->sector, req->nr_sectors);
-
-       if (req->cmd != READ) {
-               xwarn("do_request(): non-read command to cd!!\n");
-               xtrace(REQUEST, "end_request(0): write\n");
-               end_request(req, 0);
-               return;
-       }
-       else {
-               stuffp->status = 0;
-               while (req->nr_sectors) {
-                       int i;
-
-                       i = mcdx_transfer(stuffp,
-                                         req->buffer,
-                                         req->sector,
-                                         req->nr_sectors);
-
-                       if (i == -1) {
-                               end_request(req, 0);
-                               goto again;
-                       }
-                       req->sector += i;
-                       req->nr_sectors -= i;
-                       req->buffer += (i * 512);
-               }
-               end_request(req, 1);
-               goto again;
-
-               xtrace(REQUEST, "end_request(1)\n");
-               end_request(req, 1);
-       }
-
-       goto again;
-}
-
-static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
-{
-       struct s_drive_stuff *stuffp;
-       xtrace(OPENCLOSE, "open()\n");
-       stuffp = cdi->handle;
-       if (!stuffp->present)
-               return -ENXIO;
-
-       /* Make the modules looking used ... (thanx bjorn).
-        * But we shouldn't forget to decrement the module counter
-        * on error return */
-
-       /* this is only done to test if the drive talks with us */
-       if (-1 == mcdx_getstatus(stuffp, 1))
-               return -EIO;
-
-       if (stuffp->xxx) {
-
-               xtrace(OPENCLOSE, "open() media changed\n");
-               stuffp->audiostatus = CDROM_AUDIO_INVALID;
-               stuffp->readcmd = 0;
-               xtrace(OPENCLOSE, "open() Request multisession info\n");
-               if (-1 ==
-                   mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
-                       xinfo("No multidiskinfo\n");
-       } else {
-               /* multisession ? */
-               if (!stuffp->multi.multi)
-                       stuffp->multi.msf_last.second = 2;
-
-               xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
-                      stuffp->multi.multi,
-                      stuffp->multi.msf_last.minute,
-                      stuffp->multi.msf_last.second,
-                      stuffp->multi.msf_last.frame);
-
-               {;
-               }               /* got multisession information */
-               /* request the disks table of contents (aka diskinfo) */
-               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
-
-                       stuffp->lastsector = -1;
-
-               } else {
-
-                       stuffp->lastsector = (CD_FRAMESIZE / 512)
-                           * msf2log(&stuffp->di.msf_leadout) - 1;
-
-                       xtrace(OPENCLOSE,
-                              "open() start %d (%02x:%02x.%02x) %d\n",
-                              stuffp->di.n_first,
-                              stuffp->di.msf_first.minute,
-                              stuffp->di.msf_first.second,
-                              stuffp->di.msf_first.frame,
-                              msf2log(&stuffp->di.msf_first));
-                       xtrace(OPENCLOSE,
-                              "open() last %d (%02x:%02x.%02x) %d\n",
-                              stuffp->di.n_last,
-                              stuffp->di.msf_leadout.minute,
-                              stuffp->di.msf_leadout.second,
-                              stuffp->di.msf_leadout.frame,
-                              msf2log(&stuffp->di.msf_leadout));
-               }
-
-               if (stuffp->toc) {
-                       xtrace(MALLOC, "open() free old toc @ %p\n",
-                              stuffp->toc);
-                       kfree(stuffp->toc);
-
-                       stuffp->toc = NULL;
-               }
-
-               xtrace(OPENCLOSE, "open() init irq generation\n");
-               if (-1 == mcdx_config(stuffp, 1))
-                       return -EIO;
-#ifdef FALLBACK
-               /* Set the read speed */
-               xwarn("AAA %x AAA\n", stuffp->readcmd);
-               if (stuffp->readerrs)
-                       stuffp->readcmd = READ1X;
-               else
-                       stuffp->readcmd =
-                           stuffp->present | SINGLE ? READ1X : READ2X;
-               xwarn("XXX %x XXX\n", stuffp->readcmd);
-#else
-               stuffp->readcmd =
-                   stuffp->present | SINGLE ? READ1X : READ2X;
-#endif
-
-               /* try to get the first sector, iff any ... */
-               if (stuffp->lastsector >= 0) {
-                       char buf[512];
-                       int ans;
-                       int tries;
-
-                       stuffp->xa = 0;
-                       stuffp->audio = 0;
-
-                       for (tries = 6; tries; tries--) {
-
-                               stuffp->introk = 1;
-
-                               xtrace(OPENCLOSE, "open() try as %s\n",
-                                      stuffp->xa ? "XA" : "normal");
-                               /* set data mode */
-                               if (-1 == (ans = mcdx_setdatamode(stuffp,
-                                                                 stuffp->
-                                                                 xa ?
-                                                                 MODE2 :
-                                                                 MODE1,
-                                                                 1))) {
-                                       /* return -EIO; */
-                                       stuffp->xa = 0;
-                                       break;
-                               }
-
-                               if ((stuffp->audio = e_audio(ans)))
-                                       break;
-
-                               while (0 ==
-                                      (ans =
-                                       mcdx_transfer(stuffp, buf, 0, 1)));
-
-                               if (ans == 1)
-                                       break;
-                               stuffp->xa = !stuffp->xa;
-                       }
-               }
-               /* xa disks will be read in raw mode, others not */
-               if (-1 == mcdx_setdrivemode(stuffp,
-                                           stuffp->xa ? RAW : COOKED,
-                                           1))
-                       return -EIO;
-               if (stuffp->audio) {
-                       xinfo("open() audio disk found\n");
-               } else if (stuffp->lastsector >= 0) {
-                       xinfo("open() %s%s disk found\n",
-                             stuffp->xa ? "XA / " : "",
-                             stuffp->multi.
-                             multi ? "Multi Session" : "Single Session");
-               }
-       }
-       stuffp->xxx = 0;
-       stuffp->users++;
-       return 0;
-}
-
-static void mcdx_close(struct cdrom_device_info *cdi)
-{
-       struct s_drive_stuff *stuffp;
-
-       xtrace(OPENCLOSE, "close()\n");
-
-       stuffp = cdi->handle;
-
-       --stuffp->users;
-}
-
-static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-/*     Return: 1 if media changed since last call to this function
-                       0 otherwise */
-{
-       struct s_drive_stuff *stuffp;
-
-       xinfo("mcdx_media_changed called for device %s\n", cdi->name);
-
-       stuffp = cdi->handle;
-       mcdx_getstatus(stuffp, 1);
-
-       if (stuffp->yyy == 0)
-               return 0;
-
-       stuffp->yyy = 0;
-       return 1;
-}
-
-#ifndef MODULE
-static int __init mcdx_setup(char *str)
-{
-       int pi[4];
-       (void) get_options(str, ARRAY_SIZE(pi), pi);
-
-       if (pi[0] > 0)
-               mcdx_drive_map[0][0] = pi[1];
-       if (pi[0] > 1)
-               mcdx_drive_map[0][1] = pi[2];
-       return 1;
-}
-
-__setup("mcdx=", mcdx_setup);
-
-#endif
-
-/* DIRTY PART ******************************************************/
-
-static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/* This routine is used for sleeping.
- * A jifs value <0 means NO sleeping,
- *              =0 means minimal sleeping (let the kernel
- *                 run for other processes)
- *              >0 means at least sleep for that amount.
- *     May be we could use a simple count loop w/ jumps to itself, but
- *     I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
-{
-       if (jifs < 0)
-               return;
-
-       xtrace(SLEEP, "*** delay: sleepq\n");
-       interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
-       xtrace(SLEEP, "delay awoken\n");
-       if (signal_pending(current)) {
-               xtrace(SLEEP, "got signal\n");
-       }
-}
-
-static irqreturn_t mcdx_intr(int irq, void *dev_id)
-{
-       struct s_drive_stuff *stuffp = dev_id;
-       unsigned char b;
-
-#ifdef AK2
-       if (!stuffp->busy && stuffp->pending)
-               stuffp->int_err = 1;
-
-#endif                         /* AK2 */
-       /* get the interrupt status */
-       b = inb(stuffp->rreg_status);
-       stuffp->introk = ~b & MCDX_RBIT_DTEN;
-
-       /* NOTE: We only should get interrupts if the data we
-        * requested are ready to transfer.
-        * But the drive seems to generate ``asynchronous'' interrupts
-        * on several error conditions too.  (Despite the err int enable
-        * setting during initialisation) */
-
-       /* if not ok, read the next byte as the drives status */
-       if (!stuffp->introk) {
-               xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
-               if (~b & MCDX_RBIT_STEN) {
-                       xinfo("intr() irq %d    status 0x%02x\n",
-                             irq, inb(stuffp->rreg_data));
-               } else {
-                       xinfo("intr() irq %d ambiguous hw status\n", irq);
-               }
-       } else {
-               xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
-       }
-
-       stuffp->busy = 0;
-       wake_up_interruptible(&stuffp->busyq);
-       return IRQ_HANDLED;
-}
-
-
-static int mcdx_talk(struct s_drive_stuff *stuffp,
-         const unsigned char *cmd, size_t cmdlen,
-         void *buffer, size_t size, unsigned int timeout, int tries)
-/* Send a command to the drive, wait for the result.
- * returns -1 on timeout, drive status otherwise
- * If buffer is not zero, the result (length size) is stored there.
- * If buffer is zero the size should be the number of bytes to read
- * from the drive.  These bytes are discarded.
- */
-{
-       int st;
-       char c;
-       int discard;
-
-       /* Somebody wants the data read? */
-       if ((discard = (buffer == NULL)))
-               buffer = &c;
-
-       while (stuffp->lock) {
-               xtrace(SLEEP, "*** talk: lockq\n");
-               interruptible_sleep_on(&stuffp->lockq);
-               xtrace(SLEEP, "talk: awoken\n");
-       }
-
-       stuffp->lock = 1;
-
-       /* An operation other then reading data destroys the
-          * data already requested and remembered in stuffp->request, ... */
-       stuffp->valid = 0;
-
-#if MCDX_DEBUG & TALK
-       {
-               unsigned char i;
-               xtrace(TALK,
-                      "talk() %d / %d tries, res.size %d, command 0x%02x",
-                      tries, timeout, size, (unsigned char) cmd[0]);
-               for (i = 1; i < cmdlen; i++)
-                       xtrace(TALK, " 0x%02x", cmd[i]);
-               xtrace(TALK, "\n");
-       }
-#endif
-
-       /*  give up if all tries are done (bad) or if the status
-        *  st != -1 (good) */
-       for (st = -1; st == -1 && tries; tries--) {
-
-               char *bp = (char *) buffer;
-               size_t sz = size;
-
-               outsb(stuffp->wreg_data, cmd, cmdlen);
-               xtrace(TALK, "talk() command sent\n");
-
-               /* get the status byte */
-               if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-                       xinfo("talk() %02x timed out (status), %d tr%s left\n",
-                            cmd[0], tries - 1, tries == 2 ? "y" : "ies");
-                       continue;
-               }
-               st = *bp;
-               sz--;
-               if (!discard)
-                       bp++;
-
-               xtrace(TALK, "talk() got status 0x%02x\n", st);
-
-               /* command error? */
-               if (e_cmderr(st)) {
-                       xwarn("command error cmd = %02x %s \n",
-                             cmd[0], cmdlen > 1 ? "..." : "");
-                       st = -1;
-                       continue;
-               }
-
-               /* audio status? */
-               if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
-                       stuffp->audiostatus =
-                           e_audiobusy(st) ? CDROM_AUDIO_PLAY :
-                           CDROM_AUDIO_NO_STATUS;
-               else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
-                        && e_audiobusy(st) == 0)
-                       stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
-
-               /* media change? */
-               if (e_changed(st)) {
-                       xinfo("talk() media changed\n");
-                       stuffp->xxx = stuffp->yyy = 1;
-               }
-
-               /* now actually get the data */
-               while (sz--) {
-                       if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-                               xinfo("talk() %02x timed out (data), %d tr%s left\n",
-                                    cmd[0], tries - 1,
-                                    tries == 2 ? "y" : "ies");
-                               st = -1;
-                               break;
-                       }
-                       if (!discard)
-                               bp++;
-                       xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
-               }
-       }
-
-#if !MCDX_QUIET
-       if (!tries && st == -1)
-               xinfo("talk() giving up\n");
-#endif
-
-       stuffp->lock = 0;
-       wake_up_interruptible(&stuffp->lockq);
-
-       xtrace(TALK, "talk() done with 0x%02x\n", st);
-       return st;
-}
-
-/* MODULE STUFF ***********************************************************/
-
-static int __init __mcdx_init(void)
-{
-       int i;
-       int drives = 0;
-
-       mcdx_init();
-       for (i = 0; i < MCDX_NDRIVES; i++) {
-               if (mcdx_stuffp[i]) {
-                       xtrace(INIT, "init_module() drive %d stuff @ %p\n",
-                              i, mcdx_stuffp[i]);
-                       drives++;
-               }
-       }
-
-       if (!drives)
-               return -EIO;
-
-       return 0;
-}
-
-static void __exit mcdx_exit(void)
-{
-       int i;
-
-       xinfo("cleanup_module called\n");
-
-       for (i = 0; i < MCDX_NDRIVES; i++) {
-               struct s_drive_stuff *stuffp = mcdx_stuffp[i];
-               if (!stuffp)
-                       continue;
-               del_gendisk(stuffp->disk);
-               if (unregister_cdrom(&stuffp->info)) {
-                       printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
-                       continue;
-               }
-               put_disk(stuffp->disk);
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               free_irq(stuffp->irq, NULL);
-               if (stuffp->toc) {
-                       xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
-                              stuffp->toc);
-                       kfree(stuffp->toc);
-               }
-               xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
-                      stuffp);
-               mcdx_stuffp[i] = NULL;
-               kfree(stuffp);
-       }
-
-       if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
-               xwarn("cleanup() unregister_blkdev() failed\n");
-       }
-#if !MCDX_QUIET
-       else
-       xinfo("cleanup() succeeded\n");
-#endif
-       blk_cleanup_queue(mcdx_queue);
-}
-
-#ifdef MODULE
-module_init(__mcdx_init);
-#endif
-module_exit(mcdx_exit);
-
-
-/* Support functions ************************************************/
-
-static int __init mcdx_init_drive(int drive)
-{
-       struct s_version version;
-       struct gendisk *disk;
-       struct s_drive_stuff *stuffp;
-       int size = sizeof(*stuffp);
-       char msg[80];
-
-       xtrace(INIT, "init() try drive %d\n", drive);
-
-       xtrace(INIT, "kmalloc space for stuffpt's\n");
-       xtrace(MALLOC, "init() malloc %d bytes\n", size);
-       if (!(stuffp = kzalloc(size, GFP_KERNEL))) {
-               xwarn("init() malloc failed\n");
-               return 1;
-       }
-
-       disk = alloc_disk(1);
-       if (!disk) {
-               xwarn("init() malloc failed\n");
-               kfree(stuffp);
-               return 1;
-       }
-
-       xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
-              sizeof(*stuffp), stuffp);
-
-       /* set default values */
-       stuffp->present = 0;    /* this should be 0 already */
-       stuffp->toc = NULL;     /* this should be NULL already */
-
-       /* setup our irq and i/o addresses */
-       stuffp->irq = irq(mcdx_drive_map[drive]);
-       stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
-       stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
-       stuffp->wreg_hcon = stuffp->wreg_reset + 1;
-       stuffp->wreg_chn = stuffp->wreg_hcon + 1;
-
-       init_waitqueue_head(&stuffp->busyq);
-       init_waitqueue_head(&stuffp->lockq);
-       init_waitqueue_head(&stuffp->sleepq);
-
-       /* check if i/o addresses are available */
-       if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
-               xwarn("0x%03x,%d: Init failed. "
-                     "I/O ports (0x%03x..0x%03x) already in use.\n",
-                     stuffp->wreg_data, stuffp->irq,
-                     stuffp->wreg_data,
-                     stuffp->wreg_data + MCDX_IO_SIZE - 1);
-               xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
-               kfree(stuffp);
-               put_disk(disk);
-               xtrace(INIT, "init() continue at next drive\n");
-               return 0;       /* next drive */
-       }
-
-       xtrace(INIT, "init() i/o port is available at 0x%03x\n"
-              stuffp->wreg_data);
-       xtrace(INIT, "init() hardware reset\n");
-       mcdx_reset(stuffp, HARD, 1);
-
-       xtrace(INIT, "init() get version\n");
-       if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
-               /* failed, next drive */
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
-                     MCDX, stuffp->wreg_data, stuffp->irq);
-               xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
-               kfree(stuffp);
-               put_disk(disk);
-               xtrace(INIT, "init() continue at next drive\n");
-               return 0;
-       }
-
-       switch (version.code) {
-       case 'D':
-               stuffp->readcmd = READ2X;
-               stuffp->present = DOUBLE | DOOR | MULTI;
-               break;
-       case 'F':
-               stuffp->readcmd = READ1X;
-               stuffp->present = SINGLE | DOOR | MULTI;
-               break;
-       case 'M':
-               stuffp->readcmd = READ1X;
-               stuffp->present = SINGLE;
-               break;
-       default:
-               stuffp->present = 0;
-               break;
-       }
-
-       stuffp->playcmd = READ1X;
-
-       if (!stuffp->present) {
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
-                     MCDX, stuffp->wreg_data, stuffp->irq);
-               kfree(stuffp);
-               put_disk(disk);
-               return 0;       /* next drive */
-       }
-
-       xtrace(INIT, "init() register blkdev\n");
-       if (register_blkdev(MAJOR_NR, "mcdx")) {
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               kfree(stuffp);
-               put_disk(disk);
-               return 1;
-       }
-
-       mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
-       if (!mcdx_queue) {
-               unregister_blkdev(MAJOR_NR, "mcdx");
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               kfree(stuffp);
-               put_disk(disk);
-               return 1;
-       }
-
-       xtrace(INIT, "init() subscribe irq and i/o\n");
-       if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) {
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
-                     MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
-               stuffp->irq = 0;
-               blk_cleanup_queue(mcdx_queue);
-               kfree(stuffp);
-               put_disk(disk);
-               return 0;
-       }
-
-       xtrace(INIT, "init() get garbage\n");
-       {
-               int i;
-               mcdx_delay(stuffp, HZ / 2);
-               for (i = 100; i; i--)
-                       (void) inb(stuffp->rreg_status);
-       }
-
-
-#ifdef WE_KNOW_WHY
-       /* irq 11 -> channel register */
-       outb(0x50, stuffp->wreg_chn);
-#endif
-
-       xtrace(INIT, "init() set non dma but irq mode\n");
-       mcdx_config(stuffp, 1);
-
-       stuffp->info.ops = &mcdx_dops;
-       stuffp->info.speed = 2;
-       stuffp->info.capacity = 1;
-       stuffp->info.handle = stuffp;
-       sprintf(stuffp->info.name, "mcdx%d", drive);
-       disk->major = MAJOR_NR;
-       disk->first_minor = drive;
-       strcpy(disk->disk_name, stuffp->info.name);
-       disk->fops = &mcdx_bdops;
-       disk->flags = GENHD_FL_CD;
-       stuffp->disk = disk;
-
-       sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
-               " (Firmware version %c %x)\n",
-               stuffp->wreg_data, stuffp->irq, version.code, version.ver);
-       mcdx_stuffp[drive] = stuffp;
-       xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
-       if (register_cdrom(&stuffp->info) != 0) {
-               printk("Cannot register Mitsumi CD-ROM!\n");
-               free_irq(stuffp->irq, NULL);
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               kfree(stuffp);
-               put_disk(disk);
-               if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
-                       xwarn("cleanup() unregister_blkdev() failed\n");
-               blk_cleanup_queue(mcdx_queue);
-               return 2;
-       }
-       disk->private_data = stuffp;
-       disk->queue = mcdx_queue;
-       add_disk(disk);
-       printk(msg);
-       return 0;
-}
-
-static int __init mcdx_init(void)
-{
-       int drive;
-       xwarn("Version 2.14(hs) \n");
-
-       xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
-
-       /* zero the pointer array */
-       for (drive = 0; drive < MCDX_NDRIVES; drive++)
-               mcdx_stuffp[drive] = NULL;
-
-       /* do the initialisation */
-       for (drive = 0; drive < MCDX_NDRIVES; drive++) {
-               switch (mcdx_init_drive(drive)) {
-               case 2:
-                       return -EIO;
-               case 1:
-                       break;
-               }
-       }
-       return 0;
-}
-
-static int mcdx_transfer(struct s_drive_stuff *stuffp,
-             char *p, int sector, int nr_sectors)
-/*     This seems to do the actually transfer.  But it does more.  It
-       keeps track of errors occurred and will (if possible) fall back
-       to single speed on error.
-       Return: -1 on timeout or other error
-                       else status byte (as in stuff->st) */
-{
-       int ans;
-
-       ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
-       return ans;
-#ifdef FALLBACK
-       if (-1 == ans)
-               stuffp->readerrs++;
-       else
-               return ans;
-
-       if (stuffp->readerrs && stuffp->readcmd == READ1X) {
-               xwarn("XXX Already reading 1x -- no chance\n");
-               return -1;
-       }
-
-       xwarn("XXX Fallback to 1x\n");
-
-       stuffp->readcmd = READ1X;
-       return mcdx_transfer(stuffp, p, sector, nr_sectors);
-#endif
-
-}
-
-
-static int mcdx_xfer(struct s_drive_stuff *stuffp,
-                    char *p, int sector, int nr_sectors)
-/*     This does actually the transfer from the drive.
-       Return: -1 on timeout or other error
-                       else status byte (as in stuff->st) */
-{
-       int border;
-       int done = 0;
-       long timeout;
-
-       if (stuffp->audio) {
-               xwarn("Attempt to read from audio CD.\n");
-               return -1;
-       }
-
-       if (!stuffp->readcmd) {
-               xinfo("Can't transfer from missing disk.\n");
-               return -1;
-       }
-
-       while (stuffp->lock) {
-               interruptible_sleep_on(&stuffp->lockq);
-       }
-
-       if (stuffp->valid && (sector >= stuffp->pending)
-           && (sector < stuffp->low_border)) {
-
-               /* All (or at least a part of the sectors requested) seems
-                  * to be already requested, so we don't need to bother the
-                  * drive with new requests ...
-                  * Wait for the drive become idle, but first
-                  * check for possible occurred errors --- the drive
-                  * seems to report them asynchronously */
-
-
-               border = stuffp->high_border < (border =
-                                               sector + nr_sectors)
-                   ? stuffp->high_border : border;
-
-               stuffp->lock = current->pid;
-
-               do {
-
-                       while (stuffp->busy) {
-
-                               timeout =
-                                   interruptible_sleep_on_timeout
-                                   (&stuffp->busyq, 5 * HZ);
-
-                               if (!stuffp->introk) {
-                                       xtrace(XFER,
-                                              "error via interrupt\n");
-                               } else if (!timeout) {
-                                       xtrace(XFER, "timeout\n");
-                               } else if (signal_pending(current)) {
-                                       xtrace(XFER, "signal\n");
-                               } else
-                                       continue;
-
-                               stuffp->lock = 0;
-                               stuffp->busy = 0;
-                               stuffp->valid = 0;
-
-                               wake_up_interruptible(&stuffp->lockq);
-                               xtrace(XFER, "transfer() done (-1)\n");
-                               return -1;
-                       }
-
-                       /* check if we need to set the busy flag (as we
-                        * expect an interrupt */
-                       stuffp->busy = (3 == (stuffp->pending & 3));
-
-                       /* Test if it's the first sector of a block,
-                        * there we have to skip some bytes as we read raw data */
-                       if (stuffp->xa && (0 == (stuffp->pending & 3))) {
-                               const int HEAD =
-                                   CD_FRAMESIZE_RAW - CD_XA_TAIL -
-                                   CD_FRAMESIZE;
-                               insb(stuffp->rreg_data, p, HEAD);
-                       }
-
-                       /* now actually read the data */
-                       insb(stuffp->rreg_data, p, 512);
-
-                       /* test if it's the last sector of a block,
-                        * if so, we have to handle XA special */
-                       if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
-                               char dummy[CD_XA_TAIL];
-                               insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
-                       }
-
-                       if (stuffp->pending == sector) {
-                               p += 512;
-                               done++;
-                               sector++;
-                       }
-               } while (++(stuffp->pending) < border);
-
-               stuffp->lock = 0;
-               wake_up_interruptible(&stuffp->lockq);
-
-       } else {
-
-               /* The requested sector(s) is/are out of the
-                * already requested range, so we have to bother the drive
-                * with a new request. */
-
-               static unsigned char cmd[] = {
-                       0,
-                       0, 0, 0,
-                       0, 0, 0
-               };
-
-               cmd[0] = stuffp->readcmd;
-
-               /* The numbers held in ->pending, ..., should be valid */
-               stuffp->valid = 1;
-               stuffp->pending = sector & ~3;
-
-               /* do some sanity checks */
-               if (stuffp->pending > stuffp->lastsector) {
-                       xwarn
-                           ("transfer() sector %d from nirvana requested.\n",
-                            stuffp->pending);
-                       stuffp->status = MCDX_ST_EOM;
-                       stuffp->valid = 0;
-                       xtrace(XFER, "transfer() done (-1)\n");
-                       return -1;
-               }
-
-               if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
-                   > stuffp->lastsector + 1) {
-                       xtrace(XFER, "cut low_border\n");
-                       stuffp->low_border = stuffp->lastsector + 1;
-               }
-               if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
-                   > stuffp->lastsector + 1) {
-                       xtrace(XFER, "cut high_border\n");
-                       stuffp->high_border = stuffp->lastsector + 1;
-               }
-
-               {               /* Convert the sector to be requested to MSF format */
-                       struct cdrom_msf0 pending;
-                       log2msf(stuffp->pending / 4, &pending);
-                       cmd[1] = pending.minute;
-                       cmd[2] = pending.second;
-                       cmd[3] = pending.frame;
-               }
-
-               cmd[6] =
-                   (unsigned
-                    char) ((stuffp->high_border - stuffp->pending) / 4);
-               xtrace(XFER, "[%2d]\n", cmd[6]);
-
-               stuffp->busy = 1;
-               /* Now really issue the request command */
-               outsb(stuffp->wreg_data, cmd, sizeof cmd);
-
-       }
-#ifdef AK2
-       if (stuffp->int_err) {
-               stuffp->valid = 0;
-               stuffp->int_err = 0;
-               return -1;
-       }
-#endif                         /* AK2 */
-
-       stuffp->low_border = (stuffp->low_border +=
-                             done) <
-           stuffp->high_border ? stuffp->low_border : stuffp->high_border;
-
-       return done;
-}
-
-
-/*     Access to elements of the mcdx_drive_map members */
-
-static unsigned port(int *ip)
-{
-       return ip[0];
-}
-static int irq(int *ip)
-{
-       return ip[1];
-}
-
-/*     Misc number converters */
-
-static unsigned int bcd2uint(unsigned char c)
-{
-       return (c >> 4) * 10 + (c & 0x0f);
-}
-
-static unsigned int uint2bcd(unsigned int ival)
-{
-       return ((ival / 10) << 4) | (ival % 10);
-}
-
-static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
-{
-       l += CD_MSF_OFFSET;
-       pmsf->minute = uint2bcd(l / 4500), l %= 4500;
-       pmsf->second = uint2bcd(l / 75);
-       pmsf->frame = uint2bcd(l % 75);
-}
-
-static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
-{
-       return bcd2uint(pmsf->frame)
-           + bcd2uint(pmsf->second) * 75
-           + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
-}
-
-int mcdx_readtoc(struct s_drive_stuff *stuffp)
-/*  Read the toc entries from the CD,
- *  Return: -1 on failure, else 0 */
-{
-
-       if (stuffp->toc) {
-               xtrace(READTOC, "ioctl() toc already read\n");
-               return 0;
-       }
-
-       xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
-              stuffp->di.n_last - stuffp->di.n_first + 1);
-
-       if (-1 == mcdx_hold(stuffp, 1))
-               return -1;
-
-       xtrace(READTOC, "ioctl() tocmode\n");
-       if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
-               return -EIO;
-
-       /* all seems to be ok so far ... malloc */
-       {
-               int size;
-               size =
-                   sizeof(struct s_subqcode) * (stuffp->di.n_last -
-                                                stuffp->di.n_first + 2);
-
-               xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
-               stuffp->toc = kmalloc(size, GFP_KERNEL);
-               if (!stuffp->toc) {
-                       xwarn("Cannot malloc %d bytes for toc\n", size);
-                       mcdx_setdrivemode(stuffp, DATA, 1);
-                       return -EIO;
-               }
-       }
-
-       /* now read actually the index */
-       {
-               int trk;
-               int retries;
-
-               for (trk = 0;
-                    trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
-                    trk++)
-                       stuffp->toc[trk].index = 0;
-
-               for (retries = 300; retries; retries--) {       /* why 300? */
-                       struct s_subqcode q;
-                       unsigned int idx;
-
-                       if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
-                               mcdx_setdrivemode(stuffp, DATA, 1);
-                               return -EIO;
-                       }
-
-                       idx = bcd2uint(q.index);
-
-                       if ((idx > 0)
-                           && (idx <= stuffp->di.n_last)
-                           && (q.tno == 0)
-                           && (stuffp->toc[idx - stuffp->di.n_first].
-                               index == 0)) {
-                               stuffp->toc[idx - stuffp->di.n_first] = q;
-                               xtrace(READTOC,
-                                      "ioctl() toc idx %d (trk %d)\n",
-                                      idx, trk);
-                               trk--;
-                       }
-                       if (trk == 0)
-                               break;
-               }
-               memset(&stuffp->
-                      toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
-                      sizeof(stuffp->toc[0]));
-               stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
-                           1].dt = stuffp->di.msf_leadout;
-       }
-
-       /* unset toc mode */
-       xtrace(READTOC, "ioctl() undo toc mode\n");
-       if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
-               return -EIO;
-
-#if MCDX_DEBUG && READTOC
-       {
-               int trk;
-               for (trk = 0;
-                    trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
-                    trk++)
-                       xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
-                              "  %02x:%02x.%02x  %02x:%02x.%02x\n",
-                              trk + stuffp->di.n_first,
-                              stuffp->toc[trk].control,
-                              stuffp->toc[trk].tno,
-                              stuffp->toc[trk].index,
-                              stuffp->toc[trk].tt.minute,
-                              stuffp->toc[trk].tt.second,
-                              stuffp->toc[trk].tt.frame,
-                              stuffp->toc[trk].dt.minute,
-                              stuffp->toc[trk].dt.second,
-                              stuffp->toc[trk].dt.frame);
-       }
-#endif
-
-       return 0;
-}
-
-static int
-mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
-{
-       unsigned char cmd[7] = {
-               0, 0, 0, 0, 0, 0, 0
-       };
-
-       if (!stuffp->readcmd) {
-               xinfo("Can't play from missing disk.\n");
-               return -1;
-       }
-
-       cmd[0] = stuffp->playcmd;
-
-       cmd[1] = msf->cdmsf_min0;
-       cmd[2] = msf->cdmsf_sec0;
-       cmd[3] = msf->cdmsf_frame0;
-       cmd[4] = msf->cdmsf_min1;
-       cmd[5] = msf->cdmsf_sec1;
-       cmd[6] = msf->cdmsf_frame1;
-
-       xtrace(PLAYMSF, "ioctl(): play %x "
-              "%02x:%02x:%02x -- %02x:%02x:%02x\n",
-              cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
-
-       outsb(stuffp->wreg_data, cmd, sizeof cmd);
-
-       if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
-               xwarn("playmsf() timeout\n");
-               return -1;
-       }
-
-       stuffp->audiostatus = CDROM_AUDIO_PLAY;
-       return 0;
-}
-
-static int
-mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
-{
-       struct s_subqcode *p;
-       struct cdrom_msf msf;
-
-       if (-1 == mcdx_readtoc(stuffp))
-               return -1;
-
-       if (ti)
-               p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
-       else
-               p = &stuffp->start;
-
-       msf.cdmsf_min0 = p->dt.minute;
-       msf.cdmsf_sec0 = p->dt.second;
-       msf.cdmsf_frame0 = p->dt.frame;
-
-       if (ti) {
-               p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
-               stuffp->stop = *p;
-       } else
-               p = &stuffp->stop;
-
-       msf.cdmsf_min1 = p->dt.minute;
-       msf.cdmsf_sec1 = p->dt.second;
-       msf.cdmsf_frame1 = p->dt.frame;
-
-       return mcdx_playmsf(stuffp, &msf);
-}
-
-
-/* Drive functions ************************************************/
-
-static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
-{
-       struct s_drive_stuff *stuffp = cdi->handle;
-
-       if (!stuffp->present)
-               return -ENXIO;
-       if (!(stuffp->present & DOOR))
-               return -ENOSYS;
-
-       if (position)           /* 1: eject */
-               return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
-       else                    /* 0: close */
-               return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
-       return 1;
-}
-
-static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{
-       return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
-}
-
-static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{
-       return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
-}
-
-static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
-                    struct s_subqcode *sub, int tries)
-{
-       char buf[11];
-       int ans;
-
-       if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
-                                  2 * HZ, tries)))
-               return -1;
-       sub->control = buf[1];
-       sub->tno = buf[2];
-       sub->index = buf[3];
-       sub->tt.minute = buf[4];
-       sub->tt.second = buf[5];
-       sub->tt.frame = buf[6];
-       sub->dt.minute = buf[8];
-       sub->dt.second = buf[9];
-       sub->dt.frame = buf[10];
-
-       return ans;
-}
-
-static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
-                         struct s_multi *multi, int tries)
-{
-       char buf[5];
-       int ans;
-
-       if (stuffp->present & MULTI) {
-               ans =
-                   mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
-                             tries);
-               multi->multi = buf[1];
-               multi->msf_last.minute = buf[2];
-               multi->msf_last.second = buf[3];
-               multi->msf_last.frame = buf[4];
-               return ans;
-       } else {
-               multi->multi = 0;
-               return 0;
-       }
-}
-
-static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
-                   int tries)
-{
-       char buf[9];
-       int ans;
-       ans =
-           mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
-       if (ans == -1) {
-               info->n_first = 0;
-               info->n_last = 0;
-       } else {
-               info->n_first = bcd2uint(buf[1]);
-               info->n_last = bcd2uint(buf[2]);
-               info->msf_leadout.minute = buf[3];
-               info->msf_leadout.second = buf[4];
-               info->msf_leadout.frame = buf[5];
-               info->msf_first.minute = buf[6];
-               info->msf_first.second = buf[7];
-               info->msf_first.frame = buf[8];
-       }
-       return ans;
-}
-
-static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
-                 int tries)
-{
-       char cmd[2];
-       int ans;
-
-       xtrace(HW, "setdrivemode() %d\n", mode);
-
-       if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
-               return -1;
-
-       switch (mode) {
-       case TOC:
-               cmd[1] |= 0x04;
-               break;
-       case DATA:
-               cmd[1] &= ~0x04;
-               break;
-       case RAW:
-               cmd[1] |= 0x40;
-               break;
-       case COOKED:
-               cmd[1] &= ~0x40;
-               break;
-       default:
-               break;
-       }
-       cmd[0] = 0x50;
-       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
-}
-
-static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
-                int tries)
-{
-       unsigned char cmd[2] = { 0xa0 };
-       xtrace(HW, "setdatamode() %d\n", mode);
-       switch (mode) {
-       case MODE0:
-               cmd[1] = 0x00;
-               break;
-       case MODE1:
-               cmd[1] = 0x01;
-               break;
-       case MODE2:
-               cmd[1] = 0x02;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
-}
-
-static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
-{
-       char cmd[4];
-
-       xtrace(HW, "config()\n");
-
-       cmd[0] = 0x90;
-
-       cmd[1] = 0x10;          /* irq enable */
-       cmd[2] = 0x05;          /* pre, err irq enable */
-
-       if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
-               return -1;
-
-       cmd[1] = 0x02;          /* dma select */
-       cmd[2] = 0x00;          /* no dma */
-
-       return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
-}
-
-static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
-                   int tries)
-{
-       char buf[3];
-       int ans;
-
-       if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
-                                  1, buf, sizeof(buf), 2 * HZ, tries)))
-               return ans;
-
-       ver->code = buf[1];
-       ver->ver = buf[2];
-
-       return ans;
-}
-
-static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
-{
-       if (mode == HARD) {
-               outb(0, stuffp->wreg_chn);      /* no dma, no irq -> hardware */
-               outb(0, stuffp->wreg_reset);    /* hw reset */
-               return 0;
-       } else
-               return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
-}
-
-static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
-{
-       struct s_drive_stuff *stuffp = cdi->handle;
-       char cmd[2] = { 0xfe };
-
-       if (!(stuffp->present & DOOR))
-               return -ENOSYS;
-       if (stuffp->present & DOOR) {
-               cmd[1] = lock ? 0x01 : 0x00;
-               return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
-       } else
-               return 0;
-}
-
-static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{
-       return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
-}
-
-static int
-mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
-{
-       unsigned long timeout = to + jiffies;
-       char c;
-
-       if (!buf)
-               buf = &c;
-
-       while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
-               if (time_after(jiffies, timeout))
-                       return -1;
-               mcdx_delay(stuffp, delay);
-       }
-
-       *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
-
-       return 0;
-}
-
-static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
-                   struct cdrom_volctrl *vol, int tries)
-{
-       char cmd[5];
-       cmd[0] = 0xae;
-       cmd[1] = vol->channel0;
-       cmd[2] = 0;
-       cmd[3] = vol->channel1;
-       cmd[4] = 0;
-
-       return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);
diff --git a/drivers/cdrom/mcdx.h b/drivers/cdrom/mcdx.h
deleted file mode 100644 (file)
index 83c364a..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Definitions for the Mitsumi CDROM interface
- * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: @VERSION@
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Thanks to
- *  The Linux Community at all and ...
- *  Martin Harris (he wrote the first Mitsumi Driver)
- *  Eberhard Moenkeberg (he gave me much support and the initial kick)
- *  Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they
- *      improved the original driver)
- *  Jon Tombs, Bjorn Ekwall (module support)
- *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
- *  Gerd Knorr (he lent me his PhotoCD)
- *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
- *  Andreas Kies (testing the mysterious hang up's)
- *  ... somebody forgotten?
- *  Marcin Dalecki
- *  
- */
-
-/*
- *     The following lines are for user configuration
- *     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *     {0|1} -- 1 if you want the driver detect your drive, may crash and
- *     needs a long time to seek.  The higher the address the longer the
- *     seek.
- *
- *  WARNING: AUTOPROBE doesn't work.
- */
-#define MCDX_AUTOPROBE 0
-
-/*
- *     Drive specific settings according to the jumpers on the controller
- *     board(s).
- *     o       MCDX_NDRIVES  :  number of used entries of the following table
- *     o       MCDX_DRIVEMAP :  table of {i/o base, irq} per controller
- *
- *     NOTE: I didn't get a drive at irq 9(2) working.  Not even alone.
- */
-#if MCDX_AUTOPROBE == 0
-       #define MCDX_NDRIVES 1
-       #define MCDX_DRIVEMAP {         \
-                       {0x300, 11},    \
-                       {0x304, 05},    \
-                       {0x000, 00},    \
-                       {0x000, 00},    \
-                       {0x000, 00},    \
-               }
-#else
-       #error Autoprobing is not implemented yet.
-#endif
-
-#ifndef MCDX_QUIET
-#define MCDX_QUIET   1
-#endif
-
-#ifndef MCDX_DEBUG
-#define MCDX_DEBUG   0
-#endif
-
-/* *** make the following line uncommented, if you're sure,
- * *** all configuration is done */
-/* #define I_WAS_HERE */
-
-/*     The name of the device */
-#define MCDX "mcdx"    
-
-/* Flags for DEBUGGING */
-#define INIT           0
-#define MALLOC                 0
-#define IOCTL          0
-#define PLAYTRK     0
-#define SUBCHNL     0
-#define TOCHDR      0
-#define MS          0
-#define PLAYMSF     0
-#define READTOC     0
-#define OPENCLOSE      0
-#define HW                 0
-#define TALK           0
-#define IRQ            0
-#define XFER           0
-#define REQUEST                0
-#define SLEEP          0
-
-/*     The following addresses are taken from the Mitsumi Reference 
- *  and describe the possible i/o range for the controller.
- */
-#define MCDX_IO_BEGIN  ((char*) 0x300) /* first base of i/o addr */
-#define MCDX_IO_END            ((char*) 0x3fc) /* last base of i/o addr */
-
-/*     Per controller 4 bytes i/o are needed. */
-#define MCDX_IO_SIZE           4
-
-/*
- *     Bits
- */
-
-/* The status byte, returned from every command, set if
- * the description is true */
-#define MCDX_RBIT_OPEN       0x80      /* door is open */
-#define MCDX_RBIT_DISKSET    0x40      /* disk set (recognised) */
-#define MCDX_RBIT_CHANGED    0x20      /* disk was changed */
-#define MCDX_RBIT_CHECK      0x10      /* disk rotates, servo is on */
-#define MCDX_RBIT_AUDIOTR    0x08   /* current track is audio */
-#define MCDX_RBIT_RDERR      0x04      /* read error, refer SENSE KEY */
-#define MCDX_RBIT_AUDIOBS    0x02      /* currently playing audio */
-#define MCDX_RBIT_CMDERR     0x01      /* command, param or format error */
-
-/* The I/O Register holding the h/w status of the drive,
- * can be read at i/o base + 1 */
-#define MCDX_RBIT_DOOR       0x10      /* door is open */
-#define MCDX_RBIT_STEN       0x04      /* if 0, i/o base contains drive status */
-#define MCDX_RBIT_DTEN       0x02      /* if 0, i/o base contains data */
-
-/*
- *     The commands.
- */
-
-#define OPCODE 1               /* offset of opcode */
-#define MCDX_CMD_REQUEST_TOC           1, 0x10
-#define MCDX_CMD_REQUEST_STATUS                1, 0x40 
-#define MCDX_CMD_RESET                         1, 0x60
-#define MCDX_CMD_REQUEST_DRIVE_MODE    1, 0xc2
-#define MCDX_CMD_SET_INTERLEAVE                2, 0xc8, 0
-#define MCDX_CMD_DATAMODE_SET          2, 0xa0, 0
-       #define MCDX_DATAMODE1          0x01
-       #define MCDX_DATAMODE2          0x02
-#define MCDX_CMD_LOCK_DOOR             2, 0xfe, 0
-
-#define READ_AHEAD                     4       /* 8 Sectors (4K) */
-
-/*     Useful macros */
-#define e_door(x)              ((x) & MCDX_RBIT_OPEN)
-#define e_check(x)             (~(x) & MCDX_RBIT_CHECK)
-#define e_notset(x)            (~(x) & MCDX_RBIT_DISKSET)
-#define e_changed(x)   ((x) & MCDX_RBIT_CHANGED)
-#define e_audio(x)             ((x) & MCDX_RBIT_AUDIOTR)
-#define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS)
-#define e_cmderr(x)            ((x) & MCDX_RBIT_CMDERR)
-#define e_readerr(x)   ((x) & MCDX_RBIT_RDERR)
-
-/**    no drive specific */
-#define MCDX_CDBLK     2048    /* 2048 cooked data each blk */
-
-#define MCDX_DATA_TIMEOUT      (HZ/10) /* 0.1 second */
-
-/*
- * Access to the msf array
- */
-#define MSF_MIN                0                       /* minute */
-#define MSF_SEC                1                       /* second */
-#define MSF_FRM                2                       /* frame  */
-
-/*
- * Errors
- */
-#define MCDX_E         1                       /* unspec error */
-#define MCDX_ST_EOM 0x0100             /* end of media */
-#define MCDX_ST_DRV 0x00ff             /* mask to query the drive status */
-
-#ifndef I_WAS_HERE
-#ifndef MODULE
-#warning You have not edited mcdx.h
-#warning Perhaps irq and i/o settings are wrong.
-#endif
-#endif
-
-/* ex:set ts=4 sw=4: */
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
deleted file mode 100644 (file)
index 3541690..0000000
+++ /dev/null
@@ -1,2105 +0,0 @@
-/*     linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
-       $Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $
-
-       Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
-
-
-       Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
-       by Eberhard Moenkeberg (emoenke@gwdg.de). 
-
-       This program is free software; you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation; either version 2, or (at your option)
-       any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-       GNU General Public License for more details.
-
-       You should have received a copy of the GNU General Public License
-       along with this program; if not, write to the Free Software
-       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-\f
-/*     Revision history
-
-
-       14-5-95         v0.0    Plays sound tracks. No reading of data CDs yet.
-                               Detection of disk change doesn't work.
-       21-5-95         v0.1    First ALPHA version. CD can be mounted. The
-                               device major nr is borrowed from the Aztech
-                               driver. Speed is around 240 kb/s, as measured
-                               with "time dd if=/dev/cdrom of=/dev/null \
-                               bs=2048 count=4096".
-       24-6-95         v0.2    Reworked the #defines for the command codes
-                               and the like, as well as the structure of
-                               the hardware communication protocol, to
-                               reflect the "official" documentation, kindly
-                               supplied by C.K. Tan, Optics Storage Pte. Ltd.
-                               Also tidied up the state machine somewhat.
-       28-6-95         v0.3    Removed the ISP-16 interface code, as this
-                               should go into its own driver. The driver now
-                               has its own major nr.
-                               Disk change detection now seems to work, too.
-                               This version became part of the standard
-                               kernel as of version 1.3.7
-       24-9-95         v0.4    Re-inserted ISP-16 interface code which I
-                               copied from sjcd.c, with a few changes.
-                               Updated README.optcd. Submitted for
-                               inclusion in 1.3.21
-       29-9-95         v0.4a   Fixed bug that prevented compilation as module
-       25-10-95        v0.5    Started multisession code. Implementation
-                               copied from Werner Zimmermann, who copied it
-                               from Heiko Schlittermann's mcdx.
-       17-1-96         v0.6    Multisession works; some cleanup too.
-       18-4-96         v0.7    Increased some timing constants;
-                               thanks to Luke McFarlane. Also tidied up some
-                               printk behaviour. ISP16 initialization
-                               is now handled by a separate driver.
-                               
-       09-11-99                Make kernel-parameter implementation work with 2.3.x 
-                               Removed init_module & cleanup_module in favor of 
-                               module_init & module_exit.
-                               Torben Mathiasen <tmm@image.dk>
-*/
-\f
-/* Includes */
-
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <linux/blkdev.h>
-
-#include <linux/cdrom.h>
-#include "optcd.h"
-
-#include <asm/uaccess.h>
-
-#define MAJOR_NR OPTICS_CDROM_MAJOR
-#define QUEUE (opt_queue)
-#define CURRENT elv_next_request(opt_queue)
-
-\f
-/* Debug support */
-
-
-/* Don't forget to add new debug flags here. */
-#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
-    DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
-#define DEBUG(x) debug x
-static void debug(int debug_this, const char* fmt, ...)
-{
-       char s[1024];
-       va_list args;
-
-       if (!debug_this)
-               return;
-
-       va_start(args, fmt);
-       vsnprintf(s, sizeof(s), fmt, args);
-       printk(KERN_DEBUG "optcd: %s\n", s);
-       va_end(args);
-}
-#else
-#define DEBUG(x)
-#endif
-
-\f
-/* Drive hardware/firmware characteristics
-   Identifiers in accordance with Optics Storage documentation */
-
-
-#define optcd_port optcd                       /* Needed for the modutils. */
-static short optcd_port = OPTCD_PORTBASE;      /* I/O base of drive. */
-module_param(optcd_port, short, 0);
-/* Drive registers, read */
-#define DATA_PORT      optcd_port      /* Read data/status */
-#define STATUS_PORT    optcd_port+1    /* Indicate data/status availability */
-
-/* Drive registers, write */
-#define COMIN_PORT     optcd_port      /* For passing command/parameter */
-#define RESET_PORT     optcd_port+1    /* Write anything and wait 0.5 sec */
-#define HCON_PORT      optcd_port+2    /* Host Xfer Configuration */
-
-
-/* Command completion/status read from DATA register */
-#define ST_DRVERR              0x80
-#define ST_DOOR_OPEN           0x40
-#define ST_MIXEDMODE_DISK      0x20
-#define ST_MODE_BITS           0x1c
-#define ST_M_STOP              0x00
-#define ST_M_READ              0x04
-#define ST_M_AUDIO             0x04
-#define ST_M_PAUSE             0x08
-#define ST_M_INITIAL           0x0c
-#define ST_M_ERROR             0x10
-#define ST_M_OTHERS            0x14
-#define        ST_MODE2TRACK           0x02
-#define        ST_DSK_CHG              0x01
-#define ST_L_LOCK              0x01
-#define ST_CMD_OK              0x00
-#define ST_OP_OK               0x01
-#define ST_PA_OK               0x02
-#define ST_OP_ERROR            0x05
-#define ST_PA_ERROR            0x06
-
-
-/* Error codes (appear as command completion code from DATA register) */
-/* Player related errors */
-#define ERR_ILLCMD     0x11    /* Illegal command to player module */
-#define ERR_ILLPARM    0x12    /* Illegal parameter to player module */
-#define ERR_SLEDGE     0x13
-#define ERR_FOCUS      0x14
-#define ERR_MOTOR      0x15
-#define ERR_RADIAL     0x16
-#define ERR_PLL                0x17    /* PLL lock error */
-#define ERR_SUB_TIM    0x18    /* Subcode timeout error */
-#define ERR_SUB_NF     0x19    /* Subcode not found error */
-#define ERR_TRAY       0x1a
-#define ERR_TOC                0x1b    /* Table of Contents read error */
-#define ERR_JUMP       0x1c
-/* Data errors */
-#define ERR_MODE       0x21
-#define ERR_FORM       0x22
-#define ERR_HEADADDR   0x23    /* Header Address not found */
-#define ERR_CRC                0x24
-#define ERR_ECC                0x25    /* Uncorrectable ECC error */
-#define ERR_CRC_UNC    0x26    /* CRC error and uncorrectable error */
-#define ERR_ILLBSYNC   0x27    /* Illegal block sync error */
-#define ERR_VDST       0x28    /* VDST not found */
-/* Timeout errors */
-#define ERR_READ_TIM   0x31    /* Read timeout error */
-#define ERR_DEC_STP    0x32    /* Decoder stopped */
-#define ERR_DEC_TIM    0x33    /* Decoder interrupt timeout error */
-/* Function abort codes */
-#define ERR_KEY                0x41    /* Key -Detected abort */
-#define ERR_READ_FINISH        0x42    /* Read Finish */
-/* Second Byte diagnostic codes */
-#define ERR_NOBSYNC    0x01    /* No block sync */
-#define ERR_SHORTB     0x02    /* Short block */
-#define ERR_LONGB      0x03    /* Long block */
-#define ERR_SHORTDSP   0x04    /* Short DSP word */
-#define ERR_LONGDSP    0x05    /* Long DSP word */
-
-
-/* Status availability flags read from STATUS register */
-#define FL_EJECT       0x20
-#define FL_WAIT                0x10    /* active low */
-#define FL_EOP         0x08    /* active low */
-#define FL_STEN                0x04    /* Status available when low */
-#define FL_DTEN                0x02    /* Data available when low */
-#define FL_DRQ         0x01    /* active low */
-#define FL_RESET       0xde    /* These bits are high after a reset */
-#define FL_STDT                (FL_STEN|FL_DTEN)
-
-
-/* Transfer mode, written to HCON register */
-#define HCON_DTS       0x08
-#define HCON_SDRQB     0x04
-#define HCON_LOHI      0x02
-#define HCON_DMA16     0x01
-
-
-/* Drive command set, written to COMIN register */
-/* Quick response commands */
-#define COMDRVST       0x20    /* Drive Status Read */
-#define COMERRST       0x21    /* Error Status Read */
-#define COMIOCTLISTAT  0x22    /* Status Read; reset disk changed bit */
-#define COMINITSINGLE  0x28    /* Initialize Single Speed */
-#define COMINITDOUBLE  0x29    /* Initialize Double Speed */
-#define COMUNLOCK      0x30    /* Unlock */
-#define COMLOCK                0x31    /* Lock */
-#define COMLOCKST      0x32    /* Lock/Unlock Status */
-#define COMVERSION     0x40    /* Get Firmware Revision */
-#define COMVOIDREADMODE        0x50    /* Void Data Read Mode */
-/* Read commands */
-#define COMFETCH       0x60    /* Prefetch Data */
-#define COMREAD                0x61    /* Read */
-#define COMREADRAW     0x62    /* Read Raw Data */
-#define COMREADALL     0x63    /* Read All 2646 Bytes */
-/* Player control commands */
-#define COMLEADIN      0x70    /* Seek To Lead-in */
-#define COMSEEK                0x71    /* Seek */
-#define COMPAUSEON     0x80    /* Pause On */
-#define COMPAUSEOFF    0x81    /* Pause Off */
-#define COMSTOP                0x82    /* Stop */
-#define COMOPEN                0x90    /* Open Tray Door */
-#define COMCLOSE       0x91    /* Close Tray Door */
-#define COMPLAY                0xa0    /* Audio Play */
-#define COMPLAY_TNO    0xa2    /* Audio Play By Track Number */
-#define COMSUBQ                0xb0    /* Read Sub-q Code */
-#define COMLOCATION    0xb1    /* Read Head Position */
-/* Audio control commands */
-#define COMCHCTRL      0xc0    /* Audio Channel Control */
-/* Miscellaneous (test) commands */
-#define COMDRVTEST     0xd0    /* Write Test Bytes */
-#define COMTEST                0xd1    /* Diagnostic Test */
-\f
-/* Low level drive interface. Only here we do actual I/O
-   Waiting for status / data available */
-
-
-/* Busy wait until FLAG goes low. Return 0 on timeout. */
-static inline int flag_low(int flag, unsigned long timeout)
-{
-       int flag_high;
-       unsigned long count = 0;
-
-       while ((flag_high = (inb(STATUS_PORT) & flag)))
-               if (++count >= timeout)
-                       break;
-
-       DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
-               flag, count, flag_high ? " timeout" : ""));
-       return !flag_high;
-}
-
-
-/* Timed waiting for status or data */
-static int sleep_timeout;      /* max # of ticks to sleep */
-static DECLARE_WAIT_QUEUE_HEAD(waitq);
-static void sleep_timer(unsigned long data);
-static DEFINE_TIMER(delay_timer, sleep_timer, 0, 0);
-static DEFINE_SPINLOCK(optcd_lock);
-static struct request_queue *opt_queue;
-
-/* Timer routine: wake up when desired flag goes low,
-   or when timeout expires. */
-static void sleep_timer(unsigned long data)
-{
-       int flags = inb(STATUS_PORT) & FL_STDT;
-
-       if (flags == FL_STDT && --sleep_timeout > 0) {
-               mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */
-       } else
-               wake_up(&waitq);
-}
-
-
-/* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
-static int sleep_flag_low(int flag, unsigned long timeout)
-{
-       int flag_high;
-
-       DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
-
-       sleep_timeout = timeout;
-       flag_high = inb(STATUS_PORT) & flag;
-       if (flag_high && sleep_timeout > 0) {
-               mod_timer(&delay_timer, jiffies + HZ/100);
-               sleep_on(&waitq);
-               flag_high = inb(STATUS_PORT) & flag;
-       }
-
-       DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
-               flag, timeout, flag_high ? " timeout" : ""));
-       return !flag_high;
-}
-\f
-/* Low level drive interface. Only here we do actual I/O
-   Sending commands and parameters */
-
-
-/* Errors in the command protocol */
-#define ERR_IF_CMD_TIMEOUT     0x100
-#define ERR_IF_ERR_TIMEOUT     0x101
-#define ERR_IF_RESP_TIMEOUT    0x102
-#define ERR_IF_DATA_TIMEOUT    0x103
-#define ERR_IF_NOSTAT          0x104
-
-
-/* Send command code. Return <0 indicates error */
-static int send_cmd(int cmd)
-{
-       unsigned char ack;
-
-       DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
-
-       outb(HCON_DTS, HCON_PORT);      /* Enable Suspend Data Transfer */
-       outb(cmd, COMIN_PORT);          /* Send command code */
-       if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
-               return -ERR_IF_CMD_TIMEOUT;
-       ack = inb(DATA_PORT);           /* read command acknowledge */
-       outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
-       return ack==ST_OP_OK ? 0 : -ack;
-}
-
-
-/* Send command parameters. Return <0 indicates error */
-static int send_params(struct cdrom_msf *params)
-{
-       unsigned char ack;
-
-       DEBUG((DEBUG_DRIVE_IF, "sending parameters"
-               " %02x:%02x:%02x"
-               " %02x:%02x:%02x",
-               params->cdmsf_min0,
-               params->cdmsf_sec0,
-               params->cdmsf_frame0,
-               params->cdmsf_min1,
-               params->cdmsf_sec1,
-               params->cdmsf_frame1));
-
-       outb(params->cdmsf_min0, COMIN_PORT);
-       outb(params->cdmsf_sec0, COMIN_PORT);
-       outb(params->cdmsf_frame0, COMIN_PORT);
-       outb(params->cdmsf_min1, COMIN_PORT);
-       outb(params->cdmsf_sec1, COMIN_PORT);
-       outb(params->cdmsf_frame1, COMIN_PORT);
-       if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
-               return -ERR_IF_CMD_TIMEOUT;
-       ack = inb(DATA_PORT);           /* read command acknowledge */
-       return ack==ST_PA_OK ? 0 : -ack;
-}
-
-
-/* Send parameters for SEEK command. Return <0 indicates error */
-static int send_seek_params(struct cdrom_msf *params)
-{
-       unsigned char ack;
-
-       DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
-               " %02x:%02x:%02x",
-               params->cdmsf_min0,
-               params->cdmsf_sec0,
-               params->cdmsf_frame0));
-
-       outb(params->cdmsf_min0, COMIN_PORT);
-       outb(params->cdmsf_sec0, COMIN_PORT);
-       outb(params->cdmsf_frame0, COMIN_PORT);
-       if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
-               return -ERR_IF_CMD_TIMEOUT;
-       ack = inb(DATA_PORT);           /* read command acknowledge */
-       return ack==ST_PA_OK ? 0 : -ack;
-}
-
-
-/* Wait for command execution status. Choice between busy waiting
-   and sleeping. Return value <0 indicates timeout. */
-static inline int get_exec_status(int busy_waiting)
-{
-       unsigned char exec_status;
-
-       if (busy_waiting
-           ? !flag_low(FL_STEN, BUSY_TIMEOUT)
-           : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
-               return -ERR_IF_CMD_TIMEOUT;
-
-       exec_status = inb(DATA_PORT);
-       DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
-       return exec_status;
-}
-
-
-/* Wait busy for extra byte of data that a command returns.
-   Return value <0 indicates timeout. */
-static inline int get_data(int short_timeout)
-{
-       unsigned char data;
-
-       if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
-               return -ERR_IF_DATA_TIMEOUT;
-
-       data = inb(DATA_PORT);
-       DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
-       return data;
-}
-
-
-/* Returns 0 if failed */
-static int reset_drive(void)
-{
-       unsigned long count = 0;
-       int flags;
-
-       DEBUG((DEBUG_DRIVE_IF, "reset drive"));
-
-       outb(0, RESET_PORT);
-       while (++count < RESET_WAIT)
-               inb(DATA_PORT);
-
-       count = 0;
-       while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
-               if (++count >= BUSY_TIMEOUT)
-                       break;
-
-       DEBUG((DEBUG_DRIVE_IF, "reset %s",
-               flags == FL_RESET ? "succeeded" : "failed"));
-
-       if (flags != FL_RESET)
-               return 0;               /* Reset failed */
-       outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
-       return 1;                       /* Reset succeeded */
-}
-
-
-/* Facilities for asynchronous operation */
-
-/* Read status/data availability flags FL_STEN and FL_DTEN */
-static inline int stdt_flags(void)
-{
-       return inb(STATUS_PORT) & FL_STDT;
-}
-
-
-/* Fetch status that has previously been waited for. <0 means not available */
-static inline int fetch_status(void)
-{
-       unsigned char status;
-
-       if (inb(STATUS_PORT) & FL_STEN)
-               return -ERR_IF_NOSTAT;
-
-       status = inb(DATA_PORT);
-       DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
-       return status;
-}
-
-
-/* Fetch data that has previously been waited for. */
-static inline void fetch_data(char *buf, int n)
-{
-       insb(DATA_PORT, buf, n);
-       DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
-}
-
-
-/* Flush status and data fifos */
-static inline void flush_data(void)
-{
-       while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
-               inb(DATA_PORT);
-       DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
-}
-\f
-/* Command protocol */
-
-
-/* Send a simple command and wait for response. Command codes < COMFETCH
-   are quick response commands */
-static inline int exec_cmd(int cmd)
-{
-       int ack = send_cmd(cmd);
-       if (ack < 0)
-               return ack;
-       return get_exec_status(cmd < COMFETCH);
-}
-
-
-/* Send a command with parameters. Don't wait for the response,
- * which consists of data blocks read from the CD. */
-static inline int exec_read_cmd(int cmd, struct cdrom_msf *params)
-{
-       int ack = send_cmd(cmd);
-       if (ack < 0)
-               return ack;
-       return send_params(params);
-}
-
-
-/* Send a seek command with parameters and wait for response */
-static inline int exec_seek_cmd(int cmd, struct cdrom_msf *params)
-{
-       int ack = send_cmd(cmd);
-       if (ack < 0)
-               return ack;
-       ack = send_seek_params(params);
-       if (ack < 0)
-               return ack;
-       return 0;
-}
-
-
-/* Send a command with parameters and wait for response */
-static inline int exec_long_cmd(int cmd, struct cdrom_msf *params)
-{
-       int ack = exec_read_cmd(cmd, params);
-       if (ack < 0)
-               return ack;
-       return get_exec_status(0);
-}
-\f
-/* Address conversion routines */
-
-
-/* Binary to BCD (2 digits) */
-static inline void single_bin2bcd(u_char *p)
-{
-       DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
-       *p = (*p % 10) | ((*p / 10) << 4);
-}
-
-
-/* Convert entire msf struct */
-static void bin2bcd(struct cdrom_msf *msf)
-{
-       single_bin2bcd(&msf->cdmsf_min0);
-       single_bin2bcd(&msf->cdmsf_sec0);
-       single_bin2bcd(&msf->cdmsf_frame0);
-       single_bin2bcd(&msf->cdmsf_min1);
-       single_bin2bcd(&msf->cdmsf_sec1);
-       single_bin2bcd(&msf->cdmsf_frame1);
-}
-
-
-/* Linear block address to minute, second, frame form */
-#define CD_FPM (CD_SECS * CD_FRAMES)   /* frames per minute */
-
-static void lba2msf(int lba, struct cdrom_msf *msf)
-{
-       DEBUG((DEBUG_CONV, "lba2msf %d", lba));
-       lba += CD_MSF_OFFSET;
-       msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
-       msf->cdmsf_sec0 = lba / CD_FRAMES;
-       msf->cdmsf_frame0 = lba % CD_FRAMES;
-       msf->cdmsf_min1 = 0;
-       msf->cdmsf_sec1 = 0;
-       msf->cdmsf_frame1 = 0;
-       bin2bcd(msf);
-}
-
-
-/* Two BCD digits to binary */
-static inline u_char bcd2bin(u_char bcd)
-{
-       DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
-       return (bcd >> 4) * 10 + (bcd & 0x0f);
-}
-
-
-static void msf2lba(union cdrom_addr *addr)
-{
-       addr->lba = addr->msf.minute * CD_FPM
-                   + addr->msf.second * CD_FRAMES
-                   + addr->msf.frame - CD_MSF_OFFSET;
-}
-
-
-/* Minute, second, frame address BCD to binary or to linear address,
-   depending on MODE */
-static void msf_bcd2bin(union cdrom_addr *addr)
-{
-       addr->msf.minute = bcd2bin(addr->msf.minute);
-       addr->msf.second = bcd2bin(addr->msf.second);
-       addr->msf.frame = bcd2bin(addr->msf.frame);
-}
-\f
-/* High level drive commands */
-
-
-static int audio_status = CDROM_AUDIO_NO_STATUS;
-static char toc_uptodate = 0;
-static char disk_changed = 1;
-
-/* Get drive status, flagging completion of audio play and disk changes. */
-static int drive_status(void)
-{
-       int status;
-
-       status = exec_cmd(COMIOCTLISTAT);
-       DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
-       if (status < 0)
-               return status;
-       if (status == 0xff)     /* No status available */
-               return -ERR_IF_NOSTAT;
-
-       if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
-               (audio_status == CDROM_AUDIO_PLAY)) {
-               audio_status = CDROM_AUDIO_COMPLETED;
-       }
-
-       if (status & ST_DSK_CHG) {
-               toc_uptodate = 0;
-               disk_changed = 1;
-               audio_status = CDROM_AUDIO_NO_STATUS;
-       }
-
-       return status;
-}
-
-
-/* Read the current Q-channel info. Also used for reading the
-   table of contents. qp->cdsc_format must be set on entry to
-   indicate the desired address format */
-static int get_q_channel(struct cdrom_subchnl *qp)
-{
-       int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
-
-       status = drive_status();
-       if (status < 0)
-               return status;
-       qp->cdsc_audiostatus = audio_status;
-
-       status = exec_cmd(COMSUBQ);
-       if (status < 0)
-               return status;
-
-       d1 = get_data(0);
-       if (d1 < 0)
-               return d1;
-       qp->cdsc_adr = d1;
-       qp->cdsc_ctrl = d1 >> 4;
-
-       d2 = get_data(0);
-       if (d2 < 0)
-               return d2;
-       qp->cdsc_trk = bcd2bin(d2);
-
-       d3 = get_data(0);
-       if (d3 < 0)
-               return d3;
-       qp->cdsc_ind = bcd2bin(d3);
-
-       d4 = get_data(0);
-       if (d4 < 0)
-               return d4;
-       qp->cdsc_reladdr.msf.minute = d4;
-
-       d5 = get_data(0);
-       if (d5 < 0)
-               return d5;
-       qp->cdsc_reladdr.msf.second = d5;
-
-       d6 = get_data(0);
-       if (d6 < 0)
-               return d6;
-       qp->cdsc_reladdr.msf.frame = d6;
-
-       d7 = get_data(0);
-       if (d7 < 0)
-               return d7;
-       /* byte not used */
-
-       d8 = get_data(0);
-       if (d8 < 0)
-               return d8;
-       qp->cdsc_absaddr.msf.minute = d8;
-
-       d9 = get_data(0);
-       if (d9 < 0)
-               return d9;
-       qp->cdsc_absaddr.msf.second = d9;
-
-       d10 = get_data(0);
-       if (d10 < 0)
-               return d10;
-       qp->cdsc_absaddr.msf.frame = d10;
-
-       DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
-               d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
-
-       msf_bcd2bin(&qp->cdsc_absaddr);
-       msf_bcd2bin(&qp->cdsc_reladdr);
-       if (qp->cdsc_format == CDROM_LBA) {
-               msf2lba(&qp->cdsc_absaddr);
-               msf2lba(&qp->cdsc_reladdr);
-       }
-
-       return 0;
-}
-\f
-/* Table of contents handling */
-
-
-/* Errors in table of contents */
-#define ERR_TOC_MISSINGINFO    0x120
-#define ERR_TOC_MISSINGENTRY   0x121
-
-
-struct cdrom_disk_info {
-       unsigned char           first;
-       unsigned char           last;
-       struct cdrom_msf0       disk_length;
-       struct cdrom_msf0       first_track;
-       /* Multisession info: */
-       unsigned char           next;
-       struct cdrom_msf0       next_session;
-       struct cdrom_msf0       last_session;
-       unsigned char           multi;
-       unsigned char           xa;
-       unsigned char           audio;
-};
-static struct cdrom_disk_info disk_info;
-
-#define MAX_TRACKS             111
-static struct cdrom_subchnl toc[MAX_TRACKS];
-
-#define QINFO_FIRSTTRACK       100 /* bcd2bin(0xa0) */
-#define QINFO_LASTTRACK                101 /* bcd2bin(0xa1) */
-#define QINFO_DISKLENGTH       102 /* bcd2bin(0xa2) */
-#define QINFO_NEXTSESSION      110 /* bcd2bin(0xb0) */
-
-#define I_FIRSTTRACK   0x01
-#define I_LASTTRACK    0x02
-#define I_DISKLENGTH   0x04
-#define I_NEXTSESSION  0x08
-#define I_ALL  (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
-
-
-#if DEBUG_TOC
-static void toc_debug_info(int i)
-{
-       printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
-               "  %2d:%02d.%02d %2d:%02d.%02d\n",
-               i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
-               toc[i].cdsc_trk, toc[i].cdsc_ind,
-               toc[i].cdsc_reladdr.msf.minute,
-               toc[i].cdsc_reladdr.msf.second,
-               toc[i].cdsc_reladdr.msf.frame,
-               toc[i].cdsc_absaddr.msf.minute,
-               toc[i].cdsc_absaddr.msf.second,
-               toc[i].cdsc_absaddr.msf.frame);
-}
-#endif
-
-
-static int read_toc(void)
-{
-       int status, limit, count;
-       unsigned char got_info = 0;
-       struct cdrom_subchnl q_info;
-#if DEBUG_TOC
-       int i;
-#endif
-
-       DEBUG((DEBUG_TOC, "starting read_toc"));
-
-       count = 0;
-       for (limit = 60; limit > 0; limit--) {
-               int index;
-
-               q_info.cdsc_format = CDROM_MSF;
-               status = get_q_channel(&q_info);
-               if (status < 0)
-                       return status;
-
-               index = q_info.cdsc_ind;
-               if (index > 0 && index < MAX_TRACKS
-                   && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
-                       toc[index] = q_info;
-                       DEBUG((DEBUG_TOC, "got %d", index));
-                       if (index < 100)
-                               count++;
-
-                       switch (q_info.cdsc_ind) {
-                       case QINFO_FIRSTTRACK:
-                               got_info |= I_FIRSTTRACK;
-                               break;
-                       case QINFO_LASTTRACK:
-                               got_info |= I_LASTTRACK;
-                               break;
-                       case QINFO_DISKLENGTH:
-                               got_info |= I_DISKLENGTH;
-                               break;
-                       case QINFO_NEXTSESSION:
-                               got_info |= I_NEXTSESSION;
-                               break;
-                       }
-               }
-
-               if ((got_info & I_ALL) == I_ALL
-                   && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
-                      >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
-                       break;
-       }
-
-       /* Construct disk_info from TOC */
-       if (disk_info.first == 0) {
-               disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
-               disk_info.first_track.minute =
-                       toc[disk_info.first].cdsc_absaddr.msf.minute;
-               disk_info.first_track.second =
-                       toc[disk_info.first].cdsc_absaddr.msf.second;
-               disk_info.first_track.frame =
-                       toc[disk_info.first].cdsc_absaddr.msf.frame;
-       }
-       disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
-       disk_info.disk_length.minute =
-                       toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
-       disk_info.disk_length.second =
-                       toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
-       disk_info.disk_length.frame =
-                       toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
-       disk_info.next_session.minute =
-                       toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
-       disk_info.next_session.second =
-                       toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
-       disk_info.next_session.frame =
-                       toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
-       disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
-       disk_info.last_session.minute =
-                       toc[disk_info.next].cdsc_absaddr.msf.minute;
-       disk_info.last_session.second =
-                       toc[disk_info.next].cdsc_absaddr.msf.second;
-       disk_info.last_session.frame =
-                       toc[disk_info.next].cdsc_absaddr.msf.frame;
-       toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
-                       disk_info.disk_length.minute;
-       toc[disk_info.last + 1].cdsc_absaddr.msf.second =
-                       disk_info.disk_length.second;
-       toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
-                       disk_info.disk_length.frame;
-#if DEBUG_TOC
-       for (i = 1; i <= disk_info.last + 1; i++)
-               toc_debug_info(i);
-       toc_debug_info(QINFO_FIRSTTRACK);
-       toc_debug_info(QINFO_LASTTRACK);
-       toc_debug_info(QINFO_DISKLENGTH);
-       toc_debug_info(QINFO_NEXTSESSION);
-#endif
-
-       DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
-               got_info, count));
-       if ((got_info & I_ALL) != I_ALL
-           || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
-              < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
-               return -ERR_TOC_MISSINGINFO;
-       return 0;
-}
-
-
-#ifdef MULTISESSION
-static int get_multi_disk_info(void)
-{
-       int sessions, status;
-       struct cdrom_msf multi_index;
-
-
-       for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
-               int count;
-
-               for (count = 100; count < MAX_TRACKS; count++) 
-                       toc[count].cdsc_ind = 0;
-
-               multi_index.cdmsf_min0 = disk_info.next_session.minute;
-               multi_index.cdmsf_sec0 = disk_info.next_session.second;
-               multi_index.cdmsf_frame0 = disk_info.next_session.frame;
-               if (multi_index.cdmsf_sec0 >= 20)
-                       multi_index.cdmsf_sec0 -= 20;
-               else {
-                       multi_index.cdmsf_sec0 += 40;
-                       multi_index.cdmsf_min0--;
-               }
-               DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
-                       multi_index.cdmsf_min0,
-                       multi_index.cdmsf_sec0,
-                       multi_index.cdmsf_frame0));
-               bin2bcd(&multi_index);
-               multi_index.cdmsf_min1 = 0;
-               multi_index.cdmsf_sec1 = 0;
-               multi_index.cdmsf_frame1 = 1;
-
-               status = exec_read_cmd(COMREAD, &multi_index);
-               if (status < 0) {
-                       DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
-                               -status));
-                       break;
-               }
-               status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
-                               0 : -ERR_TOC_MISSINGINFO;
-               flush_data();
-               if (status < 0) {
-                       DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
-                       break;
-               }
-
-               status = read_toc();
-               if (status < 0) {
-                       DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
-                       break;
-               }
-
-               disk_info.multi = 1;
-       }
-
-       exec_cmd(COMSTOP);
-
-       if (status < 0)
-               return -EIO;
-       return 0;
-}
-#endif /* MULTISESSION */
-
-
-static int update_toc(void)
-{
-       int status, count;
-
-       if (toc_uptodate)
-               return 0;
-
-       DEBUG((DEBUG_TOC, "starting update_toc"));
-
-       disk_info.first = 0;
-       for (count = 0; count < MAX_TRACKS; count++) 
-               toc[count].cdsc_ind = 0;
-
-       status = exec_cmd(COMLEADIN);
-       if (status < 0)
-               return -EIO;
-
-       status = read_toc();
-       if (status < 0) {
-               DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
-               return -EIO;
-       }
-
-        /* Audio disk detection. Look at first track. */
-       disk_info.audio =
-               (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
-
-       /* XA detection */
-       disk_info.xa = drive_status() & ST_MODE2TRACK;
-
-       /* Multisession detection: if we want this, define MULTISESSION */
-       disk_info.multi = 0;
-#ifdef MULTISESSION
-       if (disk_info.xa)
-               get_multi_disk_info();  /* Here disk_info.multi is set */
-#endif /* MULTISESSION */
-       if (disk_info.multi)
-               printk(KERN_WARNING "optcd: Multisession support experimental, "
-                       "see Documentation/cdrom/optcd\n");
-
-       DEBUG((DEBUG_TOC, "exiting update_toc"));
-
-       toc_uptodate = 1;
-       return 0;
-}
-\f
-/* Request handling */
-
-static int current_valid(void)
-{
-        return CURRENT &&
-               CURRENT->cmd == READ &&
-               CURRENT->sector != -1;
-}
-
-/* Buffers for block size conversion. */
-#define NOBUF          -1
-
-static char buf[CD_FRAMESIZE * N_BUFS];
-static volatile int buf_bn[N_BUFS], next_bn;
-static volatile int buf_in = 0, buf_out = NOBUF;
-
-static inline void opt_invalidate_buffers(void)
-{
-       int i;
-
-       DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
-
-       for (i = 0; i < N_BUFS; i++)
-               buf_bn[i] = NOBUF;
-       buf_out = NOBUF;
-}
-
-
-/* Take care of the different block sizes between cdrom and Linux.
-   When Linux gets variable block sizes this will probably go away. */
-static void transfer(void)
-{
-#if DEBUG_BUFFERS | DEBUG_REQUEST
-       printk(KERN_DEBUG "optcd: executing transfer\n");
-#endif
-
-       if (!current_valid())
-               return;
-       while (CURRENT -> nr_sectors) {
-               int bn = CURRENT -> sector / 4;
-               int i, offs, nr_sectors;
-               for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
-
-               DEBUG((DEBUG_REQUEST, "found %d", i));
-
-               if (i >= N_BUFS) {
-                       buf_out = NOBUF;
-                       break;
-               }
-
-               offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
-               nr_sectors = 4 - (CURRENT -> sector & 3);
-
-               if (buf_out != i) {
-                       buf_out = i;
-                       if (buf_bn[i] != bn) {
-                               buf_out = NOBUF;
-                               continue;
-                       }
-               }
-
-               if (nr_sectors > CURRENT -> nr_sectors)
-                       nr_sectors = CURRENT -> nr_sectors;
-               memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
-               CURRENT -> nr_sectors -= nr_sectors;
-               CURRENT -> sector += nr_sectors;
-               CURRENT -> buffer += nr_sectors * 512;
-       }
-}
-
-
-/* State machine for reading disk blocks */
-
-enum state_e {
-       S_IDLE,         /* 0 */
-       S_START,        /* 1 */
-       S_READ,         /* 2 */
-       S_DATA,         /* 3 */
-       S_STOP,         /* 4 */
-       S_STOPPING      /* 5 */
-};
-
-static volatile enum state_e state = S_IDLE;
-#if DEBUG_STATE
-static volatile enum state_e state_old = S_STOP;
-static volatile int flags_old = 0;
-static volatile long state_n = 0;
-#endif
-
-
-/* Used as mutex to keep do_optcd_request (and other processes calling
-   ioctl) out while some process is inside a VFS call.
-   Reverse is accomplished by checking if state = S_IDLE upon entry
-   of opt_ioctl and opt_media_change. */
-static int in_vfs = 0;
-
-
-static volatile int transfer_is_active = 0;
-static volatile int error = 0; /* %% do something with this?? */
-static int tries;              /* ibid?? */
-static int timeout = 0;
-
-static void poll(unsigned long data);
-static struct timer_list req_timer = {.function = poll};
-
-
-static void poll(unsigned long data)
-{
-       static volatile int read_count = 1;
-       int flags;
-       int loop_again = 1;
-       int status = 0;
-       int skip = 0;
-
-       if (error) {
-               printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);
-               opt_invalidate_buffers();
-               if (!tries--) {
-                       printk(KERN_ERR "optcd: read block %d failed;"
-                               " Giving up\n", next_bn);
-                       if (transfer_is_active)
-                               loop_again = 0;
-                       if (current_valid())
-                               end_request(CURRENT, 0);
-                       tries = 5;
-               }
-               error = 0;
-               state = S_STOP;
-       }
-
-       while (loop_again)
-       {
-               loop_again = 0; /* each case must flip this back to 1 if we want
-                                to come back up here */
-
-#if DEBUG_STATE
-               if (state == state_old)
-                       state_n++;
-               else {
-                       state_old = state;
-                       if (++state_n > 1)
-                               printk(KERN_DEBUG "optcd: %ld times "
-                                       "in previous state\n", state_n);
-                       printk(KERN_DEBUG "optcd: state %d\n", state);
-                       state_n = 0;
-               }
-#endif
-
-               switch (state) {
-               case S_IDLE:
-                       return;
-               case S_START:
-                       if (in_vfs)
-                               break;
-                       if (send_cmd(COMDRVST)) {
-                               state = S_IDLE;
-                               while (current_valid())
-                                       end_request(CURRENT, 0);
-                               return;
-                       }
-                       state = S_READ;
-                       timeout = READ_TIMEOUT;
-                       break;
-               case S_READ: {
-                       struct cdrom_msf msf;
-                       if (!skip) {
-                               status = fetch_status();
-                               if (status < 0)
-                                       break;
-                               if (status & ST_DSK_CHG) {
-                                       toc_uptodate = 0;
-                                       opt_invalidate_buffers();
-                               }
-                       }
-                       skip = 0;
-                       if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
-                               toc_uptodate = 0;
-                               opt_invalidate_buffers();
-                               printk(KERN_WARNING "optcd: %s\n",
-                                       (status & ST_DOOR_OPEN)
-                                       ? "door open"
-                                       : "disk removed");
-                               state = S_IDLE;
-                               while (current_valid())
-                                       end_request(CURRENT, 0);
-                               return;
-                       }
-                       if (!current_valid()) {
-                               state = S_STOP;
-                               loop_again = 1;
-                               break;
-                       }
-                       next_bn = CURRENT -> sector / 4;
-                       lba2msf(next_bn, &msf);
-                       read_count = N_BUFS;
-                       msf.cdmsf_frame1 = read_count; /* Not BCD! */
-
-                       DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
-                               msf.cdmsf_min0,
-                               msf.cdmsf_sec0,
-                               msf.cdmsf_frame0,
-                               msf.cdmsf_min1,
-                               msf.cdmsf_sec1,
-                               msf.cdmsf_frame1));
-                       DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
-                               " buf_out:%d buf_bn:%d",
-                               next_bn,
-                               buf_in,
-                               buf_out,
-                               buf_bn[buf_in]));
-
-                       exec_read_cmd(COMREAD, &msf);
-                       state = S_DATA;
-                       timeout = READ_TIMEOUT;
-                       break;
-               }
-               case S_DATA:
-                       flags = stdt_flags() & (FL_STEN|FL_DTEN);
-
-#if DEBUG_STATE
-                       if (flags != flags_old) {
-                               flags_old = flags;
-                               printk(KERN_DEBUG "optcd: flags:%x\n", flags);
-                       }
-                       if (flags == FL_STEN)
-                               printk(KERN_DEBUG "timeout cnt: %d\n", timeout);
-#endif
-
-                       switch (flags) {
-                       case FL_DTEN:           /* only STEN low */
-                               if (!tries--) {
-                                       printk(KERN_ERR
-                                               "optcd: read block %d failed; "
-                                               "Giving up\n", next_bn);
-                                       if (transfer_is_active) {
-                                               tries = 0;
-                                               break;
-                                       }
-                                       if (current_valid())
-                                               end_request(CURRENT, 0);
-                                       tries = 5;
-                               }
-                               state = S_START;
-                               timeout = READ_TIMEOUT;
-                               loop_again = 1;
-                       case (FL_STEN|FL_DTEN):  /* both high */
-                               break;
-                       default:        /* DTEN low */
-                               tries = 5;
-                               if (!current_valid() && buf_in == buf_out) {
-                                       state = S_STOP;
-                                       loop_again = 1;
-                                       break;
-                               }
-                               if (read_count<=0)
-                                       printk(KERN_WARNING
-                                               "optcd: warning - try to read"
-                                               " 0 frames\n");
-                               while (read_count) {
-                                       buf_bn[buf_in] = NOBUF;
-                                       if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
-                                       /* should be no waiting here!?? */
-                                               printk(KERN_ERR
-                                                  "read_count:%d "
-                                                  "CURRENT->nr_sectors:%ld "
-                                                  "buf_in:%d\n",
-                                                       read_count,
-                                                       CURRENT->nr_sectors,
-                                                       buf_in);
-                                               printk(KERN_ERR
-                                                       "transfer active: %x\n",
-                                                       transfer_is_active);
-                                               read_count = 0;
-                                               state = S_STOP;
-                                               loop_again = 1;
-                                               end_request(CURRENT, 0);
-                                               break;
-                                       }
-                                       fetch_data(buf+
-                                           CD_FRAMESIZE*buf_in,
-                                           CD_FRAMESIZE);
-                                       read_count--;
-
-                                       DEBUG((DEBUG_REQUEST,
-                                               "S_DATA; ---I've read data- "
-                                               "read_count: %d",
-                                               read_count));
-                                       DEBUG((DEBUG_REQUEST,
-                                               "next_bn:%d  buf_in:%d "
-                                               "buf_out:%d  buf_bn:%d",
-                                               next_bn,
-                                               buf_in,
-                                               buf_out,
-                                               buf_bn[buf_in]));
-
-                                       buf_bn[buf_in] = next_bn++;
-                                       if (buf_out == NOBUF)
-                                               buf_out = buf_in;
-                                       buf_in = buf_in + 1 ==
-                                               N_BUFS ? 0 : buf_in + 1;
-                               }
-                               if (!transfer_is_active) {
-                                       while (current_valid()) {
-                                               transfer();
-                                               if (CURRENT -> nr_sectors == 0)
-                                                       end_request(CURRENT, 1);
-                                               else
-                                                       break;
-                                       }
-                               }
-
-                               if (current_valid()
-                                   && (CURRENT -> sector / 4 < next_bn ||
-                                   CURRENT -> sector / 4 >
-                                    next_bn + N_BUFS)) {
-                                       state = S_STOP;
-                                       loop_again = 1;
-                                       break;
-                               }
-                               timeout = READ_TIMEOUT;
-                               if (read_count == 0) {
-                                       state = S_STOP;
-                                       loop_again = 1;
-                                       break;
-                               }
-                       }
-                       break;
-               case S_STOP:
-                       if (read_count != 0)
-                               printk(KERN_ERR
-                                       "optcd: discard data=%x frames\n",
-                                       read_count);
-                       flush_data();
-                       if (send_cmd(COMDRVST)) {
-                               state = S_IDLE;
-                               while (current_valid())
-                                       end_request(CURRENT, 0);
-                               return;
-                       }
-                       state = S_STOPPING;
-                       timeout = STOP_TIMEOUT;
-                       break;
-               case S_STOPPING:
-                       status = fetch_status();
-                       if (status < 0 && timeout)
-                                       break;
-                       if ((status >= 0) && (status & ST_DSK_CHG)) {
-                               toc_uptodate = 0;
-                               opt_invalidate_buffers();
-                       }
-                       if (current_valid()) {
-                               if (status >= 0) {
-                                       state = S_READ;
-                                       loop_again = 1;
-                                       skip = 1;
-                                       break;
-                               } else {
-                                       state = S_START;
-                                       timeout = 1;
-                               }
-                       } else {
-                               state = S_IDLE;
-                               return;
-                       }
-                       break;
-               default:
-                       printk(KERN_ERR "optcd: invalid state %d\n", state);
-                       return;
-               } /* case */
-       } /* while */
-
-       if (!timeout--) {
-               printk(KERN_ERR "optcd: timeout in state %d\n", state);
-               state = S_STOP;
-               if (exec_cmd(COMSTOP) < 0) {
-                       state = S_IDLE;
-                       while (current_valid())
-                               end_request(CURRENT, 0);
-                       return;
-               }
-       }
-
-       mod_timer(&req_timer, jiffies + HZ/100);
-}
-
-
-static void do_optcd_request(request_queue_t * q)
-{
-       DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
-              CURRENT -> sector, CURRENT -> nr_sectors));
-
-       if (disk_info.audio) {
-               printk(KERN_WARNING "optcd: tried to mount an Audio CD\n");
-               end_request(CURRENT, 0);
-               return;
-       }
-
-       transfer_is_active = 1;
-       while (current_valid()) {
-               transfer();     /* First try to transfer block from buffers */
-               if (CURRENT -> nr_sectors == 0) {
-                       end_request(CURRENT, 1);
-               } else {        /* Want to read a block not in buffer */
-                       buf_out = NOBUF;
-                       if (state == S_IDLE) {
-                               /* %% Should this block the request queue?? */
-                               if (update_toc() < 0) {
-                                       while (current_valid())
-                                               end_request(CURRENT, 0);
-                                       break;
-                               }
-                               /* Start state machine */
-                               state = S_START;
-                               timeout = READ_TIMEOUT;
-                               tries = 5;
-                               /* %% why not start right away?? */
-                               mod_timer(&req_timer, jiffies + HZ/100);
-                       }
-                       break;
-               }
-       }
-       transfer_is_active = 0;
-
-       DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
-              next_bn, buf_in, buf_out, buf_bn[buf_in]));
-       DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
-}
-\f
-/* IOCTLs */
-
-
-static char auto_eject = 0;
-
-static int cdrompause(void)
-{
-       int status;
-
-       if (audio_status != CDROM_AUDIO_PLAY)
-               return -EINVAL;
-
-       status = exec_cmd(COMPAUSEON);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
-               return -EIO;
-       }
-       audio_status = CDROM_AUDIO_PAUSED;
-       return 0;
-}
-
-
-static int cdromresume(void)
-{
-       int status;
-
-       if (audio_status != CDROM_AUDIO_PAUSED)
-               return -EINVAL;
-
-       status = exec_cmd(COMPAUSEOFF);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
-               audio_status = CDROM_AUDIO_ERROR;
-               return -EIO;
-       }
-       audio_status = CDROM_AUDIO_PLAY;
-       return 0;
-}
-
-
-static int cdromplaymsf(void __user *arg)
-{
-       int status;
-       struct cdrom_msf msf;
-
-       if (copy_from_user(&msf, arg, sizeof msf))
-               return -EFAULT;
-
-       bin2bcd(&msf);
-       status = exec_long_cmd(COMPLAY, &msf);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
-               audio_status = CDROM_AUDIO_ERROR;
-               return -EIO;
-       }
-
-       audio_status = CDROM_AUDIO_PLAY;
-       return 0;
-}
-
-
-static int cdromplaytrkind(void __user *arg)
-{
-       int status;
-       struct cdrom_ti ti;
-       struct cdrom_msf msf;
-
-       if (copy_from_user(&ti, arg, sizeof ti))
-               return -EFAULT;
-
-       if (ti.cdti_trk0 < disk_info.first
-           || ti.cdti_trk0 > disk_info.last
-           || ti.cdti_trk1 < ti.cdti_trk0)
-               return -EINVAL;
-       if (ti.cdti_trk1 > disk_info.last)
-               ti.cdti_trk1 = disk_info.last;
-
-       msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
-       msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
-       msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
-       msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
-       msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
-       msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
-
-       DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
-               msf.cdmsf_min0,
-               msf.cdmsf_sec0,
-               msf.cdmsf_frame0,
-               msf.cdmsf_min1,
-               msf.cdmsf_sec1,
-               msf.cdmsf_frame1));
-
-       bin2bcd(&msf);
-       status = exec_long_cmd(COMPLAY, &msf);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
-               audio_status = CDROM_AUDIO_ERROR;
-               return -EIO;
-       }
-
-       audio_status = CDROM_AUDIO_PLAY;
-       return 0;
-}
-
-
-static int cdromreadtochdr(void __user *arg)
-{
-       struct cdrom_tochdr tochdr;
-
-       tochdr.cdth_trk0 = disk_info.first;
-       tochdr.cdth_trk1 = disk_info.last;
-
-       return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0;
-}
-
-
-static int cdromreadtocentry(void __user *arg)
-{
-       struct cdrom_tocentry entry;
-       struct cdrom_subchnl *tocptr;
-
-       if (copy_from_user(&entry, arg, sizeof entry))
-               return -EFAULT;
-
-       if (entry.cdte_track == CDROM_LEADOUT)
-               tocptr = &toc[disk_info.last + 1];
-       else if (entry.cdte_track > disk_info.last
-               || entry.cdte_track < disk_info.first)
-               return -EINVAL;
-       else
-               tocptr = &toc[entry.cdte_track];
-
-       entry.cdte_adr = tocptr->cdsc_adr;
-       entry.cdte_ctrl = tocptr->cdsc_ctrl;
-       entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
-       entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
-       entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
-       /* %% What should go into entry.cdte_datamode? */
-
-       if (entry.cdte_format == CDROM_LBA)
-               msf2lba(&entry.cdte_addr);
-       else if (entry.cdte_format != CDROM_MSF)
-               return -EINVAL;
-
-       return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0;
-}
-
-
-static int cdromvolctrl(void __user *arg)
-{
-       int status;
-       struct cdrom_volctrl volctrl;
-       struct cdrom_msf msf;
-
-       if (copy_from_user(&volctrl, arg, sizeof volctrl))
-               return -EFAULT;
-
-       msf.cdmsf_min0 = 0x10;
-       msf.cdmsf_sec0 = 0x32;
-       msf.cdmsf_frame0 = volctrl.channel0;
-       msf.cdmsf_min1 = volctrl.channel1;
-       msf.cdmsf_sec1 = volctrl.channel2;
-       msf.cdmsf_frame1 = volctrl.channel3;
-
-       status = exec_long_cmd(COMCHCTRL, &msf);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
-               return -EIO;
-       }
-       return 0;
-}
-
-
-static int cdromsubchnl(void __user *arg)
-{
-       int status;
-       struct cdrom_subchnl subchnl;
-
-       if (copy_from_user(&subchnl, arg, sizeof subchnl))
-               return -EFAULT;
-
-       if (subchnl.cdsc_format != CDROM_LBA
-           && subchnl.cdsc_format != CDROM_MSF)
-               return -EINVAL;
-
-       status = get_q_channel(&subchnl);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
-               return -EIO;
-       }
-
-       if (copy_to_user(arg, &subchnl, sizeof subchnl))
-               return -EFAULT;
-       return 0;
-}
-
-
-static struct gendisk *optcd_disk;
-
-
-static int cdromread(void __user *arg, int blocksize, int cmd)
-{
-       int status;
-       struct cdrom_msf msf;
-
-       if (copy_from_user(&msf, arg, sizeof msf))
-               return -EFAULT;
-
-       bin2bcd(&msf);
-       msf.cdmsf_min1 = 0;
-       msf.cdmsf_sec1 = 0;
-       msf.cdmsf_frame1 = 1;   /* read only one frame */
-       status = exec_read_cmd(cmd, &msf);
-
-       DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
-
-       if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
-               return -EIO;
-
-       fetch_data(optcd_disk->private_data, blocksize);
-
-       if (copy_to_user(arg, optcd_disk->private_data, blocksize))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int cdromseek(void __user *arg)
-{
-       int status;
-       struct cdrom_msf msf;
-
-       if (copy_from_user(&msf, arg, sizeof msf))
-               return -EFAULT;
-
-       bin2bcd(&msf);
-       status = exec_seek_cmd(COMSEEK, &msf);
-
-       DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
-
-       if (status < 0)
-               return -EIO;
-       return 0;
-}
-
-
-#ifdef MULTISESSION
-static int cdrommultisession(void __user *arg)
-{
-       struct cdrom_multisession ms;
-
-       if (copy_from_user(&ms, arg, sizeof ms))
-               return -EFAULT;
-
-       ms.addr.msf.minute = disk_info.last_session.minute;
-       ms.addr.msf.second = disk_info.last_session.second;
-       ms.addr.msf.frame = disk_info.last_session.frame;
-
-       if (ms.addr_format != CDROM_LBA
-          && ms.addr_format != CDROM_MSF)
-               return -EINVAL;
-       if (ms.addr_format == CDROM_LBA)
-               msf2lba(&ms.addr);
-
-       ms.xa_flag = disk_info.xa;
-
-       if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession)))
-               return -EFAULT;
-
-#if DEBUG_MULTIS
-       if (ms.addr_format == CDROM_MSF)
-                       printk(KERN_DEBUG
-                       "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
-                       ms.xa_flag,
-                       ms.addr.msf.minute,
-                       ms.addr.msf.second,
-                       ms.addr.msf.frame);
-       else
-               printk(KERN_DEBUG
-                   "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
-                       ms.xa_flag,
-                       ms.addr.lba,
-                       disk_info.last_session.minute,
-                       disk_info.last_session.second,
-                       disk_info.last_session.frame);
-#endif /* DEBUG_MULTIS */
-
-       return 0;
-}
-#endif /* MULTISESSION */
-
-
-static int cdromreset(void)
-{
-       if (state != S_IDLE) {
-               error = 1;
-               tries = 0;
-       }
-
-       toc_uptodate = 0;
-       disk_changed = 1;
-       opt_invalidate_buffers();
-       audio_status = CDROM_AUDIO_NO_STATUS;
-
-       if (!reset_drive())
-               return -EIO;
-       return 0;
-}
-\f
-/* VFS calls */
-
-
-static int opt_ioctl(struct inode *ip, struct file *fp,
-                     unsigned int cmd, unsigned long arg)
-{
-       int status, err, retval = 0;
-       void __user *argp = (void __user *)arg;
-
-       DEBUG((DEBUG_VFS, "starting opt_ioctl"));
-
-       if (!ip)
-               return -EINVAL;
-
-       if (cmd == CDROMRESET)
-               return cdromreset();
-
-       /* is do_optcd_request or another ioctl busy? */
-       if (state != S_IDLE || in_vfs)
-               return -EBUSY;
-
-       in_vfs = 1;
-
-       status = drive_status();
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
-               in_vfs = 0;
-               return -EIO;
-       }
-
-       if (status & ST_DOOR_OPEN)
-               switch (cmd) {  /* Actions that can be taken with door open */
-               case CDROMCLOSETRAY:
-                       /* We do this before trying to read the toc. */
-                       err = exec_cmd(COMCLOSE);
-                       if (err < 0) {
-                               DEBUG((DEBUG_VFS,
-                                      "exec_cmd COMCLOSE: %02x", -err));
-                               in_vfs = 0;
-                               return -EIO;
-                       }
-                       break;
-               default:        in_vfs = 0;
-                               return -EBUSY;
-               }
-
-       err = update_toc();
-       if (err < 0) {
-               DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
-               in_vfs = 0;
-               return -EIO;
-       }
-
-       DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
-
-       switch (cmd) {
-       case CDROMPAUSE:        retval = cdrompause(); break;
-       case CDROMRESUME:       retval = cdromresume(); break;
-       case CDROMPLAYMSF:      retval = cdromplaymsf(argp); break;
-       case CDROMPLAYTRKIND:   retval = cdromplaytrkind(argp); break;
-       case CDROMREADTOCHDR:   retval = cdromreadtochdr(argp); break;
-       case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break;
-
-       case CDROMSTOP:         err = exec_cmd(COMSTOP);
-                               if (err < 0) {
-                                       DEBUG((DEBUG_VFS,
-                                               "exec_cmd COMSTOP: %02x",
-                                               -err));
-                                       retval = -EIO;
-                               } else
-                                       audio_status = CDROM_AUDIO_NO_STATUS;
-                               break;
-       case CDROMSTART:        break;  /* This is a no-op */
-       case CDROMEJECT:        err = exec_cmd(COMUNLOCK);
-                               if (err < 0) {
-                                       DEBUG((DEBUG_VFS,
-                                               "exec_cmd COMUNLOCK: %02x",
-                                               -err));
-                                       retval = -EIO;
-                                       break;
-                               }
-                               err = exec_cmd(COMOPEN);
-                               if (err < 0) {
-                                       DEBUG((DEBUG_VFS,
-                                               "exec_cmd COMOPEN: %02x",
-                                               -err));
-                                       retval = -EIO;
-                               }
-                               break;
-
-       case CDROMVOLCTRL:      retval = cdromvolctrl(argp); break;
-       case CDROMSUBCHNL:      retval = cdromsubchnl(argp); break;
-
-       /* The drive detects the mode and automatically delivers the
-          correct 2048 bytes, so we don't need these IOCTLs */
-       case CDROMREADMODE2:    retval = -EINVAL; break;
-       case CDROMREADMODE1:    retval = -EINVAL; break;
-
-       /* Drive doesn't support reading audio */
-       case CDROMREADAUDIO:    retval = -EINVAL; break;
-
-       case CDROMEJECT_SW:     auto_eject = (char) arg;
-                               break;
-
-#ifdef MULTISESSION
-       case CDROMMULTISESSION: retval = cdrommultisession(argp); break;
-#endif
-
-       case CDROM_GET_MCN:     retval = -EINVAL; break; /* not implemented */
-       case CDROMVOLREAD:      retval = -EINVAL; break; /* not implemented */
-
-       case CDROMREADRAW:
-                       /* this drive delivers 2340 bytes in raw mode */
-                       retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW);
-                       break;
-       case CDROMREADCOOKED:
-                       retval = cdromread(argp, CD_FRAMESIZE, COMREAD);
-                       break;
-       case CDROMREADALL:
-                       retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL);
-                       break;
-
-       case CDROMSEEK:         retval = cdromseek(argp); break;
-       case CDROMPLAYBLK:      retval = -EINVAL; break; /* not implemented */
-       case CDROMCLOSETRAY:    break;  /* The action was taken earlier */
-       default:                retval = -EINVAL;
-       }
-       in_vfs = 0;
-       return retval;
-}
-
-
-static int open_count = 0;
-
-/* Open device special file; check that a disk is in. */
-static int opt_open(struct inode *ip, struct file *fp)
-{
-       DEBUG((DEBUG_VFS, "starting opt_open"));
-
-       if (!open_count && state == S_IDLE) {
-               int status;
-               char *buf;
-
-               buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL);
-               if (!buf) {
-                       printk(KERN_INFO "optcd: cannot allocate read buffer\n");
-                       return -ENOMEM;
-               }
-               optcd_disk->private_data = buf;         /* save read buffer */
-
-               toc_uptodate = 0;
-               opt_invalidate_buffers();
-
-               status = exec_cmd(COMCLOSE);    /* close door */
-               if (status < 0) {
-                       DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
-               }
-
-               status = drive_status();
-               if (status < 0) {
-                       DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
-                       goto err_out;
-               }
-               DEBUG((DEBUG_VFS, "status: %02x", status));
-               if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
-                       printk(KERN_INFO "optcd: no disk or door open\n");
-                       goto err_out;
-               }
-               status = exec_cmd(COMLOCK);             /* Lock door */
-               if (status < 0) {
-                       DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
-               }
-               status = update_toc();  /* Read table of contents */
-               if (status < 0) {
-                       DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
-                       status = exec_cmd(COMUNLOCK);   /* Unlock door */
-                       if (status < 0) {
-                               DEBUG((DEBUG_VFS,
-                                      "exec_cmd COMUNLOCK: %02x", -status));
-                       }
-                       goto err_out;
-               }
-               open_count++;
-       }
-
-       DEBUG((DEBUG_VFS, "exiting opt_open"));
-
-       return 0;
-
-err_out:
-       return -EIO;
-}
-
-
-/* Release device special file; flush all blocks from the buffer cache */
-static int opt_release(struct inode *ip, struct file *fp)
-{
-       int status;
-
-       DEBUG((DEBUG_VFS, "executing opt_release"));
-       DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n",
-               ip, ip->i_bdev->bd_disk->disk_name, fp));
-
-       if (!--open_count) {
-               toc_uptodate = 0;
-               opt_invalidate_buffers();
-               status = exec_cmd(COMUNLOCK);   /* Unlock door */
-               if (status < 0) {
-                       DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
-               }
-               if (auto_eject) {
-                       status = exec_cmd(COMOPEN);
-                       DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
-               }
-               kfree(optcd_disk->private_data);
-               del_timer(&delay_timer);
-               del_timer(&req_timer);
-       }
-       return 0;
-}
-
-
-/* Check if disk has been changed */
-static int opt_media_change(struct gendisk *disk)
-{
-       DEBUG((DEBUG_VFS, "executing opt_media_change"));
-       DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n",
-                       disk->disk_name, disk_changed));
-
-       if (disk_changed) {
-               disk_changed = 0;
-               return 1;
-       }
-       return 0;
-}
-\f
-/* Driver initialisation */
-
-
-/* Returns 1 if a drive is detected with a version string
-   starting with "DOLPHIN". Otherwise 0. */
-static int __init version_ok(void)
-{
-       char devname[100];
-       int count, i, ch, status;
-
-       status = exec_cmd(COMVERSION);
-       if (status < 0) {
-               DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
-               return 0;
-       }
-       if ((count = get_data(1)) < 0) {
-               DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
-               return 0;
-       }
-       for (i = 0, ch = -1; count > 0; count--) {
-               if ((ch = get_data(1)) < 0) {
-                       DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
-                       break;
-               }
-               if (i < 99)
-                       devname[i++] = ch;
-       }
-       devname[i] = '\0';
-       if (ch < 0)
-               return 0;
-
-       printk(KERN_INFO "optcd: Device %s detected\n", devname);
-       return ((devname[0] == 'D')
-            && (devname[1] == 'O')
-            && (devname[2] == 'L')
-            && (devname[3] == 'P')
-            && (devname[4] == 'H')
-            && (devname[5] == 'I')
-            && (devname[6] == 'N'));
-}
-
-
-static struct block_device_operations opt_fops = {
-       .owner          = THIS_MODULE,
-       .open           = opt_open,
-       .release        = opt_release,
-       .ioctl          = opt_ioctl,
-       .media_changed  = opt_media_change,
-};
-
-#ifndef MODULE
-/* Get kernel parameter when used as a kernel driver */
-static int optcd_setup(char *str)
-{
-       int ints[4];
-       (void)get_options(str, ARRAY_SIZE(ints), ints);
-       
-       if (ints[0] > 0)
-               optcd_port = ints[1];
-
-       return 1;
-}
-
-__setup("optcd=", optcd_setup);
-
-#endif /* MODULE */
-
-/* Test for presence of drive and initialize it. Called at boot time
-   or during module initialisation. */
-static int __init optcd_init(void)
-{
-       int status;
-
-       if (optcd_port <= 0) {
-               printk(KERN_INFO
-                       "optcd: no Optics Storage CDROM Initialization\n");
-               return -EIO;
-       }
-       optcd_disk = alloc_disk(1);
-       if (!optcd_disk) {
-               printk(KERN_ERR "optcd: can't allocate disk\n");
-               return -ENOMEM;
-       }
-       optcd_disk->major = MAJOR_NR;
-       optcd_disk->first_minor = 0;
-       optcd_disk->fops = &opt_fops;
-       sprintf(optcd_disk->disk_name, "optcd");
-
-       if (!request_region(optcd_port, 4, "optcd")) {
-               printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
-                       optcd_port);
-               put_disk(optcd_disk);
-               return -EIO;
-       }
-
-       if (!reset_drive()) {
-               printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
-               release_region(optcd_port, 4);
-               put_disk(optcd_disk);
-               return -EIO;
-       }
-       if (!version_ok()) {
-               printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
-               release_region(optcd_port, 4);
-               put_disk(optcd_disk);
-               return -EIO;
-       }
-       status = exec_cmd(COMINITDOUBLE);
-       if (status < 0) {
-               printk(KERN_ERR "optcd: cannot init double speed mode\n");
-               release_region(optcd_port, 4);
-               DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
-               put_disk(optcd_disk);
-               return -EIO;
-       }
-       if (register_blkdev(MAJOR_NR, "optcd")) {
-               release_region(optcd_port, 4);
-               put_disk(optcd_disk);
-               return -EIO;
-       }
-
-
-       opt_queue = blk_init_queue(do_optcd_request, &optcd_lock);
-       if (!opt_queue) {
-               unregister_blkdev(MAJOR_NR, "optcd");
-               release_region(optcd_port, 4);
-               put_disk(optcd_disk);
-               return -ENOMEM;
-       }
-
-       blk_queue_hardsect_size(opt_queue, 2048);
-       optcd_disk->queue = opt_queue;
-       add_disk(optcd_disk);
-
-       printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
-       return 0;
-}
-
-
-static void __exit optcd_exit(void)
-{
-       del_gendisk(optcd_disk);
-       put_disk(optcd_disk);
-       if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
-               printk(KERN_ERR "optcd: what's that: can't unregister\n");
-               return;
-       }
-       blk_cleanup_queue(opt_queue);
-       release_region(optcd_port, 4);
-       printk(KERN_INFO "optcd: module released.\n");
-}
-
-module_init(optcd_init);
-module_exit(optcd_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR);
diff --git a/drivers/cdrom/optcd.h b/drivers/cdrom/optcd.h
deleted file mode 100644 (file)
index 1911bb9..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*     linux/include/linux/optcd.h - Optics Storage 8000 AT CDROM driver
-       $Id: optcd.h,v 1.2 1996/01/15 18:43:44 root Exp root $
-
-       Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
-
-
-       Configuration file for linux/drivers/cdrom/optcd.c
-*/
-
-#ifndef _LINUX_OPTCD_H
-#define _LINUX_OPTCD_H
-
-
-/* I/O base of drive. Drive uses base to base+2.
-   This setting can be overridden with the kernel or insmod command
-   line option 'optcd=<portbase>'. Use address of 0 to disable driver. */
-#define OPTCD_PORTBASE 0x340
-
-
-/* enable / disable parts of driver by define / undef */
-#define        MULTISESSION            /* multisession support (ALPHA) */
-
-
-/* Change 0 to 1 to debug various parts of the driver */
-#define        DEBUG_DRIVE_IF  0       /* Low level drive interface */
-#define        DEBUG_CONV      0       /* Address conversions */
-#define        DEBUG_BUFFERS   0       /* Buffering and block size conversion */
-#define        DEBUG_REQUEST   0       /* Request mechanism */
-#define        DEBUG_STATE     0       /* State machine */
-#define        DEBUG_TOC       0       /* Q-channel and Table of Contents */
-#define        DEBUG_MULTIS    0       /* Multisession code */
-#define        DEBUG_VFS       0       /* VFS interface */
-
-
-/* Don't touch these unless you know what you're doing. */
-
-/* Various timeout loop repetition counts. */
-#define BUSY_TIMEOUT           10000000        /* for busy wait */
-#define FAST_TIMEOUT           100000          /* ibid. for probing */
-#define SLEEP_TIMEOUT          6000            /* for timer wait */
-#define MULTI_SEEK_TIMEOUT     1000            /* for timer wait */
-#define READ_TIMEOUT           6000            /* for poll wait */
-#define STOP_TIMEOUT           2000            /* for poll wait */
-#define RESET_WAIT             5000            /* busy wait at drive reset */
-
-/* # of buffers for block size conversion. 6 is optimal for my setup (P75),
-   giving 280 kb/s, with 0.4% CPU usage. Experiment to find your optimal
-   setting */
-#define N_BUFS         6
-
-
-#endif /* _LINUX_OPTCD_H */
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
deleted file mode 100644 (file)
index a1283b1..0000000
+++ /dev/null
@@ -1,5966 +0,0 @@
-/*
- *  sbpcd.c   CD-ROM device driver for the whole family of traditional,
- *            non-ATAPI IDE-style Matsushita/Panasonic CR-5xx drives.
- *            Works with SoundBlaster compatible cards and with "no-sound"
- *            interface cards like Lasermate, Panasonic CI-101P, Teac, ...
- *            Also for the Longshine LCS-7260 drive.
- *            Also for the IBM "External ISA CD-Rom" drive.
- *            Also for the CreativeLabs CD200 drive.
- *            Also for the TEAC CD-55A drive.
- *            Also for the ECS-AT "Vertos 100" drive.
- *            Not for Sanyo drives (but for the H94A, sjcd is there...).
- *            Not for any other Funai drives than the CD200 types (sometimes
- *             labelled E2550UA or MK4015 or 2800F).
- */
-
-#define VERSION "v4.63 Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000"
-
-/*   Copyright (C) 1993, 1994, 1995  Eberhard Moenkeberg <emoenke@gwdg.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2, or (at your option)
- *   any later version.
- *
- *   You should have received a copy of the GNU General Public License
- *   (for example /usr/src/linux/COPYING); if not, write to the Free
- *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *   If you change this software, you should mail a .diff file with some
- *   description lines to emoenke@gwdg.de. I want to know about it.
- *
- *   If you are the editor of a Linux CD, you should enable sbpcd.c within
- *   your boot floppy kernel and send me one of your CDs for free.
- *
- *   If you would like to port the driver to an other operating system (f.e.
- *   FreeBSD or NetBSD) or use it as an information source, you shall not be
- *   restricted by the GPL under the following conditions:
- *     a) the source code of your work is freely available
- *     b) my part of the work gets mentioned at all places where your 
- *        authorship gets mentioned
- *     c) I receive a copy of your code together with a full installation
- *        package of your operating system for free.
- *
- *
- *  VERSION HISTORY
- *
- *  0.1  initial release, April/May 93, after mcd.c (Martin Harriss)
- *
- *  0.2  thek "repeat:"-loop in do_sbpcd_request did not check for
- *       end-of-request_queue (resulting in kernel panic).
- *       Flow control seems stable, but throughput is not better.  
- *
- *  0.3  interrupt locking totally eliminated (maybe "inb" and "outb"
- *       are still locking) - 0.2 made keyboard-type-ahead losses.
- *       check_sbpcd_media_change added (to use by isofs/inode.c)
- *       - but it detects almost nothing.
- *
- *  0.4  use MAJOR 25 definitely.
- *       Almost total re-design to support double-speed drives and
- *       "naked" (no sound) interface cards ("LaserMate" interface type).
- *       Flow control should be exact now.
- *       Don't occupy the SbPro IRQ line (not needed either); will
- *       live together with Hannu Savolainen's sndkit now.
- *       Speeded up data transfer to 150 kB/sec, with help from Kai
- *       Makisara, the "provider" of the "mt" tape utility.
- *       Give "SpinUp" command if necessary.
- *       First steps to support up to 4 drives (but currently only one).
- *       Implemented audio capabilities - workman should work, xcdplayer
- *       gives some problems.
- *       This version is still consuming too much CPU time, and
- *       sleeping still has to be worked on.
- *       During "long" implied seeks, it seems possible that a 
- *       ReadStatus command gets ignored. That gives the message
- *       "ResponseStatus timed out" (happens about 6 times here during
- *       a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is
- *       handled without data error, but it should get done better.
- *
- *  0.5  Free CPU during waits (again with help from Kai Makisara).
- *       Made it work together with the LILO/kernel setup standard.
- *       Included auto-probing code, as suggested by YGGDRASIL.
- *       Formal redesign to add DDI debugging.
- *       There are still flaws in IOCTL (workman with double speed drive).
- *
- *  1.0  Added support for all drive IDs (0...3, no longer only 0)
- *       and up to 4 drives on one controller.
- *       Added "#define MANY_SESSION" for "old" multi session CDs.
- *
- *  1.1  Do SpinUp for new drives, too.
- *       Revised for clean compile under "old" kernels (0.99pl9).
- *
- *  1.2  Found the "workman with double-speed drive" bug: use the driver's
- *       audio_state, not what the drive is reporting with ReadSubQ.
- *
- *  1.3  Minor cleanups.
- *       Refinements regarding Workman.
- *
- *  1.4  Read XA disks (PhotoCDs) with "old" drives, too (but only the first
- *       session - no chance to fully access a "multi-session" CD).
- *       This currently still is too slow (50 kB/sec) - but possibly
- *       the old drives won't do it faster.
- *       Implemented "door (un)lock" for new drives (still does not work
- *       as wanted - no lock possible after an unlock).
- *       Added some debugging printout for the UPC/EAN code - but my drives 
- *       return only zeroes. Is there no UPC/EAN code written?
- *
- *  1.5  Laborate with UPC/EAN code (not better yet).
- *       Adapt to kernel 1.1.8 change (have to explicitly include
- *       <linux/string.h> now).
- *
- *  1.6  Trying to read audio frames as data. Impossible with the current
- *       drive firmware levels, as it seems. Awaiting any hint. ;-)
- *       Changed "door unlock": repeat it until success.
- *       Changed CDROMSTOP routine (stop somewhat "softer" so that Workman
- *       won't get confused).
- *       Added a third interface type: Sequoia S-1000, as used with the SPEA
- *       Media FX sound card. This interface (usable for Sony and Mitsumi 
- *       drives, too) needs a special configuration setup and behaves like a 
- *       LaserMate type after that. Still experimental - I do not have such
- *       an interface.
- *       Use the "variable BLOCK_SIZE" feature (2048). But it does only work
- *       if you give the mount option "block=2048".
- *       The media_check routine is currently disabled; now that it gets
- *       called as it should I fear it must get synchronized for not to
- *       disturb the normal driver's activity.
- *
- *  2.0  Version number bumped - two reasons:
- *       - reading audio tracks as data works now with CR-562 and CR-563. We
- *       currently do it by an IOCTL (yet has to get standardized), one frame
- *       at a time; that is pretty slow. But it works.
- *       - we are maintaining now up to 4 interfaces (each up to 4 drives):
- *       did it the easy way - a different MAJOR (25, 26, ...) and a different
- *       copy of the driver (sbpcd.c, sbpcd2.c, sbpcd3.c, sbpcd4.c - only
- *       distinguished by the value of SBPCD_ISSUE and the driver's name),
- *       and a common sbpcd.h file.
- *       Bettered the "ReadCapacity error" problem with old CR-52x drives (the
- *       drives sometimes need a manual "eject/insert" before work): just
- *       reset the drive and do again. Needs lots of resets here and sometimes
- *       that does not cure, so this can't be the solution.
- *
- *  2.1  Found bug with multisession CDs (accessing frame 16).
- *       "read audio" works now with address type CDROM_MSF, too.
- *       Bigger audio frame buffer: allows reading max. 4 frames at time; this
- *       gives a significant speedup, but reading more than one frame at once
- *       gives missing chunks at each single frame boundary.
- *
- *  2.2  Kernel interface cleanups: timers, init, setup, media check.
- *
- *  2.3  Let "door lock" and "eject" live together.
- *       Implemented "close tray" (done automatically during open).
- *
- *  2.4  Use different names for device registering.
- *
- *  2.5  Added "#if EJECT" code (default: enabled) to automatically eject
- *       the tray during last call to "sbpcd_release".
- *       Added "#if JUKEBOX" code (default: disabled) to automatically eject
- *       the tray during call to "sbpcd_open" if no disk is in.
- *       Turn on the CD volume of "compatible" sound cards, too; just define
- *       SOUND_BASE (in sbpcd.h) accordingly (default: disabled).
- *
- *  2.6  Nothing new.  
- *
- *  2.7  Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly:
- *       0 disables, 1 enables auto-ejecting. Useful to keep the tray in
- *       during shutdown.
- *
- *  2.8  Added first support (still BETA, I need feedback or a drive) for
- *       the Longshine LCS-7260 drives. They appear as double-speed drives
- *       using the "old" command scheme, extended by tray control and door
- *       lock functions.
- *       Found (and fixed preliminary) a flaw with some multisession CDs: we
- *       have to re-direct not only the accesses to frame 16 (the isofs
- *       routines drive it up to max. 100), but also those to the continuation
- *       (repetition) frames (as far as they exist - currently set fix as
- *       16..20).
- *       Changed default of the "JUKEBOX" define. If you use this default,
- *       your tray will eject if you try to mount without a disk in. Next
- *       mount command will insert the tray - so, just fill in a disk. ;-)
- *
- *  2.9  Fulfilled the Longshine LCS-7260 support; with great help and
- *       experiments by Serge Robyns.
- *       First attempts to support the TEAC CD-55A drives; but still not
- *       usable yet.
- *       Implemented the CDROMMULTISESSION ioctl; this is an attempt to handle
- *       multi session CDs more "transparent" (redirection handling has to be
- *       done within the isofs routines, and only for the special purpose of
- *       obtaining the "right" volume descriptor; accesses to the raw device
- *       should not get redirected).
- *
- *  3.0  Just a "normal" increment, with some provisions to do it better. ;-)
- *       Introduced "#define READ_AUDIO" to specify the maximum number of 
- *       audio frames to grab with one request. This defines a buffer size
- *       within kernel space; a value of 0 will reserve no such space and
- *       disable the CDROMREADAUDIO ioctl. A value of 75 enables the reading
- *       of a whole second with one command, but will use a buffer of more
- *       than 172 kB.
- *       Started CD200 support. Drive detection should work, but nothing
- *       more.
- *
- *  3.1  Working to support the CD200 and the Teac CD-55A drives.
- *       AT-BUS style device numbering no longer used: use SCSI style now.
- *       So, the first "found" device has MINOR 0, regardless of the
- *       jumpered drive ID. This implies modifications to the /dev/sbpcd*
- *       entries for some people, but will help the DAU (german TLA, english:
- *       "newbie", maybe ;-) to install his "first" system from a CD.
- *
- *  3.2  Still testing with CD200 and CD-55A drives.
- *
- *  3.3  Working with CD200 support.
- *
- *  3.4  Auto-probing stops if an address of 0 is seen (to be entered with
- *       the kernel command line).
- *       Made the driver "loadable". If used as a module, "audio copy" is
- *       disabled, and the internal read ahead data buffer has a reduced size
- *       of 4 kB; so, throughput may be reduced a little bit with slow CPUs.
- *
- *  3.5  Provisions to handle weird photoCDs which have an interrupted
- *       "formatting" immediately after the last frames of some files: simply
- *       never "read ahead" with MultiSession CDs. By this, CPU usage may be
- *       increased with those CDs, and there may be a loss in speed.
- *       Re-structured the messaging system.
- *       The "loadable" version no longer has a limited READ_AUDIO buffer
- *       size.
- *       Removed "MANY_SESSION" handling for "old" multi session CDs.
- *       Added "private" IOCTLs CDROMRESET and CDROMVOLREAD.
- *       Started again to support the TEAC CD-55A drives, now that I found
- *       the money for "my own" drive. ;-)
- *       The TEAC CD-55A support is fairly working now.
- *       I have measured that the drive "delivers" at 600 kB/sec (even with
- *       bigger requests than the drive's 64 kB buffer can satisfy), but
- *       the "real" rate does not exceed 520 kB/sec at the moment. 
- *       Caused by the various changes to build in TEAC support, the timed
- *       loops are de-optimized at the moment (less throughput with CR-52x
- *       drives, and the TEAC will give speed only with SBP_BUFFER_FRAMES 64).
- *
- *  3.6  Fixed TEAC data read problems with SbPro interfaces.
- *       Initial size of the READ_AUDIO buffer is 0. Can get set to any size
- *       during runtime.
- *
- *  3.7  Introduced MAX_DRIVES for some poor interface cards (seen with TEAC
- *       drives) which allow only one drive (ID 0); this avoids repetitive
- *       detection under IDs 1..3. 
- *       Elongated cmd_out_T response waiting; necessary for photo CDs with
- *       a lot of sessions.
- *       Bettered the sbpcd_open() behavior with TEAC drives.
- *
- *  3.8  Elongated max_latency for CR-56x drives.
- *
- *  3.9  Finally fixed the long-known SoundScape/SPEA/Sequoia S-1000 interface
- *       configuration bug.
- *       Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy
- *       the config_spea() routine into their drivers. ;-)
- *
- *  4.0  No "big step" - normal version increment.
- *       Adapted the benefits from 1.3.33.
- *       Fiddled with CDROMREADAUDIO flaws.
- *       Avoid ReadCapacity command with CD200 drives (the MKE 1.01 version
- *       seems not to support it).
- *       Fulfilled "read audio" for CD200 drives, with help of Pete Heist
- *       (heistp@rpi.edu).
- *
- *  4.1  Use loglevel KERN_INFO with printk().
- *       Added support for "Vertos 100" drive ("ECS-AT") - it is very similar
- *       to the Longshine LCS-7260. Give feedback if you can - I never saw
- *       such a drive, and I have no specs.
- *
- *  4.2  Support for Teac 16-bit interface cards. Can't get auto-detected,
- *       so you have to jumper your card to 0x2C0. Still not 100% - come
- *       in contact if you can give qualified feedback.
- *       Use loglevel KERN_NOTICE with printk(). If you get annoyed by a
- *       flood of unwanted messages and the accompanied delay, try to read
- *       my documentation. Especially the Linux CDROM drivers have to do an
- *       important job for the newcomers, so the "distributed" version has
- *       to fit some special needs. Since generations, the flood of messages
- *       is user-configurable (even at runtime), but to get aware of this, one
- *       needs a special mental quality: the ability to read.
- *       
- *  4.3  CD200F does not like to receive a command while the drive is
- *       reading the ToC; still trying to solve it.
- *       Removed some redundant verify_area calls (yes, Heiko Eissfeldt
- *       is visiting all the Linux CDROM drivers ;-).
- *       
- *  4.4  Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down"
- *       experiments: "KLOGD_PAUSE".
- *       Inhibited "play audio" attempts with data CDs. Provisions for a
- *       "data-safe" handling of "mixed" (data plus audio) Cds.
- *
- *  4.5  Meanwhile Gonzalo Tornaria <tornaria@cmat.edu.uy> (GTL) built a
- *       special end_request routine: we seem to have to take care for not
- *       to have two processes working at the request list. My understanding
- *       was and is that ll_rw_blk should not call do_sbpcd_request as long
- *       as there is still one call active (the first call will care for all
- *       outstanding I/Os, and if a second call happens, that is a bug in
- *       ll_rw_blk.c).
- *       "Check media change" without touching any drive.
- *
- *  4.6  Use a semaphore to synchronize multi-activity; elaborated by Rob
- *       Riggs <rriggs@tesser.com>. At the moment, we simply block "read"
- *       against "ioctl" and vice versa. This could be refined further, but
- *       I guess with almost no performance increase.
- *       Experiments to speed up the CD-55A; again with help of Rob Riggs
- *       (to be true, he gave both, idea & code. ;-)
- *
- *  4.61 Ported to Uniform CD-ROM driver by 
- *       Heiko Eissfeldt <heiko@colossus.escape.de> with additional
- *       changes by Erik Andersen <andersee@debian.org>
- *
- *  4.62 Fix a bug where playing audio left the drive in an unusable state.
- *         Heiko Eissfeldt <heiko@colossus.escape.de>
- *
- *  November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                  Removed init_module & cleanup_module in favor of 
- *                  module_init & module_exit.
- *                  Torben Mathiasen <tmm@image.dk>
- *
- *  4.63 Bug fixes for audio annoyances, new legacy CDROM maintainer.
- *             Annoying things fixed:
- *             TOC reread on automated disk changes
- *             TOC reread on manual cd changes
- *             Play IOCTL tries to play CD before it's actually ready... sometimes.
- *             CD_AUDIO_COMPLETED state so workman (and other playes) can repeat play.
- *             Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000
- *
- *  4.64 Fix module parameters - were being completely ignored.
- *      Can also specify max_drives=N as a setup int to get rid of
- *      "ghost" drives on crap hardware (aren't they all?)   Paul Gortmaker
- *
- *  TODO
- *     implement "read all subchannel data" (96 bytes per frame)
- *     remove alot of the virtual status bits and deal with hardware status
- *     move the change of cd for audio to a better place
- *     add debug levels to insmod parameters (trivial)
- *
- *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
- *     elaborated speed-up experiments (and the fabulous results!), for
- *     the "push" towards load-free wait loops, and for the extensive mail
- *     thread which brought additional hints and bug fixes.
- *
- */
-
-/*
- * Trying to merge requests breaks this driver horribly (as in it goes
- * boom and apparently has done so since 2.3.41).  As it is a legacy
- * driver for a horribly slow double speed CD on a hideous interface
- * designed for polled operation, I won't lose any sleep in simply
- * disallowing merging.                                Paul G.  02/2001
- *
- * Thu May 30 14:14:47 CEST 2002:
- *
- * I have presumably found the reson for the above - there was a bogous
- * end_request substitute, which was manipulating the request queues
- * incorrectly. If someone has access to the actual hardware, and it's
- * still operations - well  please free to test it.
- *
- * Marcin Dalecki
- */
-
-/*
- * Add bio/kdev_t changes for 2.5.x required to make it work again. 
- * Still room for improvement in the request handling here if anyone
- * actually cares.  Bring your own chainsaw.    Paul G.  02/2002
- */
-
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <stdarg.h>
-#include "sbpcd.h"
-
-#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
-#include <linux/blkdev.h>
-
-/*==========================================================================*/
-#if SBPCD_DIS_IRQ
-# define SBPCD_CLI cli()
-# define SBPCD_STI sti()
-#else
-# define SBPCD_CLI
-# define SBPCD_STI
-#endif
-
-/*==========================================================================*/
-/*
- * auto-probing address list
- * inspired by Adam J. Richter from Yggdrasil
- *
- * still not good enough - can cause a hang.
- *   example: a NE 2000 ethernet card at 300 will cause a hang probing 310.
- * if that happens, reboot and use the LILO (kernel) command line.
- * The possibly conflicting ethernet card addresses get NOT probed 
- * by default - to minimize the hang possibilities. 
- *
- * The SB Pro addresses get "mirrored" at 0x6xx and some more locations - to
- * avoid a type error, the 0x2xx-addresses must get checked before 0x6xx.
- *
- * send mail to emoenke@gwdg.de if your interface card is not FULLY
- * represented here.
- */
-static int sbpcd[] =
-{
-       CDROM_PORT, SBPRO, /* probe with user's setup first */
-#if DISTRIBUTION
-       0x230, 1, /* Soundblaster Pro and 16 (default) */
-#if 0
-       0x300, 0, /* CI-101P (default), WDH-7001C (default),
-                    Galaxy (default), Reveal (one default) */
-       0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */
-       0x2C0, 3, /* Teac 16-bit cards */
-       0x260, 1, /* OmniCD */
-       0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default),
-                    Longshine LCS-6853 (default) */
-       0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */
-       0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */
-       0x360, 0, /* Lasermate, CI-101P */
-       0x270, 1, /* Soundblaster 16 */
-       0x670, 0, /* "sound card #9" */
-       0x690, 0, /* "sound card #9" */
-       0x338, 2, /* SPEA Media FX, Ensonic SoundScape (default) */
-       0x328, 2, /* SPEA Media FX */
-       0x348, 2, /* SPEA Media FX */
-       0x634, 0, /* some newer sound cards */
-       0x638, 0, /* some newer sound cards */
-       0x230, 1, /* some newer sound cards */
-       /* due to incomplete address decoding of the SbPro card, these must be last */
-       0x630, 0, /* "sound card #9" (default) */
-       0x650, 0, /* "sound card #9" */
-#ifdef MODULE
-       /*
-        * some "hazardous" locations (no harm with the loadable version)
-        * (will stop the bus if a NE2000 ethernet card resides at offset -0x10)
-        */
-       0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
-       0x350, 0, /* Lasermate, CI-101P */
-       0x358, 2, /* SPEA Media FX */
-       0x370, 0, /* Lasermate, CI-101P */
-       0x290, 1, /* Soundblaster 16 */
-       0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
-#endif /* MODULE */
-#endif
-#endif /* DISTRIBUTION */
-};
-
-/*
- * Protects access to global structures etc.
- */
-static  __cacheline_aligned DEFINE_SPINLOCK(sbpcd_lock);
-static struct request_queue *sbpcd_queue;
-
-/* You can only set the first pair, from old MODULE_PARM code.  */
-static int sbpcd_set(const char *val, struct kernel_param *kp)
-{
-       get_options((char *)val, 2, (int *)sbpcd);
-       return 0;
-}
-module_param_call(sbpcd, sbpcd_set, NULL, NULL, 0);
-
-#define NUM_PROBE  (sizeof(sbpcd) / sizeof(int))
-
-/*==========================================================================*/
-
-#define INLINE inline
-
-/*==========================================================================*/
-/*
- * the forward references:
- */
-static void sbp_sleep(u_int);
-static void mark_timeout_delay(u_long);
-static void mark_timeout_data(u_long);
-#if 0
-static void mark_timeout_audio(u_long);
-#endif
-static void sbp_read_cmd(struct request *req);
-static int sbp_data(struct request *req);
-static int cmd_out(void);
-static int DiskInfo(void);
-
-/*==========================================================================*/
-
-/*
- * pattern for printk selection:
- *
- * (1<<DBG_INF)  necessary information
- * (1<<DBG_BSZ)  BLOCK_SIZE trace
- * (1<<DBG_REA)  "read" status trace
- * (1<<DBG_CHK)  "media check" trace
- * (1<<DBG_TIM)  datarate timer test
- * (1<<DBG_INI)  initialization trace
- * (1<<DBG_TOC)  tell TocEntry values
- * (1<<DBG_IOC)  ioctl trace
- * (1<<DBG_STA)  "ResponseStatus" trace
- * (1<<DBG_ERR)  "cc_ReadError" trace
- * (1<<DBG_CMD)  "cmd_out" trace
- * (1<<DBG_WRN)  give explanation before auto-probing
- * (1<<DBG_MUL)  multi session code test
- * (1<<DBG_IDX)  "drive_id != 0" test code
- * (1<<DBG_IOX)  some special information
- * (1<<DBG_DID)  drive ID test
- * (1<<DBG_RES)  drive reset info
- * (1<<DBG_SPI)  SpinUp test info
- * (1<<DBG_IOS)  ioctl trace: "subchannel"
- * (1<<DBG_IO2)  ioctl trace: general
- * (1<<DBG_UPC)  show UPC info
- * (1<<DBG_XA1)  XA mode debugging
- * (1<<DBG_LCK)  door (un)lock info
- * (1<<DBG_SQ1)   dump SubQ frame
- * (1<<DBG_AUD)  "read audio" debugging
- * (1<<DBG_SEQ)  Sequoia interface configuration trace
- * (1<<DBG_LCS)  Longshine LCS-7260 debugging trace
- * (1<<DBG_CD2)  MKE/Funai CD200 debugging trace
- * (1<<DBG_TEA)  TEAC CD-55A debugging trace
- * (1<<DBG_ECS)  ECS-AT (Vertos-100) debugging trace
- * (1<<DBG_000)  unnecessary information
- */
-#if DISTRIBUTION
-static int sbpcd_debug = (1<<DBG_INF);
-#else
-static int sbpcd_debug = 0 & ((1<<DBG_INF) |
-                         (1<<DBG_TOC) |
-                         (1<<DBG_MUL) |
-                         (1<<DBG_UPC));
-#endif /* DISTRIBUTION */
-
-static int sbpcd_ioaddr = CDROM_PORT;  /* default I/O base address */
-static int sbpro_type = SBPRO;
-static unsigned char f_16bit;
-static unsigned char do_16bit;
-static int CDo_command, CDo_reset;
-static int CDo_sel_i_d, CDo_enable;
-static int CDi_info, CDi_status, CDi_data;
-static struct cdrom_msf msf;
-static struct cdrom_ti ti;
-static struct cdrom_tochdr tochdr;
-static struct cdrom_tocentry tocentry;
-static struct cdrom_subchnl SC;
-static struct cdrom_volctrl volctrl;
-static struct cdrom_read_audio read_audio;
-
-static unsigned char msgnum;
-static char msgbuf[80];
-
-static int max_drives = MAX_DRIVES;
-module_param(max_drives, int, 0);
-#ifndef MODULE
-static unsigned char setup_done;
-static const char *str_sb_l = "soundblaster";
-static const char *str_sp_l = "spea";
-static const char *str_ss_l = "soundscape";
-static const char *str_t16_l = "teac16bit";
-static const char *str_ss = "SoundScape";
-#endif
-static const char *str_sb = "SoundBlaster";
-static const char *str_lm = "LaserMate";
-static const char *str_sp = "SPEA";
-static const char *str_t16 = "Teac16bit";
-static const char *type;
-static const char *major_name="sbpcd";
-
-/*==========================================================================*/
-
-#ifdef FUTURE
-static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq);
-#endif /* FUTURE */
-
-static int teac=SBP_TEAC_SPEED;
-static int buffers=SBP_BUFFER_FRAMES;
-
-static u_char family0[]="MATSHITA"; /* MKE CR-521, CR-522, CR-523 */
-static u_char family1[]="CR-56";    /* MKE CR-562, CR-563 */
-static u_char family2[]="CD200";    /* MKE CD200, Funai CD200F */
-static u_char familyL[]="LCS-7260"; /* Longshine LCS-7260 */
-static u_char familyT[]="CD-55";    /* TEAC CD-55A */
-static u_char familyV[]="ECS-AT";   /* ECS Vertos 100 */
-
-static u_int recursion; /* internal testing only */
-static u_int fatal_err; /* internal testing only */
-static u_int response_count;
-static u_int flags_cmd_out;
-static u_char cmd_type;
-static u_char drvcmd[10];
-static u_char infobuf[20];
-static u_char xa_head_buf[CD_XA_HEAD];
-static u_char xa_tail_buf[CD_XA_TAIL];
-
-#if OLD_BUSY
-static volatile u_char busy_data;
-static volatile u_char busy_audio; /* true semaphores would be safer */
-#endif /* OLD_BUSY */ 
-static DECLARE_MUTEX(ioctl_read_sem);
-static u_long timeout;
-static volatile u_char timed_out_delay;
-static volatile u_char timed_out_data;
-#if 0
-static volatile u_char timed_out_audio;
-#endif
-static u_int datarate= 1000000;
-static u_int maxtim16=16000000;
-static u_int maxtim04= 4000000;
-static u_int maxtim02= 2000000;
-static u_int maxtim_8=   30000;
-#if LONG_TIMING
-static u_int maxtim_data= 9000;
-#else
-static u_int maxtim_data= 3000;
-#endif /* LONG_TIMING */ 
-#if DISTRIBUTION
-static int n_retries=6;
-#else
-static int n_retries=6;
-#endif
-/*==========================================================================*/
-
-static int ndrives;
-static u_char drv_pattern[NR_SBPCD]={speed_auto,speed_auto,speed_auto,speed_auto};
-
-/*==========================================================================*/
-/*
- * drive space begins here (needed separate for each unit) 
- */
-static struct sbpcd_drive {
-       char drv_id;           /* "jumpered" drive ID or -1 */
-       char drv_sel;          /* drive select lines bits */
-       
-       char drive_model[9];
-       u_char firmware_version[4];
-       char f_eject;          /* auto-eject flag: 0 or 1 */
-       u_char *sbp_buf;       /* Pointer to internal data buffer,
-                                 space allocated during sbpcd_init() */
-       u_int sbp_bufsiz;      /* size of sbp_buf (# of frames) */
-       int sbp_first_frame;   /* First frame in buffer */
-       int sbp_last_frame;    /* Last frame in buffer  */
-       int sbp_read_frames;   /* Number of frames being read to buffer */
-       int sbp_current;       /* Frame being currently read */
-       
-       u_char mode;           /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
-       u_char *aud_buf;       /* Pointer to audio data buffer,
-                                 space allocated during sbpcd_init() */
-       u_int sbp_audsiz;      /* size of aud_buf (# of raw frames) */
-       u_int drv_type;
-       u_char drv_options;
-       int status_bits;
-       u_char diskstate_flags;
-       u_char sense_byte;
-       
-       u_char CD_changed;
-       char open_count;
-       u_char error_byte;
-       
-       u_char f_multisession;
-       u_int lba_multi;
-       int first_session;
-       int last_session;
-       int track_of_last_session;
-       
-       u_char audio_state;
-       u_int pos_audio_start;
-       u_int pos_audio_end;
-       char vol_chan0;
-       u_char vol_ctrl0;
-       char vol_chan1;
-       u_char vol_ctrl1;
-#if 000 /* no supported drive has it */
-       char vol_chan2;
-       u_char vol_ctrl2;
-       char vol_chan3;
-       u_char vol_ctrl3;
-#endif /*000 */
-       u_char volume_control; /* TEAC on/off bits */
-       
-       u_char SubQ_ctl_adr;
-       u_char SubQ_trk;
-       u_char SubQ_pnt_idx;
-       u_int SubQ_run_tot;
-       u_int SubQ_run_trk;
-       u_char SubQ_whatisthis;
-       
-       u_char UPC_ctl_adr;
-       u_char UPC_buf[7];
-       
-       int frame_size;
-       int CDsize_frm;
-       
-       u_char xa_byte; /* 0x20: XA capabilities */
-       u_char n_first_track; /* binary */
-       u_char n_last_track; /* binary (not bcd), 0x01...0x63 */
-       u_int size_msf; /* time of whole CD, position of LeadOut track */
-       u_int size_blk;
-       
-       u_char TocEnt_nixbyte; /* em */
-       u_char TocEnt_ctl_adr;
-       u_char TocEnt_number;
-       u_char TocEnt_format; /* em */
-       u_int TocEnt_address;
-#ifdef SAFE_MIXED
-       char has_data;
-#endif /* SAFE_MIXED */ 
-       u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
-       
-       struct {
-               u_char nixbyte; /* em */
-               u_char ctl_adr; /* 0x4x: data, 0x0x: audio */
-               u_char number;
-               u_char format; /* em */ /* 0x00: lba, 0x01: msf */
-               u_int address;
-       } TocBuffer[MAX_TRACKS+1]; /* last entry faked */ 
-       
-       int in_SpinUp; /* CR-52x test flag */
-       int n_bytes; /* TEAC awaited response count */
-       u_char error_state, b3, b4; /* TEAC command error state */
-       u_char f_drv_error; /* TEAC command error flag */
-       u_char speed_byte;
-       int frmsiz;
-       u_char f_XA; /* 1: XA */
-       u_char type_byte; /* 0, 1, 3 */
-       u_char mode_xb_6;
-       u_char mode_yb_7;
-       u_char mode_xb_8;
-       u_char delay;
-       struct cdrom_device_info *sbpcd_infop;
-       struct gendisk *disk;
-} D_S[NR_SBPCD];
-
-static struct sbpcd_drive *current_drive = D_S;
-
-/*
- * drive space ends here (needed separate for each unit)
- */
-/*==========================================================================*/
-#if 0
-unsigned long cli_sti; /* for saving the processor flags */
-#endif
-/*==========================================================================*/
-static DEFINE_TIMER(delay_timer, mark_timeout_delay, 0, 0);
-static DEFINE_TIMER(data_timer, mark_timeout_data, 0, 0);
-#if 0
-static DEFINE_TIMER(audio_timer, mark_timeout_audio, 0, 0);
-#endif
-/*==========================================================================*/
-/*
- * DDI interface
- */
-static void msg(int level, const char *fmt, ...)
-{
-#if DISTRIBUTION
-#define MSG_LEVEL KERN_NOTICE
-#else
-#define MSG_LEVEL KERN_INFO
-#endif /* DISTRIBUTION */
-
-       char buf[256];
-       va_list args;
-       
-       if (!(sbpcd_debug&(1<<level))) return;
-       
-       msgnum++;
-       if (msgnum>99) msgnum=0;
-       va_start(args, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, args);
-       va_end(args);
-       printk(MSG_LEVEL "%s-%d [%02d]:  %s", major_name, current_drive - D_S, msgnum, buf);
-#if KLOGD_PAUSE
-       sbp_sleep(KLOGD_PAUSE); /* else messages get lost */
-#endif /* KLOGD_PAUSE */ 
-       return;
-}
-/*==========================================================================*/
-/*
- * DDI interface: runtime trace bit pattern maintenance
- */
-static int sbpcd_dbg_ioctl(unsigned long arg, int level)
-{
-       switch(arg)
-       {
-       case 0: /* OFF */
-               sbpcd_debug = DBG_INF;
-               break;
-               
-       default:
-               if (arg>=128) sbpcd_debug &= ~(1<<(arg-128));
-               else sbpcd_debug |= (1<<arg);
-       }
-       return (arg);
-}
-/*==========================================================================*/
-static void mark_timeout_delay(u_long i)
-{
-       timed_out_delay=1;
-#if 0
-       msg(DBG_TIM,"delay timer expired.\n");
-#endif
-}
-/*==========================================================================*/
-static void mark_timeout_data(u_long i)
-{
-       timed_out_data=1;
-#if 0
-       msg(DBG_TIM,"data timer expired.\n");
-#endif
-}
-/*==========================================================================*/
-#if 0
-static void mark_timeout_audio(u_long i)
-{
-       timed_out_audio=1;
-#if 0
-       msg(DBG_TIM,"audio timer expired.\n");
-#endif
-}
-#endif
-/*==========================================================================*/
-/*
- * Wait a little while (used for polling the drive).
- */
-static void sbp_sleep(u_int time)
-{
-       sti();
-       schedule_timeout_interruptible(time);
-       sti();
-}
-/*==========================================================================*/
-#define RETURN_UP(rc) {up(&ioctl_read_sem); return(rc);}
-/*==========================================================================*/
-/*
- *  convert logical_block_address to m-s-f_number (3 bytes only)
- */
-static INLINE void lba2msf(int lba, u_char *msf)
-{
-       lba += CD_MSF_OFFSET;
-       msf[0] = lba / (CD_SECS*CD_FRAMES);
-       lba %= CD_SECS*CD_FRAMES;
-       msf[1] = lba / CD_FRAMES;
-       msf[2] = lba % CD_FRAMES;
-}
-/*==========================================================================*/
-/*==========================================================================*/
-/*
- *  convert msf-bin to msf-bcd
- */
-static INLINE void bin2bcdx(u_char *p)  /* must work only up to 75 or 99 */
-{
-       *p=((*p/10)<<4)|(*p%10);
-}
-/*==========================================================================*/
-static INLINE u_int blk2msf(u_int blk)
-{
-       MSF msf;
-       u_int mm;
-       
-       msf.c[3] = 0;
-       msf.c[2] = (blk + CD_MSF_OFFSET) / (CD_SECS * CD_FRAMES);
-       mm = (blk + CD_MSF_OFFSET) % (CD_SECS * CD_FRAMES);
-       msf.c[1] = mm / CD_FRAMES;
-       msf.c[0] = mm % CD_FRAMES;
-       return (msf.n);
-}
-/*==========================================================================*/
-static INLINE u_int make16(u_char rh, u_char rl)
-{
-       return ((rh<<8)|rl);
-}
-/*==========================================================================*/
-static INLINE u_int make32(u_int rh, u_int rl)
-{
-       return ((rh<<16)|rl);
-}
-/*==========================================================================*/
-static INLINE u_char swap_nibbles(u_char i)
-{
-       return ((i<<4)|(i>>4));
-}
-/*==========================================================================*/
-static INLINE u_char byt2bcd(u_char i)
-{
-       return (((i/10)<<4)+i%10);
-}
-/*==========================================================================*/
-static INLINE u_char bcd2bin(u_char bcd)
-{
-       return ((bcd>>4)*10+(bcd&0x0F));
-}
-/*==========================================================================*/
-static INLINE int msf2blk(int msfx)
-{
-       MSF msf;
-       int i;
-       
-       msf.n=msfx;
-       i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_MSF_OFFSET;
-       if (i<0) return (0);
-       return (i);
-}
-/*==========================================================================*/
-/*
- *  convert m-s-f_number (3 bytes only) to logical_block_address 
- */
-static INLINE int msf2lba(u_char *msf)
-{
-       int i;
-       
-       i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_MSF_OFFSET;
-       if (i<0) return (0);
-       return (i);
-}
-/*==========================================================================*/
-/* evaluate cc_ReadError code */ 
-static int sta2err(int sta)
-{
-       if (famT_drive)
-       {
-               if (sta==0x00) return (0);
-               if (sta==0x01) return (-604); /* CRC error */
-               if (sta==0x02) return (-602); /* drive not ready */
-               if (sta==0x03) return (-607); /* unknown media */
-               if (sta==0x04) return (-612); /* general failure */
-               if (sta==0x05) return (0);
-               if (sta==0x06) return (-ERR_DISKCHANGE); /* disk change */
-               if (sta==0x0b) return (-612); /* general failure */
-               if (sta==0xff) return (-612); /* general failure */
-               return (0);
-       }
-       else
-       {
-               if (sta<=2) return (sta);
-               if (sta==0x05) return (-604); /* CRC error */
-               if (sta==0x06) return (-606); /* seek error */
-               if (sta==0x0d) return (-606); /* seek error */
-               if (sta==0x0e) return (-603); /* unknown command */
-               if (sta==0x14) return (-603); /* unknown command */
-               if (sta==0x0c) return (-611); /* read fault */
-               if (sta==0x0f) return (-611); /* read fault */
-               if (sta==0x10) return (-611); /* read fault */
-               if (sta>=0x16) return (-612); /* general failure */
-               if (sta==0x11) return (-ERR_DISKCHANGE); /* disk change (LCS: removed) */
-               if (famL_drive)
-                       if (sta==0x12) return (-ERR_DISKCHANGE); /* disk change (inserted) */
-               return (-602); /* drive not ready */
-       }
-}
-/*==========================================================================*/
-static INLINE void clr_cmdbuf(void)
-{
-       int i;
-       
-       for (i=0;i<10;i++) drvcmd[i]=0;
-       cmd_type=0;
-}
-/*==========================================================================*/
-static void flush_status(void)
-{
-       int i;
-       
-       sbp_sleep(15*HZ/10);
-       for (i=maxtim_data;i!=0;i--) inb(CDi_status);
-}
-/*====================================================================*/
-/*
- * CDi status loop for Teac CD-55A (Rob Riggs)
- *
- * This is needed because for some strange reason
- * the CD-55A can take a real long time to give a
- * status response. This seems to happen after we
- * issue a READ command where a long seek is involved.
- *
- * I tried to ensure that we get max throughput with
- * minimal busy waiting. We busy wait at first, then
- * "switch gears" and start sleeping. We sleep for
- * longer periods of time the longer we wait.
- *
- */
-static int CDi_stat_loop_T(void)
-{
-       int     i, gear=1;
-       u_long  timeout_1, timeout_2, timeout_3, timeout_4;
-
-       timeout_1 = jiffies + HZ / 50;  /* sbp_sleep(0) for a short period */
-       timeout_2 = jiffies + HZ / 5;   /* nap for no more than 200ms */
-       timeout_3 = jiffies + 5 * HZ;   /* sleep for up to 5s */
-       timeout_4 = jiffies + 45 * HZ;  /* long sleep for up to 45s. */
-       do
-          {
-            i = inb(CDi_status);
-            if (!(i&s_not_data_ready)) return (i);
-            if (!(i&s_not_result_ready)) return (i);
-            switch(gear)
-              {
-              case 4:
-                sbp_sleep(HZ);
-                if (time_after(jiffies, timeout_4)) gear++;
-                msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n");
-                break;
-              case 3:
-                sbp_sleep(HZ/10);
-                if (time_after(jiffies, timeout_3)) gear++;
-                break;
-              case 2:
-                sbp_sleep(HZ/100);
-                if (time_after(jiffies, timeout_2)) gear++;
-                break;
-              case 1:
-                sbp_sleep(0);
-                if (time_after(jiffies, timeout_1)) gear++;
-              }
-          } while (gear < 5);
-       return -1;
-}
-/*==========================================================================*/
-static int CDi_stat_loop(void)
-{
-       int i,j;
-       
-       for(timeout = jiffies + 10*HZ, i=maxtim_data; time_before(jiffies, timeout); )
-       {
-               for ( ;i!=0;i--)
-               {
-                       j=inb(CDi_status);
-                       if (!(j&s_not_data_ready)) return (j);
-                       if (!(j&s_not_result_ready)) return (j);
-                       if (fam0L_drive) if (j&s_attention) return (j);
-               }
-               sbp_sleep(1);
-               i = 1;
-       }
-       msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__);
-       return (-1);
-}
-/*==========================================================================*/
-#if 00000
-/*==========================================================================*/
-static int tst_DataReady(void)
-{
-       int i;
-       
-       i=inb(CDi_status);
-       if (i&s_not_data_ready) return (0);
-       return (1);
-}
-/*==========================================================================*/
-static int tst_ResultReady(void)
-{
-       int i;
-       
-       i=inb(CDi_status);
-       if (i&s_not_result_ready) return (0);
-       return (1);
-}
-/*==========================================================================*/
-static int tst_Attention(void)
-{
-       int i;
-       
-       i=inb(CDi_status);
-       if (i&s_attention) return (1);
-       return (0);
-}
-/*==========================================================================*/
-#endif
-/*==========================================================================*/
-static int ResponseInfo(void)
-{
-       int i,j,st=0;
-       u_long timeout;
-       
-       for (i=0,timeout=jiffies+HZ;i<response_count;i++) 
-       {
-               for (j=maxtim_data; ; )
-               {
-                       for ( ;j!=0;j-- )
-                       {
-                               st=inb(CDi_status);
-                               if (!(st&s_not_result_ready)) break;
-                       }
-                       if ((j!=0)||time_after_eq(jiffies, timeout)) break;
-                       sbp_sleep(1);
-                       j = 1;
-               }
-               if (time_after_eq(jiffies, timeout)) break;
-               infobuf[i]=inb(CDi_info);
-       }
-#if 000
-       while (!(inb(CDi_status)&s_not_result_ready))
-       {
-               infobuf[i++]=inb(CDi_info);
-       }
-       j=i-response_count;
-       if (j>0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j);
-#endif /* 000 */
-       for (j=0;j<i;j++)
-               sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
-       msgbuf[j*3]=0;
-       msg(DBG_CMD,"ResponseInfo:%s (%d,%d)\n",msgbuf,response_count,i);
-       j=response_count-i;
-       if (j>0) return (-j);
-       else return (i);
-}
-/*==========================================================================*/
-static void EvaluateStatus(int st)
-{
-       current_drive->status_bits=0;
-       if (fam1_drive) current_drive->status_bits=st|p_success;
-       else if (fam0_drive)
-       {
-               if (st&p_caddin_old) current_drive->status_bits |= p_door_closed|p_caddy_in;
-               if (st&p_spinning) current_drive->status_bits |= p_spinning;
-               if (st&p_check) current_drive->status_bits |= p_check;
-               if (st&p_success_old) current_drive->status_bits |= p_success;
-               if (st&p_busy_old) current_drive->status_bits |= p_busy_new;
-               if (st&p_disk_ok) current_drive->status_bits |= p_disk_ok;
-       }
-       else if (famLV_drive)
-       {
-               current_drive->status_bits |= p_success;
-               if (st&p_caddin_old) current_drive->status_bits |= p_disk_ok|p_caddy_in;
-               if (st&p_spinning) current_drive->status_bits |= p_spinning;
-               if (st&p_check) current_drive->status_bits |= p_check;
-               if (st&p_busy_old) current_drive->status_bits |= p_busy_new;
-               if (st&p_lcs_door_closed) current_drive->status_bits |= p_door_closed;
-               if (st&p_lcs_door_locked) current_drive->status_bits |= p_door_locked;
-       }
-       else if (fam2_drive)
-       {
-               current_drive->status_bits |= p_success;
-               if (st&p2_check) current_drive->status_bits |= p1_check;
-               if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed;
-               if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in;
-               if (st&p2_busy1) current_drive->status_bits |= p1_busy;
-               if (st&p2_busy2) current_drive->status_bits |= p1_busy;
-               if (st&p2_spinning) current_drive->status_bits |= p1_spinning;
-               if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked;
-               if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok;
-       }
-       else if (famT_drive)
-       {
-               return; /* still needs to get coded */
-               current_drive->status_bits |= p_success;
-               if (st&p2_check) current_drive->status_bits |= p1_check;
-               if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed;
-               if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in;
-               if (st&p2_busy1) current_drive->status_bits |= p1_busy;
-               if (st&p2_busy2) current_drive->status_bits |= p1_busy;
-               if (st&p2_spinning) current_drive->status_bits |= p1_spinning;
-               if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked;
-               if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok;
-       }
-       return;
-}
-/*==========================================================================*/
-static int cmd_out_T(void);
-
-static int get_state_T(void)
-{
-       int i;
-
-       clr_cmdbuf();
-       current_drive->n_bytes=1;
-       drvcmd[0]=CMDT_STATUS;
-       i=cmd_out_T();
-       if (i>=0) i=infobuf[0];
-       else
-       {
-               msg(DBG_TEA,"get_state_T error %d\n", i);
-               return (i);
-       }
-       if (i>=0)
-               /* 2: closed, disk in */
-               current_drive->status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok;
-       else if (current_drive->error_state==6)
-       {
-               /* 3: closed, disk in, changed ("06 xx xx") */
-               current_drive->status_bits=p1_door_closed|p1_disk_in;
-               current_drive->CD_changed=0xFF;
-               current_drive->diskstate_flags &= ~toc_bit;
-       }
-       else if ((current_drive->error_state!=2)||(current_drive->b3!=0x3A)||(current_drive->b4==0x00))
-       {
-               /* 1: closed, no disk ("xx yy zz"or "02 3A 00") */
-               current_drive->status_bits=p1_door_closed;
-               current_drive->open_count=0;
-       }
-       else if (current_drive->b4==0x01)
-       {
-               /* 0: open ("02 3A 01") */
-               current_drive->status_bits=0;
-               current_drive->open_count=0;
-       }
-       else
-       {
-               /* 1: closed, no disk ("02 3A xx") */
-               current_drive->status_bits=p1_door_closed;
-               current_drive->open_count=0;
-       }
-       return (current_drive->status_bits);
-}
-/*==========================================================================*/
-static int ResponseStatus(void)
-{
-       int i,j;
-       u_long timeout;
-       
-       msg(DBG_STA,"doing ResponseStatus...\n");
-       if (famT_drive) return (get_state_T());
-       if (flags_cmd_out & f_respo3) timeout = jiffies;
-       else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ;
-       else timeout = jiffies + 4*HZ;
-       j=maxtim_8;
-       do
-       {
-               for ( ;j!=0;j--)
-               { 
-                       i=inb(CDi_status);
-                       if (!(i&s_not_result_ready)) break;
-               }
-               if ((j!=0)||time_after(jiffies, timeout)) break;
-               sbp_sleep(1);
-               j = 1;
-       }
-       while (1);
-       if (j==0) 
-       {
-               if ((flags_cmd_out & f_respo3) == 0)
-                       msg(DBG_STA,"ResponseStatus: timeout.\n");
-               current_drive->status_bits=0;
-               return (-401);
-       }
-       i=inb(CDi_info);
-       msg(DBG_STA,"ResponseStatus: response %02X.\n", i);
-       EvaluateStatus(i);
-       msg(DBG_STA,"status_bits=%02X, i=%02X\n",current_drive->status_bits,i);
-       return (current_drive->status_bits);
-}
-/*==========================================================================*/
-static void cc_ReadStatus(void)
-{
-       int i;
-       
-       msg(DBG_STA,"giving cc_ReadStatus command\n");
-       if (famT_drive) return;
-       SBPCD_CLI;
-       if (fam0LV_drive) OUT(CDo_command,CMD0_STATUS);
-       else if (fam1_drive) OUT(CDo_command,CMD1_STATUS);
-       else if (fam2_drive) OUT(CDo_command,CMD2_STATUS);
-       if (!fam0LV_drive) for (i=0;i<6;i++) OUT(CDo_command,0);
-       SBPCD_STI;
-}
-/*==========================================================================*/
-static int cc_ReadError(void)
-{
-       int i;
-
-       clr_cmdbuf();
-       msg(DBG_ERR,"giving cc_ReadError command.\n");
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_READ_ERR;
-               response_count=8;
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (fam0LV_drive)
-       {
-               drvcmd[0]=CMD0_READ_ERR;
-               response_count=6;
-               if (famLV_drive)
-                       flags_cmd_out=f_putcmd;
-               else
-                       flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_READ_ERR;
-               response_count=6;
-               flags_cmd_out=f_putcmd;
-       }
-       else if (famT_drive)
-       {
-               response_count=5;
-               drvcmd[0]=CMDT_READ_ERR;
-       }
-       i=cmd_out();
-       current_drive->error_byte=0;
-       msg(DBG_ERR,"cc_ReadError: cmd_out(CMDx_READ_ERR) returns %d (%02X)\n",i,i);
-       if (i<0) return (i);
-       if (fam0V_drive) i=1;
-       else i=2;
-       current_drive->error_byte=infobuf[i];
-       msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,current_drive->error_byte,current_drive->error_byte);
-       i=sta2err(infobuf[i]);
-        if (i==-ERR_DISKCHANGE)
-        {
-                current_drive->CD_changed=0xFF;
-                current_drive->diskstate_flags &= ~toc_bit;
-        }
-       return (i);
-}
-/*==========================================================================*/
-static int cc_DriveReset(void);
-
-static int cmd_out_T(void)
-{
-#undef CMDT_TRIES
-#define CMDT_TRIES 1000
-#define TEST_FALSE_FF 1
-
-       int i, j, l=0, m, ntries;
-       unsigned long flags;
-
-       current_drive->error_state=0;
-       current_drive->b3=0;
-       current_drive->b4=0;
-       current_drive->f_drv_error=0;
-       for (i=0;i<10;i++) sprintf(&msgbuf[i*3]," %02X",drvcmd[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_CMD,"cmd_out_T:%s\n",msgbuf);
-
-       OUT(CDo_sel_i_d,0);
-       OUT(CDo_enable,current_drive->drv_sel);
-       i=inb(CDi_status);
-       do_16bit=0;
-       if ((f_16bit)&&(!(i&0x80)))
-       {
-               do_16bit=1;
-               msg(DBG_TEA,"cmd_out_T: do_16bit set.\n");
-       }
-       if (!(i&s_not_result_ready))
-       do
-       {
-               j=inb(CDi_info);
-               i=inb(CDi_status);
-               sbp_sleep(0);
-               msg(DBG_TEA,"cmd_out_T: spurious !s_not_result_ready. (%02X)\n", j);
-       }
-       while (!(i&s_not_result_ready));
-       save_flags(flags); cli();
-       for (i=0;i<10;i++) OUT(CDo_command,drvcmd[i]);
-       restore_flags(flags);
-       for (ntries=CMDT_TRIES;ntries>0;ntries--)
-       {
-               if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */
-#if 01
-               OUT(CDo_sel_i_d,1);
-#endif /* 01 */
-               if (teac==2)
-                  {
-                    if ((i=CDi_stat_loop_T()) == -1) break;
-                  }
-               else
-                  {
-#if 0
-                    OUT(CDo_sel_i_d,1);
-#endif /* 0 */ 
-                    i=inb(CDi_status);
-                  }
-               if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */
-               {
-                       OUT(CDo_sel_i_d,1);
-                       if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */
-                       if (drvcmd[0]==CMDT_DISKINFO)
-                       {
-                               l=0;
-                               do
-                                {
-                                        if (do_16bit)
-                                        {
-                                                i=inw(CDi_data);
-                                                infobuf[l++]=i&0x0ff;
-                                                infobuf[l++]=i>>8;
-#if TEST_FALSE_FF
-                                                if ((l==2)&&(infobuf[0]==0x0ff))
-                                                {
-                                                        infobuf[0]=infobuf[1];
-                                                        l=1;
-                                                        msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n");
-                                                }
-#endif /* TEST_FALSE_FF */ 
-                                        }
-                                        else infobuf[l++]=inb(CDi_data);
-                                        i=inb(CDi_status);
-                                }
-                               while (!(i&s_not_data_ready));
-                               for (j=0;j<l;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
-                               msgbuf[j*3]=0;
-                               msg(DBG_CMD,"cmd_out_T data response:%s\n", msgbuf);
-                       }
-                       else
-                       {
-                               msg(DBG_TEA,"cmd_out_T: data response with cmd_%02X!\n",
-                                    drvcmd[0]);
-                               j=0;
-                               do
-                               {
-                                        if (do_16bit) i=inw(CDi_data);
-                                        else i=inb(CDi_data);
-                                        j++;
-                                        i=inb(CDi_status);
-                               }
-                               while (!(i&s_not_data_ready));
-                               msg(DBG_TEA,"cmd_out_T: data response: discarded %d bytes/words.\n", j);
-                               fatal_err++;
-                       }
-               }
-               i=inb(CDi_status);
-               if (!(i&s_not_result_ready))
-               {
-                       OUT(CDo_sel_i_d,0);
-                       if (drvcmd[0]==CMDT_DISKINFO) m=l;
-                       else m=0;
-                       do
-                       {
-                               infobuf[m++]=inb(CDi_info);
-                               i=inb(CDi_status);
-                       }
-                       while (!(i&s_not_result_ready));
-                       for (j=0;j<m;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
-                       msgbuf[j*3]=0;
-                       msg(DBG_CMD,"cmd_out_T info response:%s\n", msgbuf);
-                       if (drvcmd[0]==CMDT_DISKINFO)
-                        {
-                                infobuf[0]=infobuf[l];
-                                if (infobuf[0]!=0x02) return (l); /* data length */
-                        }
-                       else if (infobuf[0]!=0x02) return (m); /* info length */
-                       do
-                       {
-                               ++recursion;
-                               if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (%02X): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", drvcmd[0], recursion);
-                               clr_cmdbuf();
-                               drvcmd[0]=CMDT_READ_ERR;
-                               j=cmd_out_T(); /* !!! recursive here !!! */
-                               --recursion;
-                               sbp_sleep(1);
-                       }
-                       while (j<0);
-                       current_drive->error_state=infobuf[2];
-                       current_drive->b3=infobuf[3];
-                       current_drive->b4=infobuf[4];
-                       if (current_drive->f_drv_error)
-                       {
-                               current_drive->f_drv_error=0;
-                               cc_DriveReset();
-                               current_drive->error_state=2;
-                       }
-                       return (-current_drive->error_state-400);
-               }
-               if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */
-               if ((teac==0)||(ntries<(CMDT_TRIES-5))) sbp_sleep(HZ/10);
-               else sbp_sleep(HZ/100);
-               if (ntries>(CMDT_TRIES-50)) continue;
-               msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1);
-       }
-       current_drive->f_drv_error=1;
-       cc_DriveReset();
-       current_drive->error_state=2;
-       return (-99);
-}
-/*==========================================================================*/
-static int cmd_out(void)
-{
-       int i=0;
-       
-       if (famT_drive) return(cmd_out_T());
-       
-       if (flags_cmd_out&f_putcmd)
-       { 
-               unsigned long flags;
-               for (i=0;i<7;i++)
-                       sprintf(&msgbuf[i*3], " %02X", drvcmd[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_CMD,"cmd_out:%s\n", msgbuf);
-               save_flags(flags); cli();
-               for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-               restore_flags(flags);
-       }
-       if (response_count!=0)
-       {
-               if (cmd_type!=0)
-               {
-                       if (sbpro_type==1) OUT(CDo_sel_i_d,1);
-                       msg(DBG_INF,"misleaded to try ResponseData.\n");
-                       if (sbpro_type==1) OUT(CDo_sel_i_d,0);
-                       return (-22);
-               }
-               else i=ResponseInfo();
-               if (i<0) return (i);
-       }
-       if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to CDi_stat_loop.\n");
-       if (flags_cmd_out&f_lopsta)
-       {
-               i=CDi_stat_loop();
-               if ((i<0)||!(i&s_attention)) return (-8);
-       }
-       if (!(flags_cmd_out&f_getsta)) goto LOC_229;
-       
- LOC_228:
-       if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadStatus.\n");
-       cc_ReadStatus();
-       
- LOC_229:
-       if (flags_cmd_out&f_ResponseStatus) 
-       {
-               if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to ResponseStatus.\n");
-               i=ResponseStatus();
-               /* builds status_bits, returns orig. status or p_busy_new */
-               if (i<0) return (i);
-               if (flags_cmd_out&(f_bit1|f_wait_if_busy))
-               {
-                       if (!st_check)
-                       {
-                               if ((flags_cmd_out&f_bit1)&&(i&p_success)) goto LOC_232;
-                               if ((!(flags_cmd_out&f_wait_if_busy))||(!st_busy)) goto LOC_228;
-                       }
-               }
-       }
- LOC_232:
-       if (!(flags_cmd_out&f_obey_p_check)) return (0);
-       if (!st_check) return (0);
-       if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadError.\n");
-       i=cc_ReadError();
-       if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cmd_out OK.\n");
-       msg(DBG_000,"cmd_out: cc_ReadError=%d\n", i);
-       return (i);
-}
-/*==========================================================================*/
-static int cc_Seek(u_int pos, char f_blk_msf)
-{
-       int i;
-       
-  clr_cmdbuf();
-       if (f_blk_msf>1) return (-3);
-       if (fam0V_drive)
-       {
-               drvcmd[0]=CMD0_SEEK;
-               if (f_blk_msf==1) pos=msf2blk(pos);
-               drvcmd[2]=(pos>>16)&0x00FF;
-               drvcmd[3]=(pos>>8)&0x00FF;
-               drvcmd[4]=pos&0x00FF;
-               if (fam0_drive)
-                 flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
-                       f_ResponseStatus | f_obey_p_check | f_bit1;
-               else
-                 flags_cmd_out = f_putcmd;
-       }
-       else if (fam1L_drive)
-       {
-               drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */
-               if (f_blk_msf==0) pos=blk2msf(pos);
-               drvcmd[1]=(pos>>16)&0x00FF;
-               drvcmd[2]=(pos>>8)&0x00FF;
-               drvcmd[3]=pos&0x00FF;
-               if (famL_drive)
-                       flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-               else
-                       flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_SEEK;
-               if (f_blk_msf==0) pos=blk2msf(pos);
-               drvcmd[2]=(pos>>24)&0x00FF;
-               drvcmd[3]=(pos>>16)&0x00FF;
-               drvcmd[4]=(pos>>8)&0x00FF;
-               drvcmd[5]=pos&0x00FF;
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (famT_drive)
-       {
-               drvcmd[0]=CMDT_SEEK;
-               if (f_blk_msf==1) pos=msf2blk(pos);
-               drvcmd[2]=(pos>>24)&0x00FF;
-               drvcmd[3]=(pos>>16)&0x00FF;
-               drvcmd[4]=(pos>>8)&0x00FF;
-               drvcmd[5]=pos&0x00FF;
-               current_drive->n_bytes=1;
-       }
-       response_count=0;
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_SpinUp(void)
-{
-       int i;
-       
-       msg(DBG_SPI,"SpinUp.\n");
-       current_drive->in_SpinUp = 1;
-       clr_cmdbuf();
-       if (fam0LV_drive)
-       {
-               drvcmd[0]=CMD0_SPINUP;
-               if (fam0L_drive)
-                 flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|
-                   f_ResponseStatus|f_obey_p_check|f_bit1;
-               else
-                 flags_cmd_out=f_putcmd;
-       }
-       else if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_SPINUP;
-               flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_TRAY_CTL;
-               drvcmd[4]=0x01; /* "spinup" */
-               flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               drvcmd[0]=CMDT_TRAY_CTL;
-               drvcmd[4]=0x03; /* "insert", it hopefully spins the drive up */
-       }
-       response_count=0;
-       i=cmd_out();
-       current_drive->in_SpinUp = 0;
-       return (i);
-}
-/*==========================================================================*/
-static int cc_SpinDown(void)
-{
-       int i;
-       
-       if (fam0_drive) return (0);
-       clr_cmdbuf();
-       response_count=0;
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_SPINDOWN;
-               flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_TRAY_CTL;
-               drvcmd[4]=0x02; /* "eject" */
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (famL_drive)
-       {
-               drvcmd[0]=CMDL_SPINDOWN;
-               drvcmd[1]=1;
-               flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-       }
-       else if (famV_drive)
-       {
-               drvcmd[0]=CMDV_SPINDOWN;
-               flags_cmd_out=f_putcmd;
-       }
-       else if (famT_drive)
-       {
-               drvcmd[0]=CMDT_TRAY_CTL;
-               drvcmd[4]=0x02; /* "eject" */
-       }
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_get_mode_T(void)
-{
-       int i;
-       
-       clr_cmdbuf();
-       response_count=10;
-       drvcmd[0]=CMDT_GETMODE;
-       drvcmd[4]=response_count;
-       i=cmd_out_T();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_set_mode_T(void)
-{
-       int i;
-       
-       clr_cmdbuf();
-       response_count=1;
-       drvcmd[0]=CMDT_SETMODE;
-       drvcmd[1]=current_drive->speed_byte;
-       drvcmd[2]=current_drive->frmsiz>>8;
-       drvcmd[3]=current_drive->frmsiz&0x0FF;
-       drvcmd[4]=current_drive->f_XA; /* 1: XA */
-       drvcmd[5]=current_drive->type_byte; /* 0, 1, 3 */
-       drvcmd[6]=current_drive->mode_xb_6;
-       drvcmd[7]=current_drive->mode_yb_7|current_drive->volume_control;
-       drvcmd[8]=current_drive->mode_xb_8;
-       drvcmd[9]=current_drive->delay;
-       i=cmd_out_T();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_prep_mode_T(void)
-{
-       int i, j;
-       
-       i=cc_get_mode_T();
-       if (i<0) return (i);
-       for (i=0;i<10;i++)
-               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf);
-       current_drive->speed_byte=0x02; /* 0x02: auto quad, 0x82: quad, 0x81: double, 0x80: single */
-       current_drive->frmsiz=make16(infobuf[2],infobuf[3]);
-       current_drive->f_XA=infobuf[4];
-       if (current_drive->f_XA==0) current_drive->type_byte=0;
-       else current_drive->type_byte=1;
-       current_drive->mode_xb_6=infobuf[6];
-       current_drive->mode_yb_7=1;
-       current_drive->mode_xb_8=infobuf[8];
-       current_drive->delay=0; /* 0, 1, 2, 3 */
-       j=cc_set_mode_T();
-       i=cc_get_mode_T();
-       for (i=0;i<10;i++)
-               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf);
-       return (j);
-}
-/*==========================================================================*/
-static int cc_SetSpeed(u_char speed, u_char x1, u_char x2)
-{
-       int i;
-       
-       if (fam0LV_drive) return (0);
-       clr_cmdbuf();
-       response_count=0;
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_SETMODE;
-               drvcmd[1]=0x03;
-               drvcmd[2]=speed;
-               drvcmd[3]=x1;
-               drvcmd[4]=x2;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_SETSPEED;
-               if (speed&speed_auto)
-               {
-                       drvcmd[2]=0xFF;
-                       drvcmd[3]=0xFF;
-               }
-               else
-               {
-                       drvcmd[2]=0;
-                       drvcmd[3]=150;
-               }
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               return (0);
-       }
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_SetVolume(void)
-{
-       int i;
-       u_char channel0,channel1,volume0,volume1;
-       u_char control0,value0,control1,value1;
-       
-       current_drive->diskstate_flags &= ~volume_bit;
-       clr_cmdbuf();
-       channel0=current_drive->vol_chan0;
-       volume0=current_drive->vol_ctrl0;
-       channel1=control1=current_drive->vol_chan1;
-       volume1=value1=current_drive->vol_ctrl1;
-       control0=value0=0;
-       
-       if (famV_drive) return (0);
-
-       if (((current_drive->drv_options&audio_mono)!=0)&&(current_drive->drv_type>=drv_211))
-       {
-               if ((volume0!=0)&&(volume1==0))
-               {
-                       volume1=volume0;
-                       channel1=channel0;
-               }
-               else if ((volume0==0)&&(volume1!=0))
-               {
-                       volume0=volume1;
-                       channel0=channel1;
-               }
-       }
-       if (channel0>1)
-       {
-               channel0=0;
-               volume0=0;
-       }
-       if (channel1>1)
-       {
-               channel1=1;
-               volume1=0;
-       }
-       
-       if (fam1_drive)
-       {
-               control0=channel0+1;
-               control1=channel1+1;
-               value0=(volume0>volume1)?volume0:volume1;
-               value1=value0;
-               if (volume0==0) control0=0;
-               if (volume1==0) control1=0;
-               drvcmd[0]=CMD1_SETMODE;
-               drvcmd[1]=0x05;
-               drvcmd[3]=control0;
-               drvcmd[4]=value0;
-               drvcmd[5]=control1;
-               drvcmd[6]=value1;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               control0=channel0+1;
-               control1=channel1+1;
-               value0=(volume0>volume1)?volume0:volume1;
-               value1=value0;
-               if (volume0==0) control0=0;
-               if (volume1==0) control1=0;
-               drvcmd[0]=CMD2_SETMODE;
-               drvcmd[1]=0x0E;
-               drvcmd[3]=control0;
-               drvcmd[4]=value0;
-               drvcmd[5]=control1;
-               drvcmd[6]=value1;
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (famL_drive)
-       {
-               if ((volume0==0)||(channel0!=0)) control0 |= 0x80;
-               if ((volume1==0)||(channel1!=1)) control0 |= 0x40;
-               if (volume0|volume1) value0=0x80;
-               drvcmd[0]=CMDL_SETMODE;
-               drvcmd[1]=0x03;
-               drvcmd[4]=control0;
-               drvcmd[5]=value0;
-               flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-       }
-       else if (fam0_drive) /* different firmware levels */
-       {
-               if (current_drive->drv_type>=drv_300)
-               {
-                       control0=volume0&0xFC;
-                       value0=volume1&0xFC;
-                       if ((volume0!=0)&&(volume0<4)) control0 |= 0x04;
-                       if ((volume1!=0)&&(volume1<4)) value0 |= 0x04;
-                       if (channel0!=0) control0 |= 0x01;
-                       if (channel1==1) value0 |= 0x01;
-               }
-               else
-               {
-                       value0=(volume0>volume1)?volume0:volume1;
-                       if (current_drive->drv_type<drv_211)
-                       {
-                               if (channel0!=0)
-                               {
-                                       i=channel1;
-                                       channel1=channel0;
-                                       channel0=i;
-                                       i=volume1;
-                                       volume1=volume0;
-                                       volume0=i;
-                               }
-                               if (channel0==channel1)
-                               {
-                                       if (channel0==0)
-                                       {
-                                               channel1=1;
-                                               volume1=0;
-                                               volume0=value0;
-                                       }
-                                       else
-                                       {
-                                               channel0=0;
-                                               volume0=0;
-                                               volume1=value0;
-                                       }
-                               }
-                       }
-                       
-                       if ((volume0!=0)&&(volume1!=0))
-                       {
-                               if (volume0==0xFF) volume1=0xFF;
-                               else if (volume1==0xFF) volume0=0xFF;
-                       }
-                       else if (current_drive->drv_type<drv_201) volume0=volume1=value0;
-                       
-                       if (current_drive->drv_type>=drv_201)
-                       {
-                               if (volume0==0) control0 |= 0x80;
-                               if (volume1==0) control0 |= 0x40;
-                       }
-                       if (current_drive->drv_type>=drv_211)
-                       {
-                               if (channel0!=0) control0 |= 0x20;
-                               if (channel1!=1) control0 |= 0x10;
-                       }
-               }
-               drvcmd[0]=CMD0_SETMODE;
-               drvcmd[1]=0x83;
-               drvcmd[4]=control0;
-               drvcmd[5]=value0;
-               flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               current_drive->volume_control=0;
-               if (!volume0) current_drive->volume_control|=0x10;
-               if (!volume1) current_drive->volume_control|=0x20;
-               i=cc_prep_mode_T();
-               if (i<0) return (i);
-       }
-       if (!famT_drive)
-       {
-               response_count=0;
-               i=cmd_out();
-               if (i<0) return (i);
-       }
-       current_drive->diskstate_flags |= volume_bit;
-       return (0);
-}
-/*==========================================================================*/
-static int GetStatus(void)
-{
-       int i;
-       
-       if (famT_drive) return (0);
-       flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check;
-       response_count=0;
-       cmd_type=0;
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_DriveReset(void)
-{
-       int i;
-       
-       msg(DBG_RES,"cc_DriveReset called.\n");
-       clr_cmdbuf();
-       response_count=0;
-       if (fam0LV_drive) OUT(CDo_reset,0x00);
-       else if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_RESET;
-               flags_cmd_out=f_putcmd;
-               i=cmd_out();
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_RESET;
-               flags_cmd_out=f_putcmd;
-               i=cmd_out();
-               OUT(CDo_reset,0x00);
-       }
-       else if (famT_drive)
-       {
-               OUT(CDo_sel_i_d,0);
-               OUT(CDo_enable,current_drive->drv_sel);
-               OUT(CDo_command,CMDT_RESET);
-               for (i=1;i<10;i++) OUT(CDo_command,0);
-       }
-       if (fam0LV_drive) sbp_sleep(5*HZ); /* wait 5 seconds */
-       else sbp_sleep(1*HZ); /* wait a second */
-#if 1
-       if (famT_drive)
-       {
-               msg(DBG_TEA, "================CMDT_RESET given=================.\n");
-               sbp_sleep(3*HZ);
-       }
-#endif /* 1 */ 
-       flush_status();
-       i=GetStatus();
-       if (i<0) return i;
-       if (!famT_drive)
-               if (current_drive->error_byte!=aud_12) return -501;
-       return (0);
-}
-
-/*==========================================================================*/
-static int SetSpeed(void)
-{
-       int i, speed;
-       
-       if (!(current_drive->drv_options&(speed_auto|speed_300|speed_150))) return (0);
-       speed=speed_auto;
-       if (!(current_drive->drv_options&speed_auto))
-       {
-               speed |= speed_300;
-               if (!(current_drive->drv_options&speed_300)) speed=0;
-       }
-       i=cc_SetSpeed(speed,0,0);
-       return (i);
-}
-
-static void switch_drive(struct sbpcd_drive *);
-
-static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed)
-{
-       struct sbpcd_drive *p = cdi->handle;
-       if (p != current_drive)
-               switch_drive(p);
-
-       return cc_SetSpeed(speed == 2 ? speed_300 : speed_150, 0, 0);
-}
-
-/*==========================================================================*/
-static int DriveReset(void)
-{
-       int i;
-       
-       i=cc_DriveReset();
-       if (i<0) return (-22);
-       do
-       {
-               i=GetStatus();
-               if ((i<0)&&(i!=-ERR_DISKCHANGE)) {
-                       return (-2); /* from sta2err */
-               }
-               if (!st_caddy_in) break;
-               sbp_sleep(1);
-       }
-       while (!st_diskok);
-#if 000
-       current_drive->CD_changed=1;
-#endif
-       if ((st_door_closed) && (st_caddy_in))
-       {
-               i=DiskInfo();
-               if (i<0) return (-23);
-       }
-       return (0);
-}
-
-static int sbpcd_reset(struct cdrom_device_info *cdi)
-{
-       struct sbpcd_drive *p = cdi->handle;
-       if (p != current_drive)
-               switch_drive(p);
-       return DriveReset();
-}
-
-/*==========================================================================*/
-static int cc_PlayAudio(int pos_audio_start,int pos_audio_end)
-{
-       int i, j, n;
-       
-       if (current_drive->audio_state==audio_playing) return (-EINVAL);
-       clr_cmdbuf();
-       response_count=0;
-       if (famLV_drive)
-       {
-               drvcmd[0]=CMDL_PLAY;
-               i=msf2blk(pos_audio_start);
-               n=msf2blk(pos_audio_end)+1-i;
-               drvcmd[1]=(i>>16)&0x00FF;
-               drvcmd[2]=(i>>8)&0x00FF;
-               drvcmd[3]=i&0x00FF;
-               drvcmd[4]=(n>>16)&0x00FF;
-               drvcmd[5]=(n>>8)&0x00FF;
-               drvcmd[6]=n&0x00FF;
-               if (famL_drive)
-               flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
-                       f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
-               else
-                 flags_cmd_out = f_putcmd;
-       }
-       else
-       {
-               j=1;
-               if (fam1_drive)
-               {
-                       drvcmd[0]=CMD1_PLAY_MSF;
-                       flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus |
-                               f_obey_p_check | f_wait_if_busy;
-               }
-               else if (fam2_drive)
-               {
-                       drvcmd[0]=CMD2_PLAY_MSF;
-                       flags_cmd_out = f_putcmd | f_ResponseStatus | f_obey_p_check;
-               }
-               else if (famT_drive)
-               {
-                       drvcmd[0]=CMDT_PLAY_MSF;
-                       j=3;
-                       response_count=1;
-               }
-               else if (fam0_drive)
-               {
-                       drvcmd[0]=CMD0_PLAY_MSF;
-                       flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
-                               f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
-               }
-               drvcmd[j]=(pos_audio_start>>16)&0x00FF;
-               drvcmd[j+1]=(pos_audio_start>>8)&0x00FF;
-               drvcmd[j+2]=pos_audio_start&0x00FF;
-               drvcmd[j+3]=(pos_audio_end>>16)&0x00FF;
-               drvcmd[j+4]=(pos_audio_end>>8)&0x00FF;
-               drvcmd[j+5]=pos_audio_end&0x00FF;
-       }
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_Pause_Resume(int pau_res)
-{
-       int i;
-       
-       clr_cmdbuf();
-       response_count=0;
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_PAU_RES;
-               if (pau_res!=1) drvcmd[1]=0x80;
-               flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_PAU_RES;
-               if (pau_res!=1) drvcmd[2]=0x01;
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (fam0LV_drive)
-       {
-               drvcmd[0]=CMD0_PAU_RES;
-               if (pau_res!=1) drvcmd[1]=0x80;
-               if (famL_drive)
-                       flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|
-                               f_obey_p_check|f_bit1;
-               else if (famV_drive)
-                 flags_cmd_out=f_putcmd;
-               else
-                       flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|
-                               f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               if (pau_res==3) return (cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end));
-               else if (pau_res==1) drvcmd[0]=CMDT_PAUSE;
-               else return (-56);
-       }
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int cc_LockDoor(char lock)
-{
-       int i;
-       
-       if (fam0_drive) return (0);
-       msg(DBG_LCK,"cc_LockDoor: %d (drive %d)\n", lock, current_drive - D_S);
-       msg(DBG_LCS,"p_door_locked bit %d before\n", st_door_locked);
-       clr_cmdbuf();
-       response_count=0;
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_LOCK_CTL;
-               if (lock==1) drvcmd[1]=0x01;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_LOCK_CTL;
-               if (lock==1) drvcmd[4]=0x01;
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (famLV_drive)
-       {
-               drvcmd[0]=CMDL_LOCK_CTL;
-               if (lock==1) drvcmd[1]=0x01;
-               if (famL_drive)
-                 flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-               else
-                 flags_cmd_out=f_putcmd;
-       }
-       else if (famT_drive)
-       {
-               drvcmd[0]=CMDT_LOCK_CTL;
-               if (lock==1) drvcmd[4]=0x01;
-       }
-       i=cmd_out();
-       msg(DBG_LCS,"p_door_locked bit %d after\n", st_door_locked);
-       return (i);
-}
-/*==========================================================================*/
-/*==========================================================================*/
-static int UnLockDoor(void)
-{
-       int i,j;
-       
-       j=20;
-       do
-       {
-               i=cc_LockDoor(0);
-               --j;
-               sbp_sleep(1);
-       }
-       while ((i<0)&&(j));
-       if (i<0)
-       {
-               cc_DriveReset();
-               return -84;
-       }
-       return (0);
-}
-/*==========================================================================*/
-static int LockDoor(void)
-{
-       int i,j;
-       
-       j=20;
-       do
-       {
-               i=cc_LockDoor(1);
-               --j;
-               sbp_sleep(1);
-       }
-       while ((i<0)&&(j));
-       if (j==0)
-       {               
-               cc_DriveReset();
-               j=20;
-               do
-               {
-                       i=cc_LockDoor(1);
-                       --j;
-                       sbp_sleep(1);
-               }
-               while ((i<0)&&(j));
-       }
-       return (i);
-}
-
-static int sbpcd_lock_door(struct cdrom_device_info *cdi, int lock)
-{
-  return lock ? LockDoor() : UnLockDoor();
-}
-
-/*==========================================================================*/
-static int cc_CloseTray(void)
-{
-       int i;
-       
-       if (fam0_drive) return (0);
-       msg(DBG_LCK,"cc_CloseTray (drive %d)\n", current_drive - D_S);
-       msg(DBG_LCS,"p_door_closed bit %d before\n", st_door_closed);
-       
-       clr_cmdbuf();
-       response_count=0;
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_TRAY_CTL;
-               flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_TRAY_CTL;
-               drvcmd[1]=0x01;
-               drvcmd[4]=0x03; /* "insert" */
-               flags_cmd_out=f_putcmd|f_ResponseStatus;
-       }
-       else if (famLV_drive)
-       {
-               drvcmd[0]=CMDL_TRAY_CTL;
-               if (famLV_drive)
-                 flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|
-                       f_ResponseStatus|f_obey_p_check|f_bit1;
-               else
-                 flags_cmd_out=f_putcmd;
-       }
-       else if (famT_drive)
-       {
-               drvcmd[0]=CMDT_TRAY_CTL;
-               drvcmd[4]=0x03; /* "insert" */
-       }
-       i=cmd_out();
-       msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed);
-
-       i=cc_ReadError();
-       flags_cmd_out |= f_respo2;
-       cc_ReadStatus(); /* command: give 1-byte status */
-       i=ResponseStatus();
-       if (famT_drive&&(i<0))
-       {
-               cc_DriveReset();
-               i=ResponseStatus();
-#if 0
-                sbp_sleep(HZ);
-#endif /* 0 */ 
-               i=ResponseStatus();
-       }
-       if (i<0)
-       {
-               msg(DBG_INF,"sbpcd cc_CloseTray: ResponseStatus timed out (%d).\n",i);
-       }
-       if (!(famT_drive))
-       {
-               if (!st_spinning)
-               {
-                       cc_SpinUp();
-                       if (st_check) i=cc_ReadError();
-                       flags_cmd_out |= f_respo2;
-                       cc_ReadStatus();
-                       i=ResponseStatus();
-               } else {
-               }
-       }
-       i=DiskInfo();
-       return (i);
-}
-
-static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position)
-{
-       int retval=0;
-       switch_drive(cdi->handle);
-       /* DUH! --AJK */
-       if(current_drive->CD_changed != 0xFF) {
-               current_drive->CD_changed=0xFF;
-               current_drive->diskstate_flags &= ~cd_size_bit;
-       }
-       if (position == 1) {
-               cc_SpinDown();
-       } else {
-               retval=cc_CloseTray();
-       }
-  return retval;
-}
-
-/*==========================================================================*/
-static int cc_ReadSubQ(void)
-{
-       int i,j;
-
-       current_drive->diskstate_flags &= ~subq_bit;
-       for (j=255;j>0;j--)
-       {
-               clr_cmdbuf();
-               if (fam1_drive)
-               {
-                       drvcmd[0]=CMD1_READSUBQ;
-                       flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-                       response_count=11;
-               }
-               else if (fam2_drive)
-               {
-                       drvcmd[0]=CMD2_READSUBQ;
-                       drvcmd[1]=0x02;
-                       drvcmd[3]=0x01;
-                       flags_cmd_out=f_putcmd;
-                       response_count=10;
-               }
-               else if (fam0LV_drive)
-               {
-                       drvcmd[0]=CMD0_READSUBQ;
-                       drvcmd[1]=0x02;
-                       if (famLV_drive)
-                               flags_cmd_out=f_putcmd;
-                       else
-                               flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-                       response_count=13;
-               }
-               else if (famT_drive)
-               {
-                       response_count=12;
-                       drvcmd[0]=CMDT_READSUBQ;
-                       drvcmd[1]=0x02;
-                       drvcmd[2]=0x40;
-                       drvcmd[3]=0x01;
-                       drvcmd[8]=response_count;
-               }
-               i=cmd_out();
-               if (i<0) return (i);
-               for (i=0;i<response_count;i++)
-               {
-                       sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-                       msgbuf[i*3]=0;
-                       msg(DBG_SQ1,"cc_ReadSubQ:%s\n", msgbuf);
-               }
-               if (famT_drive) break;
-               if (infobuf[0]!=0) break;
-               if ((!st_spinning) || (j==1))
-               {
-                       current_drive->SubQ_ctl_adr=current_drive->SubQ_trk=current_drive->SubQ_pnt_idx=current_drive->SubQ_whatisthis=0;
-                       current_drive->SubQ_run_tot=current_drive->SubQ_run_trk=0;
-                       return (0);
-               }
-       }
-       if (famT_drive) current_drive->SubQ_ctl_adr=infobuf[1];
-       else current_drive->SubQ_ctl_adr=swap_nibbles(infobuf[1]);
-       current_drive->SubQ_trk=byt2bcd(infobuf[2]);
-       current_drive->SubQ_pnt_idx=byt2bcd(infobuf[3]);
-       if (fam0LV_drive) i=5;
-       else if (fam12_drive) i=4;
-       else if (famT_drive) i=8;
-       current_drive->SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
-       i=7;
-       if (fam0LV_drive) i=9;
-       else if (fam12_drive) i=7;
-       else if (famT_drive) i=4;
-       current_drive->SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
-       current_drive->SubQ_whatisthis=infobuf[i+3];
-       current_drive->diskstate_flags |= subq_bit;
-       return (0);
-}
-/*==========================================================================*/
-static int cc_ModeSense(void)
-{
-       int i;
-       
-       if (fam2_drive) return (0);
-       if (famV_drive) return (0);
-       current_drive->diskstate_flags &= ~frame_size_bit;
-       clr_cmdbuf();
-       if (fam1_drive)
-       {
-               response_count=5;
-               drvcmd[0]=CMD1_GETMODE;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam0L_drive)
-       {
-               response_count=2;
-               drvcmd[0]=CMD0_GETMODE;
-               if (famL_drive) flags_cmd_out=f_putcmd;
-               else flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               response_count=10;
-               drvcmd[0]=CMDT_GETMODE;
-               drvcmd[4]=response_count;
-       }
-       i=cmd_out();
-       if (i<0) return (i);
-       i=0;
-       current_drive->sense_byte=0;
-       if (fam1_drive) current_drive->sense_byte=infobuf[i++];
-       else if (famT_drive)
-       {
-               if (infobuf[4]==0x01) current_drive->xa_byte=0x20;
-               else current_drive->xa_byte=0;
-               i=2;
-       }
-       current_drive->frame_size=make16(infobuf[i],infobuf[i+1]);
-       for (i=0;i<response_count;i++)
-               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_XA1,"cc_ModeSense:%s\n", msgbuf);
-       
-       current_drive->diskstate_flags |= frame_size_bit;
-       return (0);
-}
-/*==========================================================================*/
-/*==========================================================================*/
-static int cc_ModeSelect(int framesize)
-{
-       int i;
-       
-       if (fam2_drive) return (0);
-       if (famV_drive) return (0);
-       current_drive->diskstate_flags &= ~frame_size_bit;
-       clr_cmdbuf();
-       current_drive->frame_size=framesize;
-       if (framesize==CD_FRAMESIZE_RAW) current_drive->sense_byte=0x82;
-       else current_drive->sense_byte=0x00;
-       
-       msg(DBG_XA1,"cc_ModeSelect: %02X %04X\n",
-           current_drive->sense_byte, current_drive->frame_size);
-       
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_SETMODE;
-               drvcmd[1]=0x00;
-               drvcmd[2]=current_drive->sense_byte;
-               drvcmd[3]=(current_drive->frame_size>>8)&0xFF;
-               drvcmd[4]=current_drive->frame_size&0xFF;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam0L_drive)
-       {
-               drvcmd[0]=CMD0_SETMODE;
-               drvcmd[1]=0x00;
-               drvcmd[2]=(current_drive->frame_size>>8)&0xFF;
-               drvcmd[3]=current_drive->frame_size&0xFF;
-               drvcmd[4]=0x00;
-               if(famL_drive)
-                       flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check;
-               else
-                       flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               return (-1);
-       }
-       response_count=0;
-       i=cmd_out();
-       if (i<0) return (i);
-       current_drive->diskstate_flags |= frame_size_bit;
-       return (0);
-}
-/*==========================================================================*/
-static int cc_GetVolume(void)
-{
-       int i;
-       u_char switches;
-       u_char chan0=0;
-       u_char vol0=0;
-       u_char chan1=1;
-       u_char vol1=0;
-       
-       if (famV_drive) return (0);
-       current_drive->diskstate_flags &= ~volume_bit;
-       clr_cmdbuf();
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_GETMODE;
-               drvcmd[1]=0x05;
-               response_count=5;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_GETMODE;
-               drvcmd[1]=0x0E;
-               response_count=5;
-               flags_cmd_out=f_putcmd;
-       }
-       else if (fam0L_drive)
-       {
-               drvcmd[0]=CMD0_GETMODE;
-               drvcmd[1]=0x03;
-               response_count=2;
-               if(famL_drive)
-                       flags_cmd_out=f_putcmd;
-               else
-                       flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               i=cc_get_mode_T();
-               if (i<0) return (i);
-       }
-       if (!famT_drive)
-       {
-               i=cmd_out();
-               if (i<0) return (i);
-       }
-       if (fam1_drive)
-       {
-               chan0=infobuf[1]&0x0F;
-               vol0=infobuf[2];
-               chan1=infobuf[3]&0x0F;
-               vol1=infobuf[4];
-               if (chan0==0)
-               {
-                       chan0=1;
-                       vol0=0;
-               }
-               if (chan1==0)
-               {
-                       chan1=2;
-                       vol1=0;
-               }
-               chan0 >>= 1;
-               chan1 >>= 1;
-       }
-       else if (fam2_drive)
-       {
-               chan0=infobuf[1];
-               vol0=infobuf[2];
-               chan1=infobuf[3];
-               vol1=infobuf[4];
-       }
-       else if (famL_drive)
-       {
-               chan0=0;
-               chan1=1;
-               vol0=vol1=infobuf[1];
-               switches=infobuf[0];
-               if ((switches&0x80)!=0) chan0=1;
-               if ((switches&0x40)!=0) chan1=0;
-       }
-       else if (fam0_drive) /* different firmware levels */
-       {
-               chan0=0;
-               chan1=1;
-               vol0=vol1=infobuf[1];
-               if (current_drive->drv_type>=drv_201)
-               {
-                       if (current_drive->drv_type<drv_300)
-                       {
-                               switches=infobuf[0];
-                               if ((switches&0x80)!=0) vol0=0;
-                               if ((switches&0x40)!=0) vol1=0;
-                               if (current_drive->drv_type>=drv_211)
-                               {
-                                       if ((switches&0x20)!=0) chan0=1;
-                                       if ((switches&0x10)!=0) chan1=0;
-                               }
-                       }
-                       else
-                       {
-                               vol0=infobuf[0];
-                               if ((vol0&0x01)!=0) chan0=1;
-                               if ((vol1&0x01)==0) chan1=0;
-                               vol0 &= 0xFC;
-                               vol1 &= 0xFC;
-                               if (vol0!=0) vol0 += 3;
-                               if (vol1!=0) vol1 += 3;
-                       }
-               }
-       }
-       else if (famT_drive)
-       {
-               current_drive->volume_control=infobuf[7];
-               chan0=0;
-               chan1=1;
-               if (current_drive->volume_control&0x10) vol0=0;
-               else vol0=0xff;
-               if (current_drive->volume_control&0x20) vol1=0;
-               else vol1=0xff;
-       }
-       current_drive->vol_chan0=chan0;
-       current_drive->vol_ctrl0=vol0;
-       current_drive->vol_chan1=chan1;
-       current_drive->vol_ctrl1=vol1;
-#if 000
-       current_drive->vol_chan2=2;
-       current_drive->vol_ctrl2=0xFF;
-       current_drive->vol_chan3=3;
-       current_drive->vol_ctrl3=0xFF;
-#endif /*  000 */
-       current_drive->diskstate_flags |= volume_bit;
-       return (0);
-}
-/*==========================================================================*/
-static int cc_ReadCapacity(void)
-{
-       int i, j;
-       
-       if (fam2_drive) return (0); /* some firmware lacks this command */
-       if (famLV_drive) return (0); /* some firmware lacks this command */
-       if (famT_drive) return (0); /* done with cc_ReadTocDescr() */
-       current_drive->diskstate_flags &= ~cd_size_bit;
-       for (j=3;j>0;j--)
-       {
-               clr_cmdbuf();
-               if (fam1_drive)
-               {
-                       drvcmd[0]=CMD1_CAPACITY;
-                       response_count=5;
-                       flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-               }
-#if 00
-               else if (fam2_drive)
-               {
-                       drvcmd[0]=CMD2_CAPACITY;
-                       response_count=8;
-                       flags_cmd_out=f_putcmd;
-               }
-#endif
-               else if (fam0_drive)
-               {
-                       drvcmd[0]=CMD0_CAPACITY;
-                       response_count=5;
-                       flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-               }
-               i=cmd_out();
-               if (i>=0) break;
-               msg(DBG_000,"cc_ReadCapacity: cmd_out: err %d\n", i);
-               cc_ReadError();
-       }
-       if (j==0) return (i);
-       if (fam1_drive) current_drive->CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_MSF_OFFSET;
-       else if (fam0_drive) current_drive->CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2]));
-#if 00
-       else if (fam2_drive) current_drive->CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3]));
-#endif
-       current_drive->diskstate_flags |= cd_size_bit;
-       msg(DBG_000,"cc_ReadCapacity: %d frames.\n", current_drive->CDsize_frm);
-       return (0);
-}
-/*==========================================================================*/
-static int cc_ReadTocDescr(void)
-{
-       int i;
-       
-       current_drive->diskstate_flags &= ~toc_bit;
-       clr_cmdbuf();
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_DISKINFO;
-               response_count=6;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam0LV_drive)
-       {
-               drvcmd[0]=CMD0_DISKINFO;
-               response_count=6;
-               if(famLV_drive)
-                       flags_cmd_out=f_putcmd;
-               else
-                       flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               /* possibly longer timeout periods necessary */
-               current_drive->f_multisession=0;
-               drvcmd[0]=CMD2_DISKINFO;
-               drvcmd[1]=0x02;
-               drvcmd[2]=0xAB;
-               drvcmd[3]=0xFF; /* session */
-               response_count=8;
-               flags_cmd_out=f_putcmd;
-       }
-       else if (famT_drive)
-       {
-               current_drive->f_multisession=0;
-               response_count=12;
-               drvcmd[0]=CMDT_DISKINFO;
-               drvcmd[1]=0x02;
-               drvcmd[6]=CDROM_LEADOUT;
-               drvcmd[8]=response_count;
-               drvcmd[9]=0x00;
-       }
-       i=cmd_out();
-       if (i<0) return (i);
-       if ((famT_drive)&&(i<response_count)) return (-100-i);
-       if ((fam1_drive)||(fam2_drive)||(fam0LV_drive))
-               current_drive->xa_byte=infobuf[0];
-       if (fam2_drive)
-       {
-               current_drive->first_session=infobuf[1];
-               current_drive->last_session=infobuf[2];
-               current_drive->n_first_track=infobuf[3];
-               current_drive->n_last_track=infobuf[4];
-               if (current_drive->first_session!=current_drive->last_session)
-               {
-                       current_drive->f_multisession=1;
-                       current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7])));
-               }
-#if 0
-               if (current_drive->first_session!=current_drive->last_session)
-               {
-                       if (current_drive->last_session<=20)
-                               zwanzig=current_drive->last_session+1;
-                       else zwanzig=20;
-                       for (count=current_drive->first_session;count<zwanzig;count++)
-                       {
-                               drvcmd[0]=CMD2_DISKINFO;
-                               drvcmd[1]=0x02;
-                               drvcmd[2]=0xAB;
-                               drvcmd[3]=count;
-                               response_count=8;
-                               flags_cmd_out=f_putcmd;
-                               i=cmd_out();
-                               if (i<0) return (i);
-                               current_drive->msf_multi_n[count]=make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7]));
-                       }
-                       current_drive->diskstate_flags |= multisession_bit;
-               }
-#endif
-               drvcmd[0]=CMD2_DISKINFO;
-               drvcmd[1]=0x02;
-               drvcmd[2]=0xAA;
-               drvcmd[3]=0xFF;
-               response_count=5;
-               flags_cmd_out=f_putcmd;
-               i=cmd_out();
-               if (i<0) return (i);
-               current_drive->size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4]));
-               current_drive->size_blk=msf2blk(current_drive->size_msf);
-               current_drive->CDsize_frm=current_drive->size_blk+1;
-       }
-       else if (famT_drive)
-       {
-               current_drive->size_msf=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11]));
-               current_drive->size_blk=msf2blk(current_drive->size_msf);
-               current_drive->CDsize_frm=current_drive->size_blk+1;
-               current_drive->n_first_track=infobuf[2];
-               current_drive->n_last_track=infobuf[3];
-       }
-       else
-       {
-               current_drive->n_first_track=infobuf[1];
-               current_drive->n_last_track=infobuf[2];
-               current_drive->size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5]));
-               current_drive->size_blk=msf2blk(current_drive->size_msf);
-               if (famLV_drive) current_drive->CDsize_frm=current_drive->size_blk+1;
-       }
-       current_drive->diskstate_flags |= toc_bit;
-       msg(DBG_TOC,"TocDesc: xa %02X firstt %02X lastt %02X size %08X firstses %02X lastsess %02X\n",
-           current_drive->xa_byte,
-           current_drive->n_first_track,
-           current_drive->n_last_track,
-           current_drive->size_msf,
-           current_drive->first_session,
-           current_drive->last_session);
-       return (0);
-}
-/*==========================================================================*/
-static int cc_ReadTocEntry(int num)
-{
-       int i;
-       
-       clr_cmdbuf();
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_READTOC;
-               drvcmd[2]=num;
-               response_count=8;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam2_drive)
-       {
-               /* possibly longer timeout periods necessary */
-               drvcmd[0]=CMD2_DISKINFO;
-               drvcmd[1]=0x02;
-               drvcmd[2]=num;
-               response_count=5;
-               flags_cmd_out=f_putcmd;
-       }
-       else if (fam0LV_drive)
-       {
-               drvcmd[0]=CMD0_READTOC;
-               drvcmd[1]=0x02;
-               drvcmd[2]=num;
-               response_count=8;
-               if (famLV_drive)
-                       flags_cmd_out=f_putcmd;
-               else
-                 flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (famT_drive)
-       {
-               response_count=12;
-               drvcmd[0]=CMDT_DISKINFO;
-               drvcmd[1]=0x02;
-               drvcmd[6]=num;
-               drvcmd[8]=response_count;
-               drvcmd[9]=0x00;
-       }
-       i=cmd_out();
-       if (i<0) return (i);
-       if ((famT_drive)&&(i<response_count)) return (-100-i);
-       if ((fam1_drive)||(fam0LV_drive))
-       {
-               current_drive->TocEnt_nixbyte=infobuf[0];
-               i=1;
-       }
-       else if (fam2_drive) i=0;
-       else if (famT_drive) i=5;
-       current_drive->TocEnt_ctl_adr=swap_nibbles(infobuf[i++]);
-       if ((fam1_drive)||(fam0L_drive))
-       {
-               current_drive->TocEnt_number=infobuf[i++];
-               current_drive->TocEnt_format=infobuf[i];
-       }
-       else
-         {
-           current_drive->TocEnt_number=num;
-           current_drive->TocEnt_format=0;
-         }
-       if (fam1_drive) i=4;
-       else if (fam0LV_drive) i=5;
-       else if (fam2_drive) i=2;
-       else if (famT_drive) i=9;
-       current_drive->TocEnt_address=make32(make16(0,infobuf[i]),
-                                    make16(infobuf[i+1],infobuf[i+2]));
-       for (i=0;i<response_count;i++)
-               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_ECS,"TocEntry:%s\n", msgbuf);
-       msg(DBG_TOC,"TocEntry: %02X %02X %02X %02X %08X\n",
-           current_drive->TocEnt_nixbyte, current_drive->TocEnt_ctl_adr,
-           current_drive->TocEnt_number, current_drive->TocEnt_format,
-           current_drive->TocEnt_address);
-       return (0);
-}
-/*==========================================================================*/
-static int cc_ReadPacket(void)
-{
-       int i;
-       
-       clr_cmdbuf();
-       drvcmd[0]=CMD0_PACKET;
-       drvcmd[1]=response_count;
-       if(famL_drive) flags_cmd_out=f_putcmd;
-       else if (fam01_drive)
-               flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-       else if (fam2_drive) return (-1); /* not implemented yet */
-       else if (famT_drive)
-       {
-               return (-1);
-       }
-       i=cmd_out();
-       return (i);
-}
-/*==========================================================================*/
-static int convert_UPC(u_char *p)
-{
-       int i;
-       
-       p++;
-       if (fam0L_drive) p[13]=0;
-       for (i=0;i<7;i++)
-       {
-               if (fam1_drive) current_drive->UPC_buf[i]=swap_nibbles(*p++);
-               else if (fam0L_drive)
-               {
-                       current_drive->UPC_buf[i]=((*p++)<<4)&0xFF;
-                       current_drive->UPC_buf[i] |= *p++;
-               }
-               else if (famT_drive)
-               {
-                       return (-1);
-               }
-               else /* CD200 */
-               {
-                       return (-1);
-               }
-       }
-       current_drive->UPC_buf[6] &= 0xF0;
-       return (0);
-}
-/*==========================================================================*/
-static int cc_ReadUPC(void)
-{
-       int i;
-#if TEST_UPC
-       int block, checksum;
-#endif /* TEST_UPC */ 
-       
-       if (fam2_drive) return (0); /* not implemented yet */
-       if (famT_drive) return (0); /* not implemented yet */
-       if (famV_drive) return (0); /* not implemented yet */
-#if 1
-       if (fam0_drive) return (0); /* but it should work */
-#endif
-       
-       current_drive->diskstate_flags &= ~upc_bit;
-#if TEST_UPC
-       for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++)
-       {
-#endif /* TEST_UPC */ 
-               clr_cmdbuf();
-               if (fam1_drive)
-               {
-                       drvcmd[0]=CMD1_READ_UPC;
-#if TEST_UPC
-                       drvcmd[1]=(block>>16)&0xFF;
-                       drvcmd[2]=(block>>8)&0xFF;
-                       drvcmd[3]=block&0xFF;
-#endif /* TEST_UPC */ 
-                       response_count=8;
-                       flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-               }
-               else if (fam0L_drive)
-               {
-                       drvcmd[0]=CMD0_READ_UPC;
-#if TEST_UPC
-                       drvcmd[2]=(block>>16)&0xFF;
-                       drvcmd[3]=(block>>8)&0xFF;
-                       drvcmd[4]=block&0xFF;
-#endif /* TEST_UPC */ 
-                       response_count=0;
-                       flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-               }
-               else if (fam2_drive)
-               {
-                       return (-1);
-               }
-               else if (famT_drive)
-               {
-                       return (-1);
-               }
-               i=cmd_out();
-               if (i<0)
-               {
-                       msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i);
-                       return (i);
-               }
-               if (fam0L_drive)
-               {
-                       response_count=16;
-                       if (famL_drive) flags_cmd_out=f_putcmd;
-                       i=cc_ReadPacket();
-                       if (i<0)
-                       {
-                               msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i);
-                               return (i);
-                       }
-               }
-#if TEST_UPC
-               checksum=0;
-#endif /* TEST_UPC */ 
-               for (i=0;i<(fam1_drive?8:16);i++)
-               {
-#if TEST_UPC
-                       checksum |= infobuf[i];
-#endif /* TEST_UPC */ 
-                       sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-               }
-               msgbuf[i*3]=0;
-               msg(DBG_UPC,"UPC info:%s\n", msgbuf);
-#if TEST_UPC
-               if ((checksum&0x7F)!=0) break;
-       }
-#endif /* TEST_UPC */ 
-       current_drive->UPC_ctl_adr=0;
-       if (fam1_drive) i=0;
-       else i=2;
-       if ((infobuf[i]&0x80)!=0)
-       {
-               convert_UPC(&infobuf[i]);
-               current_drive->UPC_ctl_adr = (current_drive->TocEnt_ctl_adr & 0xF0) | 0x02;
-       }
-       for (i=0;i<7;i++)
-               sprintf(&msgbuf[i*3], " %02X", current_drive->UPC_buf[i]);
-       sprintf(&msgbuf[i*3], " (%02X)", current_drive->UPC_ctl_adr);
-       msgbuf[i*3+5]=0;
-       msg(DBG_UPC,"UPC code:%s\n", msgbuf);
-       current_drive->diskstate_flags |= upc_bit;
-       return (0);
-}
-
-static int sbpcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
-{
-       int i;
-       unsigned char *mcnp = mcn->medium_catalog_number;
-       unsigned char *resp;
-
-       current_drive->diskstate_flags &= ~upc_bit;
-       clr_cmdbuf();
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_READ_UPC;
-               response_count=8;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-       }
-       else if (fam0L_drive)
-       {
-               drvcmd[0]=CMD0_READ_UPC;
-               response_count=0;
-               flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-       }
-       else if (fam2_drive)
-       {
-               return (-1);
-       }
-       else if (famT_drive)
-       {
-               return (-1);
-       }
-       i=cmd_out();
-       if (i<0)
-       {
-               msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i);
-               return (i);
-       }
-       if (fam0L_drive)
-       {
-               response_count=16;
-               if (famL_drive) flags_cmd_out=f_putcmd;
-               i=cc_ReadPacket();
-               if (i<0)
-               {
-                       msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i);
-                       return (i);
-               }
-       }
-       current_drive->UPC_ctl_adr=0;
-       if (fam1_drive) i=0;
-       else i=2;
-
-       resp = infobuf + i;
-       if (*resp++ == 0x80) {
-               /* packed bcd to single ASCII digits */
-               *mcnp++ = (*resp >> 4)     + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4)     + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4)     + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4)     + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4)     + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4)     + '0';
-               *mcnp++ = (*resp++ & 0x0f) + '0';
-               *mcnp++ = (*resp >> 4)     + '0';
-       }
-       *mcnp = '\0';
-
-       current_drive->diskstate_flags |= upc_bit;
-       return (0);
-}
-
-/*==========================================================================*/
-static int cc_CheckMultiSession(void)
-{
-       int i;
-       
-       if (fam2_drive) return (0);
-       current_drive->f_multisession=0;
-       current_drive->lba_multi=0;
-       if (fam0_drive) return (0);
-       clr_cmdbuf();
-       if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_MULTISESS;
-               response_count=6;
-               flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-               i=cmd_out();
-               if (i<0) return (i);
-               if ((infobuf[0]&0x80)!=0)
-               {
-                       current_drive->f_multisession=1;
-                       current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[1]),
-                                                       make16(infobuf[2],infobuf[3])));
-               }
-       }
-       else if (famLV_drive)
-       {
-               drvcmd[0]=CMDL_MULTISESS;
-               drvcmd[1]=3;
-               drvcmd[2]=1;
-               response_count=8;
-               flags_cmd_out=f_putcmd;
-               i=cmd_out();
-               if (i<0) return (i);
-               current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]),
-                                               make16(infobuf[6],infobuf[7])));
-       }
-       else if (famT_drive)
-       {
-               response_count=12;
-               drvcmd[0]=CMDT_DISKINFO;
-               drvcmd[1]=0x02;
-               drvcmd[6]=0;
-               drvcmd[8]=response_count;
-               drvcmd[9]=0x40;
-               i=cmd_out();
-               if (i<0) return (i);
-               if (i<response_count) return (-100-i);
-               current_drive->first_session=infobuf[2];
-               current_drive->last_session=infobuf[3];
-               current_drive->track_of_last_session=infobuf[6];
-               if (current_drive->first_session!=current_drive->last_session)
-               {
-                       current_drive->f_multisession=1;
-                       current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11])));
-               }
-       }
-       for (i=0;i<response_count;i++)
-               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_MUL,"MultiSession Info:%s (%d)\n", msgbuf, current_drive->lba_multi);
-       if (current_drive->lba_multi>200)
-       {
-               current_drive->f_multisession=1;
-               msg(DBG_MUL,"MultiSession base: %06X\n", current_drive->lba_multi);
-       }
-       return (0);
-}
-/*==========================================================================*/
-#ifdef FUTURE
-static int cc_SubChanInfo(int frame, int count, u_char *buffer)
-       /* "frame" is a RED BOOK (msf-bin) address */
-{
-       int i;
-       
-       if (fam0LV_drive) return (-ENOSYS); /* drive firmware lacks it */
-       if (famT_drive)
-       {
-               return (-1);
-       }
-#if 0
-       if (current_drive->audio_state!=audio_playing) return (-ENODATA);
-#endif
-       clr_cmdbuf();
-       drvcmd[0]=CMD1_SUBCHANINF;
-       drvcmd[1]=(frame>>16)&0xFF;
-       drvcmd[2]=(frame>>8)&0xFF;
-       drvcmd[3]=frame&0xFF;
-       drvcmd[5]=(count>>8)&0xFF;
-       drvcmd[6]=count&0xFF;
-       flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-       cmd_type=READ_SC;
-       current_drive->frame_size=CD_FRAMESIZE_SUB;
-       i=cmd_out(); /* which buffer to use? */
-       return (i);
-}
-#endif /* FUTURE */ 
-/*==========================================================================*/
-static void __init check_datarate(void)
-{
-       int i=0;
-       
-       msg(DBG_IOX,"check_datarate entered.\n");
-       datarate=0;
-#if TEST_STI
-       for (i=0;i<=1000;i++) printk(".");
-#endif
-       /* set a timer to make (timed_out_delay!=0) after 1.1 seconds */
-#if 1
-       del_timer(&delay_timer);
-#endif
-       delay_timer.expires=jiffies+11*HZ/10;
-       timed_out_delay=0;
-       add_timer(&delay_timer);
-#if 0
-       msg(DBG_TIM,"delay timer started (11*HZ/10).\n");
-#endif
-       do
-       {
-               i=inb(CDi_status);
-               datarate++;
-#if 1
-               if (datarate>0x6FFFFFFF) break;
-#endif 
-       }
-       while (!timed_out_delay);
-       del_timer(&delay_timer);
-#if 0
-       msg(DBG_TIM,"datarate: %04X\n", datarate);
-#endif
-       if (datarate<65536) datarate=65536;
-       maxtim16=datarate*16;
-       maxtim04=datarate*4;
-       maxtim02=datarate*2;
-       maxtim_8=datarate/32;
-#if LONG_TIMING
-       maxtim_data=datarate/100;
-#else
-       maxtim_data=datarate/300;
-#endif /* LONG_TIMING */ 
-#if 0
-       msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data);
-#endif
-}
-/*==========================================================================*/
-#if 0
-static int c2_ReadError(int fam)
-{
-       int i;
-       
-       clr_cmdbuf();
-       response_count=9;
-       clr_respo_buf(9);
-       if (fam==1)
-       {
-               drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */
-               i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus);
-       }
-       else if (fam==2)
-       {
-               drvcmd[0]=CMD2_READ_ERR;
-               i=do_cmd(f_putcmd);
-       }
-       else return (-1);
-       return (i);
-}
-#endif
-/*==========================================================================*/
-static void __init ask_mail(void)
-{
-       int i;
-       
-       msg(DBG_INF, "please mail the following lines to emoenke@gwdg.de\n");
-       msg(DBG_INF, "(don't mail if you are not using the actual kernel):\n");
-       msg(DBG_INF, "%s\n", VERSION);
-       msg(DBG_INF, "address %03X, type %s, drive %s (ID %d)\n",
-           CDo_command, type, current_drive->drive_model, current_drive->drv_id);
-       for (i=0;i<12;i++)
-               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_INF,"infobuf =%s\n", msgbuf);
-       for (i=0;i<12;i++)
-               sprintf(&msgbuf[i*3], " %c ", infobuf[i]);
-       msgbuf[i*3]=0;
-       msg(DBG_INF,"infobuf =%s\n", msgbuf);
-}
-/*==========================================================================*/
-static int __init check_version(void)
-{
-       int i, j, l;
-       int teac_possible=0;
-       
-       msg(DBG_INI,"check_version: id=%d, d=%d.\n", current_drive->drv_id, current_drive - D_S);
-       current_drive->drv_type=0;
-
-       /* check for CR-52x, CR-56x, LCS-7260 and ECS-AT */
-       /* clear any pending error state */
-       clr_cmdbuf();
-       drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */
-       response_count=9;
-       flags_cmd_out=f_putcmd;
-       i=cmd_out();
-       if (i<0) msg(DBG_INI,"CMD0_READ_ERR returns %d (ok anyway).\n",i);
-       /* read drive version */
-       clr_cmdbuf();
-       for (i=0;i<12;i++) infobuf[i]=0;
-       drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */
-       response_count=12; /* fam1: only 11 */
-       flags_cmd_out=f_putcmd;
-       i=cmd_out();
-       if (i<-1) msg(DBG_INI,"CMD0_READ_VER returns %d\n",i);
-       if (i==-11) teac_possible++;
-       j=0;
-       for (i=0;i<12;i++) j+=infobuf[i];
-       if (j)
-       {
-               for (i=0;i<12;i++)
-                       sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_ECS,"infobuf =%s\n", msgbuf);
-               for (i=0;i<12;i++)
-                       sprintf(&msgbuf[i*3], " %c ", infobuf[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_ECS,"infobuf =%s\n", msgbuf);
-       }
-       for (i=0;i<4;i++) if (infobuf[i]!=family1[i]) break;
-       if (i==4)
-       {
-               current_drive->drive_model[0]='C';
-               current_drive->drive_model[1]='R';
-               current_drive->drive_model[2]='-';
-               current_drive->drive_model[3]='5';
-               current_drive->drive_model[4]=infobuf[i++];
-               current_drive->drive_model[5]=infobuf[i++];
-               current_drive->drive_model[6]=0;
-               current_drive->drv_type=drv_fam1;
-       }
-       if (!current_drive->drv_type)
-       {
-               for (i=0;i<8;i++) if (infobuf[i]!=family0[i]) break;
-               if (i==8)
-               {
-                       current_drive->drive_model[0]='C';
-                       current_drive->drive_model[1]='R';
-                       current_drive->drive_model[2]='-';
-                       current_drive->drive_model[3]='5';
-                       current_drive->drive_model[4]='2';
-                       current_drive->drive_model[5]='x';
-                       current_drive->drive_model[6]=0;
-                       current_drive->drv_type=drv_fam0;
-               }
-       }
-       if (!current_drive->drv_type)
-       {
-               for (i=0;i<8;i++) if (infobuf[i]!=familyL[i]) break;
-               if (i==8)
-               {
-                       for (j=0;j<8;j++)
-                               current_drive->drive_model[j]=infobuf[j];
-                       current_drive->drive_model[8]=0;
-                       current_drive->drv_type=drv_famL;
-               }
-       }
-       if (!current_drive->drv_type)
-       {
-               for (i=0;i<6;i++) if (infobuf[i]!=familyV[i]) break;
-               if (i==6)
-               {
-                       for (j=0;j<6;j++)
-                               current_drive->drive_model[j]=infobuf[j];
-                       current_drive->drive_model[6]=0;
-                       current_drive->drv_type=drv_famV;
-                       i+=2; /* 2 blanks before version */
-               }
-       }
-       if (!current_drive->drv_type)
-       {
-               /* check for CD200 */
-               clr_cmdbuf();
-               drvcmd[0]=CMD2_READ_ERR;
-               response_count=9;
-               flags_cmd_out=f_putcmd;
-               i=cmd_out();
-               if (i<0) msg(DBG_INI,"CMD2_READERR returns %d (ok anyway).\n",i);
-               if (i<0) msg(DBG_000,"CMD2_READERR returns %d (ok anyway).\n",i);
-               /* read drive version */
-               clr_cmdbuf();
-               for (i=0;i<12;i++) infobuf[i]=0;
-               if (sbpro_type==1) OUT(CDo_sel_i_d,0);
-#if 0
-               OUT(CDo_reset,0);
-               sbp_sleep(6*HZ);
-               OUT(CDo_enable,current_drive->drv_sel);
-#endif
-               drvcmd[0]=CMD2_READ_VER;
-               response_count=12;
-               flags_cmd_out=f_putcmd;
-               i=cmd_out();
-               if (i<0) msg(DBG_INI,"CMD2_READ_VER returns %d\n",i);
-               if (i==-7) teac_possible++;
-               j=0;
-               for (i=0;i<12;i++) j+=infobuf[i];
-               if (j)
-               {
-                       for (i=0;i<12;i++)
-                               sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
-                       msgbuf[i*3]=0;
-                       msg(DBG_IDX,"infobuf =%s\n", msgbuf);
-                       for (i=0;i<12;i++)
-                               sprintf(&msgbuf[i*3], " %c ", infobuf[i]);
-                       msgbuf[i*3]=0;
-                       msg(DBG_IDX,"infobuf =%s\n", msgbuf);
-               }
-               if (i>=0)
-               {
-                       for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break;
-                       if (i==5)
-                       {
-                               current_drive->drive_model[0]='C';
-                               current_drive->drive_model[1]='D';
-                               current_drive->drive_model[2]='2';
-                               current_drive->drive_model[3]='0';
-                               current_drive->drive_model[4]='0';
-                               current_drive->drive_model[5]=infobuf[i++];
-                               current_drive->drive_model[6]=infobuf[i++];
-                               current_drive->drive_model[7]=0;
-                               current_drive->drv_type=drv_fam2;
-                       }
-               }
-       }
-       if (!current_drive->drv_type)
-       {
-               /* check for TEAC CD-55A */
-               msg(DBG_TEA,"teac_possible: %d\n",teac_possible);
-               for (j=1;j<=((current_drive->drv_id==0)?3:1);j++)
-               {
-                       for (l=1;l<=((current_drive->drv_id==0)?10:1);l++)
-                       {
-                               msg(DBG_TEA,"TEAC reset #%d-%d.\n", j, l);
-                               if (sbpro_type==1) OUT(CDo_reset,0);
-                               else
-                               {
-                                       OUT(CDo_enable,current_drive->drv_sel);
-                                       OUT(CDo_sel_i_d,0);
-                                       OUT(CDo_command,CMDT_RESET);
-                                       for (i=0;i<9;i++) OUT(CDo_command,0);
-                               }
-                               sbp_sleep(5*HZ/10);
-                               OUT(CDo_enable,current_drive->drv_sel);
-                               OUT(CDo_sel_i_d,0);
-                               i=inb(CDi_status);
-                               msg(DBG_TEA,"TEAC CDi_status: %02X.\n",i);
-#if 0
-                               if (i&s_not_result_ready) continue; /* drive not present or ready */
-#endif
-                               i=inb(CDi_info);
-                               msg(DBG_TEA,"TEAC CDi_info: %02X.\n",i);
-                               if (i==0x55) break; /* drive found */
-                       }
-                       if (i==0x55) break; /* drive found */
-               }
-               if (i==0x55) /* drive found */
-               {
-                       msg(DBG_TEA,"TEAC drive found.\n");
-                       clr_cmdbuf();
-                       flags_cmd_out=f_putcmd;
-                       response_count=12;
-                       drvcmd[0]=CMDT_READ_VER;
-                       drvcmd[4]=response_count;
-                       for (i=0;i<12;i++) infobuf[i]=0;
-                       i=cmd_out_T();
-                       if (i!=0) msg(DBG_TEA,"cmd_out_T(CMDT_READ_VER) returns %d.\n",i);
-                       for (i=1;i<6;i++) if (infobuf[i]!=familyT[i-1]) break;
-                       if (i==6)
-                       {
-                               current_drive->drive_model[0]='C';
-                               current_drive->drive_model[1]='D';
-                               current_drive->drive_model[2]='-';
-                               current_drive->drive_model[3]='5';
-                               current_drive->drive_model[4]='5';
-                               current_drive->drive_model[5]=0;
-                               current_drive->drv_type=drv_famT;
-                       }
-               }
-       }
-       if (!current_drive->drv_type)
-       {
-               msg(DBG_TEA,"no drive found at address %03X under ID %d.\n",CDo_command,current_drive->drv_id);
-               return (-522);
-       }
-       for (j=0;j<4;j++) current_drive->firmware_version[j]=infobuf[i+j];
-       if (famL_drive)
-       {
-         u_char lcs_firm_e1[]="A E1";
-         u_char lcs_firm_f4[]="A4F4";
-               
-         for (j=0;j<4;j++)
-           if (current_drive->firmware_version[j]!=lcs_firm_e1[j]) break;
-         if (j==4) current_drive->drv_type=drv_e1;
-         
-         for (j=0;j<4;j++)
-           if (current_drive->firmware_version[j]!=lcs_firm_f4[j]) break;
-         if (j==4) current_drive->drv_type=drv_f4;
-
-         if (current_drive->drv_type==drv_famL) ask_mail();
-       }
-       else if (famT_drive)
-       {
-               j=infobuf[4]; /* one-byte version??? - here: 0x15 */
-               if (j=='5')
-               {
-                       current_drive->firmware_version[0]=infobuf[7];
-                       current_drive->firmware_version[1]=infobuf[8];
-                       current_drive->firmware_version[2]=infobuf[10];
-                       current_drive->firmware_version[3]=infobuf[11];
-               }
-               else
-               {
-                       if (j!=0x15) ask_mail();
-                       current_drive->firmware_version[0]='0';
-                       current_drive->firmware_version[1]='.';
-                       current_drive->firmware_version[2]='0'+(j>>4);
-                       current_drive->firmware_version[3]='0'+(j&0x0f);
-               }
-       }
-       else /* CR-52x, CR-56x, CD200, ECS-AT */
-       {
-               j = (current_drive->firmware_version[0] & 0x0F) * 100 +
-                       (current_drive->firmware_version[2] & 0x0F) *10 +
-                               (current_drive->firmware_version[3] & 0x0F);
-               if (fam0_drive)
-               {
-                       if (j<200) current_drive->drv_type=drv_199;
-                       else if (j<201) current_drive->drv_type=drv_200;
-                       else if (j<210) current_drive->drv_type=drv_201;
-                       else if (j<211) current_drive->drv_type=drv_210;
-                       else if (j<300) current_drive->drv_type=drv_211;
-                       else if (j>=300) current_drive->drv_type=drv_300;
-               }
-               else if (fam1_drive)
-               {
-                       if (j<100) current_drive->drv_type=drv_099;
-                       else
-                       {
-                               current_drive->drv_type=drv_100;
-                               if ((j!=500)&&(j!=102)) ask_mail();
-                       }
-               }
-               else if (fam2_drive)
-               {
-                       if (current_drive->drive_model[5]=='F')
-                       {
-                               if ((j!=1)&&(j!=35)&&(j!=200)&&(j!=210))
-                                 ask_mail(); /* unknown version at time */
-                       }
-                       else
-                       {
-                               msg(DBG_INF,"this CD200 drive is not fully supported yet - only audio will work.\n");
-                               if ((j!=101)&&(j!=35))
-                                 ask_mail(); /* unknown version at time */
-                       }
-               }
-               else if (famV_drive)
-                 {
-                   if ((j==100)||(j==150)) current_drive->drv_type=drv_at;
-                   ask_mail(); /* hopefully we get some feedback by this */
-                 }
-       }
-       msg(DBG_LCS,"drive type %02X\n",current_drive->drv_type);
-       msg(DBG_INI,"check_version done.\n");
-       return (0);
-}
-/*==========================================================================*/
-static void switch_drive(struct sbpcd_drive *p)
-{
-       current_drive = p;
-       OUT(CDo_enable,current_drive->drv_sel);
-       msg(DBG_DID,"drive %d (ID=%d) activated.\n",
-               current_drive - D_S, current_drive->drv_id);
-       return;
-}
-/*==========================================================================*/
-#ifdef PATH_CHECK
-/*
- * probe for the presence of an interface card
- */
-static int __init check_card(int port)
-{
-#undef N_RESPO
-#define N_RESPO 20
-       int i, j, k;
-       u_char response[N_RESPO];
-       u_char save_port0;
-       u_char save_port3;
-       
-       msg(DBG_INI,"check_card entered.\n");
-       save_port0=inb(port+0);
-       save_port3=inb(port+3);
-       
-       for (j=0;j<NR_SBPCD;j++)
-       {
-               OUT(port+3,j) ; /* enable drive #j */
-               OUT(port+0,CMD0_PATH_CHECK);
-               for (i=10;i>0;i--) OUT(port+0,0);
-               for (k=0;k<N_RESPO;k++) response[k]=0;
-               for (k=0;k<N_RESPO;k++)
-               {
-                       for (i=10000;i>0;i--)
-                       {
-                               if (inb(port+1)&s_not_result_ready) continue;
-                               response[k]=inb(port+0);
-                               break;
-                       }
-               }
-               for (i=0;i<N_RESPO;i++)
-                       sprintf(&msgbuf[i*3], " %02X", response[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf);
-               OUT(port+0,CMD0_PATH_CHECK);
-               for (i=10;i>0;i--) OUT(port+0,0);
-               for (k=0;k<N_RESPO;k++) response[k]=0xFF;
-               for (k=0;k<N_RESPO;k++)
-               {
-                       for (i=10000;i>0;i--)
-                       {
-                               if (inb(port+1)&s_not_result_ready) continue;
-                               response[k]=inb(port+0);
-                               break;
-                       }
-               }
-               for (i=0;i<N_RESPO;i++)
-                       sprintf(&msgbuf[i*3], " %02X", response[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf);
-
-               if (response[0]==0xAA)
-                       if (response[1]==0x55)
-                               return (0);
-       }
-       for (j=0;j<NR_SBPCD;j++)
-       {
-               OUT(port+3,j) ; /* enable drive #j */
-               OUT(port+0,CMD2_READ_VER);
-               for (i=10;i>0;i--) OUT(port+0,0);
-               for (k=0;k<N_RESPO;k++) response[k]=0;
-               for (k=0;k<N_RESPO;k++)
-               {
-                       for (i=1000000;i>0;i--)
-                       {
-                               if (inb(port+1)&s_not_result_ready) continue;
-                               response[k]=inb(port+0);
-                               break;
-                       }
-               }
-               for (i=0;i<N_RESPO;i++)
-                       sprintf(&msgbuf[i*3], " %02X", response[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf);
-
-               OUT(port+0,CMD2_READ_VER);
-               for (i=10;i>0;i--) OUT(port+0,0);
-               for (k=0;k<N_RESPO;k++) response[k]=0xFF;
-               for (k=0;k<N_RESPO;k++)
-               {
-                       for (i=1000000;i>0;i--)
-                       {
-                               if (inb(port+1)&s_not_result_ready) continue;
-                               response[k]=inb(port+0);
-                               break;
-                       }
-               }
-               for (i=0;i<N_RESPO;i++)
-                       sprintf(&msgbuf[i*3], " %02X", response[i]);
-               msgbuf[i*3]=0;
-               msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf);
-
-               if (response[0]==0xAA)
-                       if (response[1]==0x55)
-                               return (0);
-       }
-       OUT(port+0,save_port0);
-       OUT(port+3,save_port3);
-       return (0); /* in any case - no real "function" at time */
-}
-#endif /* PATH_CHECK */ 
-/*==========================================================================*/
-/*==========================================================================*/
-/*
- * probe for the presence of drives on the selected controller
- */
-static int __init check_drives(void)
-{
-       int i, j;
-       
-       msg(DBG_INI,"check_drives entered.\n");
-       ndrives=0;
-       for (j=0;j<max_drives;j++)
-       {
-               struct sbpcd_drive *p = D_S + ndrives;
-               p->drv_id=j;
-               if (sbpro_type==1) p->drv_sel=(j&0x01)<<1|(j&0x02)>>1;
-               else p->drv_sel=j;
-               switch_drive(p);
-               msg(DBG_INI,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j);
-               msg(DBG_000,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j);
-               i=check_version();
-               if (i<0) msg(DBG_INI,"check_version returns %d.\n",i);
-               else
-               {
-                       current_drive->drv_options=drv_pattern[j];
-                       if (fam0L_drive) current_drive->drv_options&=~(speed_auto|speed_300|speed_150);
-                       msg(DBG_INF, "Drive %d (ID=%d): %.9s (%.4s) at 0x%03X (type %d)\n",
-                           current_drive - D_S,
-                           current_drive->drv_id,
-                           current_drive->drive_model,
-                           current_drive->firmware_version,
-                           CDo_command,
-                           sbpro_type);
-                       ndrives++;
-               }
-       }
-       for (j=ndrives;j<NR_SBPCD;j++) D_S[j].drv_id=-1;
-       if (ndrives==0) return (-1);
-       return (0);
-}
-/*==========================================================================*/
-#ifdef FUTURE
-/*
- *  obtain if requested service disturbs current audio state
- */            
-static int obey_audio_state(u_char audio_state, u_char func,u_char subfunc)
-{
-       switch (audio_state)                   /* audio status from controller  */
-       {
-       case aud_11: /* "audio play in progress" */
-       case audx11:
-               switch (func)                      /* DOS command code */
-               {
-               case cmd_07: /* input flush  */
-               case cmd_0d: /* open device  */
-               case cmd_0e: /* close device */
-               case cmd_0c: /* ioctl output */
-                       return (1);
-               case cmd_03: /* ioctl input  */
-                       switch (subfunc)
-                               /* DOS ioctl input subfunction */
-                       {
-                       case cxi_00:
-                       case cxi_06:
-                       case cxi_09:
-                               return (1);
-                       default:
-                               return (ERROR15);
-                       }
-                       return (1);
-               default:
-                       return (ERROR15);
-               }
-               return (1);
-       case aud_12:                  /* "audio play paused"      */
-       case audx12:
-               return (1);
-       default:
-               return (2);
-       }
-}
-/*==========================================================================*/
-/* allowed is only
- * ioctl_o, flush_input, open_device, close_device, 
- * tell_address, tell_volume, tell_capabiliti,
- * tell_framesize, tell_CD_changed, tell_audio_posi
- */
-static int check_allowed1(u_char func1, u_char func2)
-{
-#if 000
-       if (func1==ioctl_o) return (0);
-       if (func1==read_long) return (-1);
-       if (func1==read_long_prefetch) return (-1);
-       if (func1==seek) return (-1);
-       if (func1==audio_play) return (-1);
-       if (func1==audio_pause) return (-1);
-       if (func1==audio_resume) return (-1);
-       if (func1!=ioctl_i) return (0);
-       if (func2==tell_SubQ_run_tot) return (-1);
-       if (func2==tell_cdsize) return (-1);
-       if (func2==tell_TocDescrip) return (-1);
-       if (func2==tell_TocEntry) return (-1);
-       if (func2==tell_subQ_info) return (-1);
-       if (fam1_drive) if (func2==tell_SubChanInfo) return (-1);
-       if (func2==tell_UPC) return (-1);
-#else
-       return (0);
-#endif
-}
-/*==========================================================================*/
-static int check_allowed2(u_char func1, u_char func2)
-{
-#if 000
-       if (func1==read_long) return (-1);
-       if (func1==read_long_prefetch) return (-1);
-       if (func1==seek) return (-1);
-       if (func1==audio_play) return (-1);
-  if (func1!=ioctl_o) return (0);
-       if (fam1_drive)
-       {
-               if (func2==EjectDisk) return (-1);
-               if (func2==CloseTray) return (-1);
-       }
-#else
-       return (0);
-#endif
-}
-/*==========================================================================*/
-static int check_allowed3(u_char func1, u_char func2)
-{
-#if 000
-       if (func1==ioctl_i)
-       {
-               if (func2==tell_address) return (0);
-               if (func2==tell_capabiliti) return (0);
-               if (func2==tell_CD_changed) return (0);
-               if (fam0L_drive) if (func2==tell_SubChanInfo) return (0);
-               return (-1);
-       }
-       if (func1==ioctl_o)
-       {
-               if (func2==DriveReset) return (0);
-               if (fam0L_drive)
-               {
-                       if (func2==EjectDisk) return (0);
-                       if (func2==LockDoor) return (0);
-         if (func2==CloseTray) return (0);
-               }
-               return (-1);
-    }
-       if (func1==flush_input) return (-1);
-       if (func1==read_long) return (-1);
-       if (func1==read_long_prefetch) return (-1);
-       if (func1==seek) return (-1);
-       if (func1==audio_play) return (-1);
-       if (func1==audio_pause) return (-1);
-       if (func1==audio_resume) return (-1);
-#else
-       return (0);
-#endif
-}
-/*==========================================================================*/
-static int seek_pos_audio_end(void)
-{
-       int i;
-
-       i=msf2blk(current_drive->pos_audio_end)-1;
-       if (i<0) return (-1);
-       i=cc_Seek(i,0);
-       return (i);
-}
-#endif /* FUTURE */ 
-/*==========================================================================*/
-static int ReadToC(void)
-{
-       int i, j;
-       current_drive->diskstate_flags &= ~toc_bit;
-       current_drive->ored_ctl_adr=0;
-       /* special handling of CD-I HE */
-       if ((current_drive->n_first_track == 2 && current_drive->n_last_track == 2) ||
-             current_drive->xa_byte == 0x10)
-        {
-               current_drive->TocBuffer[1].nixbyte=0;
-               current_drive->TocBuffer[1].ctl_adr=0x40;
-               current_drive->TocBuffer[1].number=1;
-               current_drive->TocBuffer[1].format=0;
-               current_drive->TocBuffer[1].address=blk2msf(0);
-               current_drive->ored_ctl_adr |= 0x40;
-               current_drive->n_first_track = 1;
-               current_drive->n_last_track = 1;
-               current_drive->xa_byte = 0x10;
-                j = 2;
-        } else
-       for (j=current_drive->n_first_track;j<=current_drive->n_last_track;j++)
-       {
-               i=cc_ReadTocEntry(j);
-               if (i<0)
-               {
-                       msg(DBG_INF,"cc_ReadTocEntry(%d) returns %d.\n",j,i);
-                       return (i);
-               }
-               current_drive->TocBuffer[j].nixbyte=current_drive->TocEnt_nixbyte;
-               current_drive->TocBuffer[j].ctl_adr=current_drive->TocEnt_ctl_adr;
-               current_drive->TocBuffer[j].number=current_drive->TocEnt_number;
-               current_drive->TocBuffer[j].format=current_drive->TocEnt_format;
-               current_drive->TocBuffer[j].address=current_drive->TocEnt_address;
-               current_drive->ored_ctl_adr |= current_drive->TocEnt_ctl_adr;
-       }
-       /* fake entry for LeadOut Track */
-       current_drive->TocBuffer[j].nixbyte=0;
-       current_drive->TocBuffer[j].ctl_adr=0;
-       current_drive->TocBuffer[j].number=CDROM_LEADOUT;
-       current_drive->TocBuffer[j].format=0;
-       current_drive->TocBuffer[j].address=current_drive->size_msf;
-       
-       current_drive->diskstate_flags |= toc_bit;
-       return (0);
-}
-/*==========================================================================*/
-static int DiskInfo(void)
-{
-       int i, j;
-       
-       current_drive->mode=READ_M1;
-       
-#undef LOOP_COUNT
-#define LOOP_COUNT 10 /* needed for some "old" drives */
-       
-       msg(DBG_000,"DiskInfo entered.\n");
-       for (j=1;j<LOOP_COUNT;j++)
-       {
-#if 0
-               i=SetSpeed();
-               if (i<0)
-               {
-                       msg(DBG_INF,"DiskInfo: SetSpeed returns %d\n", i);
-                       continue;
-               }
-               i=cc_ModeSense();
-               if (i<0)
-               {
-                       msg(DBG_INF,"DiskInfo: cc_ModeSense returns %d\n", i);
-                       continue;
-               }
-#endif
-               i=cc_ReadCapacity();
-               if (i>=0) break;
-               msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i);
-#if 0
-               i=cc_DriveReset();
-#endif
-               if (!fam0_drive && j == 2) break;
-       }
-       if (j==LOOP_COUNT) return (-33); /* give up */
-       
-       i=cc_ReadTocDescr();
-       if (i<0)
-       {
-               msg(DBG_INF,"DiskInfo: ReadTocDescr returns %d\n", i);
-               return (i);
-       }
-       i=ReadToC();
-       if (i<0)
-       {
-               msg(DBG_INF,"DiskInfo: ReadToC returns %d\n", i);
-               return (i);
-       }
-       i=cc_CheckMultiSession();
-       if (i<0)
-       {
-               msg(DBG_INF,"DiskInfo: cc_CheckMultiSession returns %d\n", i);
-               return (i);
-       }
-       if (current_drive->f_multisession) current_drive->sbp_bufsiz=1;  /* possibly a weird PhotoCD */
-       else current_drive->sbp_bufsiz=buffers;
-       i=cc_ReadTocEntry(current_drive->n_first_track);
-       if (i<0)
-       {
-               msg(DBG_INF,"DiskInfo: cc_ReadTocEntry(1) returns %d\n", i);
-               return (i);
-       }
-       i=cc_ReadUPC();
-       if (i<0) msg(DBG_INF,"DiskInfo: cc_ReadUPC returns %d\n", i);
-       if ((fam0L_drive) && (current_drive->xa_byte==0x20 || current_drive->xa_byte == 0x10))
-       {
-               /* XA disk with old drive */
-               cc_ModeSelect(CD_FRAMESIZE_RAW1);
-               cc_ModeSense();
-       }
-       if (famT_drive) cc_prep_mode_T();
-       msg(DBG_000,"DiskInfo done.\n");
-       return (0);
-}
-
-static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
-       struct sbpcd_drive *p = cdi->handle;
-       int st;
-
-       if (CDSL_CURRENT != slot_nr) {
-                /* we have no changer support */
-                return -EINVAL;
-       }
-
-        cc_ReadStatus();
-       st=ResponseStatus();
-       if (st<0)
-       {
-               msg(DBG_INF,"sbpcd_drive_status: timeout.\n");
-               return (0);
-       }
-       msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked);
-       msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed);
-       msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in);
-       msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok);
-       msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning);
-       msg(DBG_000,"Drive Status: busy =%d.\n", st_busy);
-
-#if 0
-  if (!(p->status_bits & p_door_closed)) return CDS_TRAY_OPEN;
-  if (p->status_bits & p_disk_ok) return CDS_DISC_OK;
-  if (p->status_bits & p_disk_in) return CDS_DRIVE_NOT_READY;
-
-  return CDS_NO_DISC;
-#else
-  if (p->status_bits & p_spinning) return CDS_DISC_OK;
-/*  return CDS_TRAY_OPEN; */
-  return CDS_NO_DISC;
-  
-#endif
-
-}
-
-
-/*==========================================================================*/
-#ifdef FUTURE
-/*
- *  called always if driver gets entered
- *  returns 0 or ERROR2 or ERROR15
- */
-static int prepare(u_char func, u_char subfunc)
-{
-       int i;
-       
-       if (fam0L_drive)
-       {
-               i=inb(CDi_status);
-               if (i&s_attention) GetStatus();
-       }
-       else if (fam1_drive) GetStatus();
-       else if (fam2_drive) GetStatus();
-       else if (famT_drive) GetStatus();
-       if (current_drive->CD_changed==0xFF)
-       {
-               current_drive->diskstate_flags=0;
-               current_drive->audio_state=0;
-               if (!st_diskok)
-               {
-                       i=check_allowed1(func,subfunc);
-                       if (i<0) return (-2);
-               }
-               else 
-               {
-                       i=check_allowed3(func,subfunc);
-                       if (i<0)
-                       {
-                               current_drive->CD_changed=1;
-                               return (-15);
-                       }
-               }
-       }
-       else
-       {
-               if (!st_diskok)
-               {
-                       current_drive->diskstate_flags=0;
-                       current_drive->audio_state=0;
-                       i=check_allowed1(func,subfunc);
-                       if (i<0) return (-2);
-               }
-               else
-               { 
-                       if (st_busy)
-                       {
-                               if (current_drive->audio_state!=audio_pausing)
-                               {
-                                       i=check_allowed2(func,subfunc);
-                                       if (i<0) return (-2);
-                               }
-                       }
-                       else
-                       {
-                               if (current_drive->audio_state==audio_playing) seek_pos_audio_end();
-                               current_drive->audio_state=0;
-                       }
-                       if (!frame_size_valid)
-                       {
-                               i=DiskInfo();
-                               if (i<0)
-                               {
-                                       current_drive->diskstate_flags=0;
-                                       current_drive->audio_state=0;
-                                       i=check_allowed1(func,subfunc);
-                                       if (i<0) return (-2);
-                               }
-                       }
-               }
-    }
-       return (0);
-}
-#endif /* FUTURE */ 
-/*==========================================================================*/
-/*==========================================================================*/
-/*
- * Check the results of the "get status" command.
- */
-static int sbp_status(void)
-{
-       int st;
-       
-       st=ResponseStatus();
-       if (st<0)
-       {
-               msg(DBG_INF,"sbp_status: timeout.\n");
-               return (0);
-       }
-       
-       if (!st_spinning) msg(DBG_SPI,"motor got off - ignoring.\n");
-       
-       if (st_check) 
-       {
-               msg(DBG_INF,"st_check detected - retrying.\n");
-               return (0);
-       }
-       if (!st_door_closed)
-       {
-               msg(DBG_INF,"door is open - retrying.\n");
-               return (0);
-       }
-       if (!st_caddy_in)
-       {
-               msg(DBG_INF,"disk removed - retrying.\n");
-               return (0);
-       }
-       if (!st_diskok) 
-       {
-               msg(DBG_INF,"!st_diskok detected - retrying.\n");
-               return (0);
-       }
-       if (st_busy) 
-       {
-               msg(DBG_INF,"st_busy detected - retrying.\n");
-               return (0);
-       }
-       return (1);
-}
-/*==========================================================================*/
-               
-static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp)
-{
-       struct sbpcd_drive *p = cdi->handle;
-       ms_infp->addr_format = CDROM_LBA;
-       ms_infp->addr.lba    = p->lba_multi;
-       if (p->f_multisession)
-               ms_infp->xa_flag=1; /* valid redirection address */
-       else
-               ms_infp->xa_flag=0; /* invalid redirection address */
-
-       return  0;
-}
-
-static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
-                      void * arg)
-{
-       struct sbpcd_drive *p = cdi->handle;
-       int i, st, j;
-       
-       msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08p)\n", cdi->name, cmd, arg);
-       if (p->drv_id==-1) {
-               msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name);
-               return (-ENXIO);             /* no such drive */
-       }
-       down(&ioctl_read_sem);
-       if (p != current_drive)
-               switch_drive(p);
-       
-       msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd);
-       switch (cmd)            /* Sun-compatible */
-       {
-               
-       case CDROMPAUSE:     /* Pause the drive */
-               msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n");
-               /* pause the drive unit when it is currently in PLAY mode,         */
-               /* or reset the starting and ending locations when in PAUSED mode. */
-               /* If applicable, at the next stopping point it reaches            */
-               /* the drive will discontinue playing.                             */
-               switch (current_drive->audio_state)
-               {
-               case audio_playing:
-                       if (famL_drive) i=cc_ReadSubQ();
-                       else i=cc_Pause_Resume(1);
-                       if (i<0) RETURN_UP(-EIO);
-                       if (famL_drive) i=cc_Pause_Resume(1);
-                       else i=cc_ReadSubQ();
-                       if (i<0) RETURN_UP(-EIO);
-                       current_drive->pos_audio_start=current_drive->SubQ_run_tot;
-                       current_drive->audio_state=audio_pausing;
-                       RETURN_UP(0);
-               case audio_pausing:
-                       i=cc_Seek(current_drive->pos_audio_start,1);
-                       if (i<0) RETURN_UP(-EIO);
-                       RETURN_UP(0);
-               default:
-                       RETURN_UP(-EINVAL);
-               }
-
-       case CDROMRESUME: /* resume paused audio play */
-               msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n");
-               /* resume playing audio tracks when a previous PLAY AUDIO call has  */
-               /* been paused with a PAUSE command.                                */
-               /* It will resume playing from the location saved in SubQ_run_tot.  */
-               if (current_drive->audio_state!=audio_pausing) RETURN_UP(-EINVAL);
-               if (famL_drive)
-                       i=cc_PlayAudio(current_drive->pos_audio_start,
-                                      current_drive->pos_audio_end);
-               else i=cc_Pause_Resume(3);
-               if (i<0) RETURN_UP(-EIO);
-               current_drive->audio_state=audio_playing;
-               RETURN_UP(0);
-
-       case CDROMPLAYMSF:
-               msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
-#ifdef SAFE_MIXED
-               if (current_drive->has_data>1) RETURN_UP(-EBUSY);
-#endif /* SAFE_MIXED */
-               if (current_drive->audio_state==audio_playing)
-               {
-                       i=cc_Pause_Resume(1);
-                       if (i<0) RETURN_UP(-EIO);
-                       i=cc_ReadSubQ();
-                       if (i<0) RETURN_UP(-EIO);
-                       current_drive->pos_audio_start=current_drive->SubQ_run_tot;
-                       i=cc_Seek(current_drive->pos_audio_start,1);
-               }
-               memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf));
-               /* values come as msf-bin */
-               current_drive->pos_audio_start = (msf.cdmsf_min0<<16) |
-                        (msf.cdmsf_sec0<<8) |
-                               msf.cdmsf_frame0;
-               current_drive->pos_audio_end = (msf.cdmsf_min1<<16) |
-                       (msf.cdmsf_sec1<<8) |
-                               msf.cdmsf_frame1;
-               msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
-                   current_drive->pos_audio_start,current_drive->pos_audio_end);
-               i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end);
-               if (i<0)
-               {
-                       msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
-                       DriveReset();
-                       current_drive->audio_state=0;
-                       RETURN_UP(-EIO);
-               }
-               current_drive->audio_state=audio_playing;
-               RETURN_UP(0);
-               
-       case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
-               msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
-#ifdef SAFE_MIXED
-               if (current_drive->has_data>1) RETURN_UP(-EBUSY);
-#endif /* SAFE_MIXED */
-               if (current_drive->audio_state==audio_playing)
-               {
-                       msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
-#if 1
-                       RETURN_UP(0); /* just let us play on */
-#else
-                       RETURN_UP(-EINVAL); /* play on, but say "error" */
-#endif
-               }
-               memcpy(&ti,(void *) arg,sizeof(struct cdrom_ti));
-               msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n",
-                   ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1);
-               if (ti.cdti_trk0<current_drive->n_first_track) RETURN_UP(-EINVAL);
-               if (ti.cdti_trk0>current_drive->n_last_track) RETURN_UP(-EINVAL);
-               if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
-               if (ti.cdti_trk1>current_drive->n_last_track) ti.cdti_trk1=current_drive->n_last_track;
-               current_drive->pos_audio_start=current_drive->TocBuffer[ti.cdti_trk0].address;
-               current_drive->pos_audio_end=current_drive->TocBuffer[ti.cdti_trk1+1].address;
-               i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end);
-               if (i<0)
-               {
-                       msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
-                       DriveReset();
-                       current_drive->audio_state=0;
-                       RETURN_UP(-EIO);
-               }
-               current_drive->audio_state=audio_playing;
-               RETURN_UP(0);
-               
-       case CDROMREADTOCHDR:        /* Read the table of contents header */
-               msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n");
-               tochdr.cdth_trk0=current_drive->n_first_track;
-               tochdr.cdth_trk1=current_drive->n_last_track;
-               memcpy((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
-               RETURN_UP(0);
-               
-       case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
-               msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n");
-               memcpy(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
-               i=tocentry.cdte_track;
-               if (i==CDROM_LEADOUT) i=current_drive->n_last_track+1;
-               else if (i<current_drive->n_first_track||i>current_drive->n_last_track)
-                  RETURN_UP(-EINVAL);
-               tocentry.cdte_adr=current_drive->TocBuffer[i].ctl_adr&0x0F;
-               tocentry.cdte_ctrl=(current_drive->TocBuffer[i].ctl_adr>>4)&0x0F;
-               tocentry.cdte_datamode=current_drive->TocBuffer[i].format;
-               if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
-               {
-                       tocentry.cdte_addr.msf.minute=(current_drive->TocBuffer[i].address>>16)&0x00FF;
-                       tocentry.cdte_addr.msf.second=(current_drive->TocBuffer[i].address>>8)&0x00FF;
-                       tocentry.cdte_addr.msf.frame=current_drive->TocBuffer[i].address&0x00FF;
-               }
-               else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
-                       tocentry.cdte_addr.lba=msf2blk(current_drive->TocBuffer[i].address);
-               else RETURN_UP(-EINVAL);
-               memcpy((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
-               RETURN_UP(0);
-               
-       case CDROMSTOP:      /* Spin down the drive */
-               msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
-#ifdef SAFE_MIXED
-               if (current_drive->has_data>1) RETURN_UP(-EBUSY);
-#endif /* SAFE_MIXED */ 
-               i=cc_Pause_Resume(1);
-               current_drive->audio_state=0;
-#if 0
-               cc_DriveReset();
-#endif
-               RETURN_UP(i);
-
-       case CDROMSTART:  /* Spin up the drive */
-               msg(DBG_IOC,"ioctl: CDROMSTART entered.\n");
-               cc_SpinUp();
-               current_drive->audio_state=0;
-               RETURN_UP(0);
-
-       case CDROMVOLCTRL:   /* Volume control */
-               msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n");
-               memcpy(&volctrl,(char *) arg,sizeof(volctrl));
-               current_drive->vol_chan0=0;
-               current_drive->vol_ctrl0=volctrl.channel0;
-               current_drive->vol_chan1=1;
-               current_drive->vol_ctrl1=volctrl.channel1;
-               i=cc_SetVolume();
-               RETURN_UP(0);
-
-       case CDROMVOLREAD:   /* read Volume settings from drive */
-               msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n");
-               st=cc_GetVolume();
-               if (st<0) RETURN_UP(st);
-               volctrl.channel0=current_drive->vol_ctrl0;
-               volctrl.channel1=current_drive->vol_ctrl1;
-               volctrl.channel2=0;
-               volctrl.channel2=0;
-               memcpy((void *)arg,&volctrl,sizeof(volctrl));
-               RETURN_UP(0);
-
-       case CDROMSUBCHNL:   /* Get subchannel info */
-               msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n");
-               /* Bogus, I can do better than this! --AJK
-               if ((st_spinning)||(!subq_valid)) {
-                       i=cc_ReadSubQ();
-                       if (i<0) RETURN_UP(-EIO);
-               }
-               */
-               i=cc_ReadSubQ();
-               if (i<0) {
-                       j=cc_ReadError(); /* clear out error status from drive */
-                       current_drive->audio_state=CDROM_AUDIO_NO_STATUS;
-                       /* get and set the disk state here,
-                       probably not the right place, but who cares!
-                       It makes it work properly! --AJK */
-                       if (current_drive->CD_changed==0xFF) {
-                               msg(DBG_000,"Disk changed detect\n");
-                               current_drive->diskstate_flags &= ~cd_size_bit;
-                       }
-                       RETURN_UP(-EIO);
-               }
-               if (current_drive->CD_changed==0xFF) {
-                       /* reread the TOC because the disk has changed! --AJK */
-                       msg(DBG_000,"Disk changed STILL detected, rereading TOC!\n");
-                       i=DiskInfo();
-                       if(i==0) {
-                               current_drive->CD_changed=0x00; /* cd has changed, procede, */
-                               RETURN_UP(-EIO); /* and get TOC, etc on next try! --AJK */
-                       } else {
-                               RETURN_UP(-EIO); /* we weren't ready yet! --AJK */
-                       }
-               }
-               memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
-               /*
-                       This virtual crap is very bogus!
-                       It doesn't detect when the cd is done playing audio!
-                       Lets do this right with proper hardware register reading!
-               */
-               cc_ReadStatus();
-               i=ResponseStatus();
-               msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked);
-               msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed);
-               msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in);
-               msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok);
-               msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning);
-               msg(DBG_000,"Drive Status: busy =%d.\n", st_busy);
-               /* st_busy indicates if it's _ACTUALLY_ playing audio */
-               switch (current_drive->audio_state)
-               {
-               case audio_playing:
-                       if(st_busy==0) {
-                               /* CD has stopped playing audio --AJK */
-                               current_drive->audio_state=audio_completed;
-                               SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED;
-                       } else {
-                               SC.cdsc_audiostatus=CDROM_AUDIO_PLAY;
-                       }
-                       break;
-               case audio_pausing:
-                       SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED;
-                       break;
-               case audio_completed:
-                       SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED;
-                       break;
-               default:
-                       SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS;
-                       break;
-               }
-               SC.cdsc_adr=current_drive->SubQ_ctl_adr;
-               SC.cdsc_ctrl=current_drive->SubQ_ctl_adr>>4;
-               SC.cdsc_trk=bcd2bin(current_drive->SubQ_trk);
-               SC.cdsc_ind=bcd2bin(current_drive->SubQ_pnt_idx);
-               if (SC.cdsc_format==CDROM_LBA)
-               {
-                       SC.cdsc_absaddr.lba=msf2blk(current_drive->SubQ_run_tot);
-                       SC.cdsc_reladdr.lba=msf2blk(current_drive->SubQ_run_trk);
-               }
-               else /* not only if (SC.cdsc_format==CDROM_MSF) */
-               {
-                       SC.cdsc_absaddr.msf.minute=(current_drive->SubQ_run_tot>>16)&0x00FF;
-                       SC.cdsc_absaddr.msf.second=(current_drive->SubQ_run_tot>>8)&0x00FF;
-                       SC.cdsc_absaddr.msf.frame=current_drive->SubQ_run_tot&0x00FF;
-                       SC.cdsc_reladdr.msf.minute=(current_drive->SubQ_run_trk>>16)&0x00FF;
-                       SC.cdsc_reladdr.msf.second=(current_drive->SubQ_run_trk>>8)&0x00FF;
-                       SC.cdsc_reladdr.msf.frame=current_drive->SubQ_run_trk&0x00FF;
-               }
-               memcpy((void *) arg, &SC, sizeof(struct cdrom_subchnl));
-               msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
-                   SC.cdsc_format,SC.cdsc_audiostatus,
-                   SC.cdsc_adr,SC.cdsc_ctrl,
-                   SC.cdsc_trk,SC.cdsc_ind,
-                   SC.cdsc_absaddr,SC.cdsc_reladdr);
-               RETURN_UP(0);
-
-       default:
-               msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
-               RETURN_UP(-EINVAL);
-       } /* end switch(cmd) */
-}
-/*==========================================================================*/
-/*
- *  Take care of the different block sizes between cdrom and Linux.
- */
-static void sbp_transfer(struct request *req)
-{
-       long offs;
-
-       while ( (req->nr_sectors > 0) &&
-              (req->sector/4 >= current_drive->sbp_first_frame) &&
-              (req->sector/4 <= current_drive->sbp_last_frame) )
-       {
-               offs = (req->sector - current_drive->sbp_first_frame * 4) * 512;
-               memcpy(req->buffer, current_drive->sbp_buf + offs, 512);
-               req->nr_sectors--;
-               req->sector++;
-               req->buffer += 512;
-       }
-}
-/*==========================================================================*/
-/*
- *  special end_request for sbpcd to solve CURRENT==NULL bug. (GTL)
- *  GTL = Gonzalo Tornaria <tornaria@cmat.edu.uy>
- *
- *  This is a kludge so we don't need to modify end_request.
- *  We put the req we take out after INIT_REQUEST in the requests list,
- *  so that end_request will discard it.
- *
- *  The bug could be present in other block devices, perhaps we
- *  should modify INIT_REQUEST and end_request instead, and
- *  change every block device..
- *
- *  Could be a race here?? Could e.g. a timer interrupt schedule() us?
- *  If so, we should copy end_request here, and do it right.. (or
- *  modify end_request and the block devices).
- *
- *  In any case, the race here would be much small than it was, and
- *  I couldn't reproduce..
- *
- *  The race could be: suppose CURRENT==NULL. We put our req in the list,
- *  and we are scheduled. Other process takes over, and gets into
- *  do_sbpcd_request. It sees CURRENT!=NULL (it is == to our req), so
- *  proceeds. It ends, so CURRENT is now NULL.. Now we awake somewhere in
- *  end_request, but now CURRENT==NULL... oops!
- *
- */
-#undef DEBUG_GTL
-
-/*==========================================================================*/
-/*
- *  I/O request routine, called from Linux kernel.
- */
-static void do_sbpcd_request(request_queue_t * q)
-{
-       u_int block;
-       u_int nsect;
-       int status_tries, data_tries;
-       struct request *req;
-       struct sbpcd_drive *p;
-#ifdef DEBUG_GTL
-       static int xx_nr=0;
-       int xnr;
-#endif
-
- request_loop:
-#ifdef DEBUG_GTL
-       xnr=++xx_nr;
-
-       req = elv_next_request(q);
-
-       if (!req)
-       {
-               printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n",
-                       xnr, current->pid, jiffies);
-               printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n",
-                       xnr, jiffies);
-               return;
-       }
-
-       printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n",
-               xnr, req, req->sector, req->nr_sectors, current->pid, jiffies);
-#endif
-
-       req = elv_next_request(q);      /* take out our request so no other */
-       if (!req)
-               return;
-
-       if (req -> sector == -1)
-               end_request(req, 0);
-       spin_unlock_irq(q->queue_lock);
-
-       down(&ioctl_read_sem);
-       if (rq_data_dir(elv_next_request(q)) != READ)
-       {
-               msg(DBG_INF, "bad cmd %d\n", req->cmd[0]);
-               goto err_done;
-       }
-       p = req->rq_disk->private_data;
-#if OLD_BUSY
-       while (busy_audio) sbp_sleep(HZ); /* wait a bit */
-       busy_data=1;
-#endif /* OLD_BUSY */
-
-       if (p->audio_state==audio_playing) goto err_done;
-       if (p != current_drive)
-               switch_drive(p);
-
-       block = req->sector; /* always numbered as 512-byte-pieces */
-       nsect = req->nr_sectors; /* always counted as 512-byte-pieces */
-
-       msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect);
-#if 0
-       msg(DBG_MUL,"read LBA %d\n", block/4);
-#endif
-
-       sbp_transfer(req);
-       /* if we satisfied the request from the buffer, we're done. */
-       if (req->nr_sectors == 0)
-       {
-#ifdef DEBUG_GTL
-               printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n",
-                       xnr, req, req->sector, req->nr_sectors, jiffies);
-#endif
-               up(&ioctl_read_sem);
-               spin_lock_irq(q->queue_lock);
-               end_request(req, 1);
-               goto request_loop;
-       }
-
-#ifdef FUTURE
-       i=prepare(0,0); /* at moment not really a hassle check, but ... */
-       if (i!=0)
-               msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i);
-#endif /* FUTURE */
-
-       if (!st_spinning) cc_SpinUp();
-
-       for (data_tries=n_retries; data_tries > 0; data_tries--)
-       {
-               for (status_tries=3; status_tries > 0; status_tries--)
-               {
-                       flags_cmd_out |= f_respo3;
-                       cc_ReadStatus();
-                       if (sbp_status() != 0) break;
-                       if (st_check) cc_ReadError();
-                       sbp_sleep(1);    /* wait a bit, try again */
-               }
-               if (status_tries == 0)
-               {
-                       msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__);
-                       break;
-               }
-               
-               sbp_read_cmd(req);
-               sbp_sleep(0);
-               if (sbp_data(req) != 0)
-               {
-#ifdef SAFE_MIXED
-                       current_drive->has_data=2; /* is really a data disk */
-#endif /* SAFE_MIXED */
-#ifdef DEBUG_GTL
-                       printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n",
-                               xnr, req, req->sector, req->nr_sectors, jiffies);
-#endif
-                       up(&ioctl_read_sem);
-                       spin_lock_irq(q->queue_lock);
-                       end_request(req, 1);
-                       goto request_loop;
-               }
-       }
-
- err_done:
-#if OLD_BUSY
-       busy_data=0;
-#endif /* OLD_BUSY */
-#ifdef DEBUG_GTL
-       printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n",
-               xnr, req, req->sector, req->nr_sectors, jiffies);
-#endif
-       up(&ioctl_read_sem);
-       sbp_sleep(0);    /* wait a bit, try again */
-       spin_lock_irq(q->queue_lock);
-       end_request(req, 0);
-       goto request_loop;
-}
-/*==========================================================================*/
-/*
- *  build and send the READ command.
- */
-static void sbp_read_cmd(struct request *req)
-{
-#undef OLD
-
-       int i;
-       int block;
-
-       current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1;      /* purge buffer */
-       current_drive->sbp_current = 0;
-       block=req->sector/4;
-       if (block+current_drive->sbp_bufsiz <= current_drive->CDsize_frm)
-               current_drive->sbp_read_frames = current_drive->sbp_bufsiz;
-       else
-       {
-               current_drive->sbp_read_frames=current_drive->CDsize_frm-block;
-               /* avoid reading past end of data */
-               if (current_drive->sbp_read_frames < 1)
-               {
-                       msg(DBG_INF,"requested frame %d, CD size %d ???\n",
-                           block, current_drive->CDsize_frm);
-                       current_drive->sbp_read_frames=1;
-               }
-       }
-
-       flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
-       clr_cmdbuf();
-       if (famV_drive)
-         {
-           drvcmd[0]=CMDV_READ;
-           lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
-           bin2bcdx(&drvcmd[1]);
-           bin2bcdx(&drvcmd[2]);
-           bin2bcdx(&drvcmd[3]);
-           drvcmd[4]=current_drive->sbp_read_frames>>8;
-           drvcmd[5]=current_drive->sbp_read_frames&0xff;
-           drvcmd[6]=0x02; /* flag "msf-bcd" */
-       }
-       else if (fam0L_drive)
-       {
-               flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
-               if (current_drive->xa_byte==0x20)
-               {
-                       cmd_type=READ_M2;
-                       drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
-                       drvcmd[1]=(block>>16)&0x0ff;
-                       drvcmd[2]=(block>>8)&0x0ff;
-                       drvcmd[3]=block&0x0ff;
-                       drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
-                       drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
-               }
-               else
-               {
-                       drvcmd[0]=CMD0_READ; /* "read frames", old drives */
-                       if (current_drive->drv_type>=drv_201)
-                       {
-                               lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
-                               bin2bcdx(&drvcmd[1]);
-                               bin2bcdx(&drvcmd[2]);
-                               bin2bcdx(&drvcmd[3]);
-                       }
-                       else
-                       {
-                               drvcmd[1]=(block>>16)&0x0ff;
-                               drvcmd[2]=(block>>8)&0x0ff;
-                               drvcmd[3]=block&0x0ff;
-                       }
-                       drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
-                       drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
-                       drvcmd[6]=(current_drive->drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */
-               }
-       }
-       else if (fam1_drive)
-       {
-               drvcmd[0]=CMD1_READ;
-               lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-               drvcmd[5]=(current_drive->sbp_read_frames>>8)&0x0ff;
-               drvcmd[6]=current_drive->sbp_read_frames&0x0ff;
-       }
-       else if (fam2_drive)
-       {
-               drvcmd[0]=CMD2_READ;
-               lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-               drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
-               drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
-               drvcmd[6]=0x02;
-       }
-       else if (famT_drive)
-       {
-               drvcmd[0]=CMDT_READ;
-               drvcmd[2]=(block>>24)&0x0ff;
-               drvcmd[3]=(block>>16)&0x0ff;
-               drvcmd[4]=(block>>8)&0x0ff;
-               drvcmd[5]=block&0x0ff;
-               drvcmd[7]=(current_drive->sbp_read_frames>>8)&0x0ff;
-               drvcmd[8]=current_drive->sbp_read_frames&0x0ff;
-       }
-       flags_cmd_out=f_putcmd;
-       response_count=0;
-       i=cmd_out();
-       if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i);
-       return;
-}
-/*==========================================================================*/
-/*
- *  Check the completion of the read-data command.  On success, read
- *  the current_drive->sbp_bufsiz * 2048 bytes of data from the disk into buffer.
- */
-static int sbp_data(struct request *req)
-{
-       int i=0, j=0, l, frame;
-       u_int try=0;
-       u_long timeout;
-       u_char *p;
-       u_int data_tries = 0;
-       u_int data_waits = 0;
-       u_int data_retrying = 0;
-       int error_flag;
-       int xa_count;
-       int max_latency;
-       int success;
-       int wait;
-       int duration;
-
-       error_flag=0;
-       success=0;
-#if LONG_TIMING
-       max_latency=9*HZ;
-#else
-       if (current_drive->f_multisession) max_latency=15*HZ;
-       else max_latency=5*HZ;
-#endif
-       duration=jiffies;
-       for (frame=0;frame<current_drive->sbp_read_frames&&!error_flag; frame++)
-       {
-               SBPCD_CLI;
-
-               del_timer(&data_timer);
-               data_timer.expires=jiffies+max_latency;
-               timed_out_data=0;
-               add_timer(&data_timer);
-               while (!timed_out_data)
-               {
-                       if (current_drive->f_multisession) try=maxtim_data*4;
-                       else try=maxtim_data;
-                       msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try);
-                       for ( ; try!=0;try--)
-                       {
-                               j=inb(CDi_status);
-                               if (!(j&s_not_data_ready)) break;
-                               if (!(j&s_not_result_ready)) break;
-                               if (fam0LV_drive) if (j&s_attention) break;
-                       }
-                       if (!(j&s_not_data_ready)) goto data_ready;
-                       if (try==0)
-                       {
-                               if (data_retrying == 0) data_waits++;
-                               data_retrying = 1;
-                               msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n");
-                               sbp_sleep(1);
-                               try = 1;
-                       }
-               }
-               msg(DBG_INF,"sbp_data: CDi_status loop expired.\n");
-       data_ready:
-               del_timer(&data_timer);
-
-               if (timed_out_data)
-               {
-                       msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j);
-                       error_flag++;
-               }
-               if (try==0)
-               {
-                       msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j);
-                       error_flag++;
-               }
-               if (!(j&s_not_result_ready))
-               {
-                       msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j);
-                       response_count=20;
-                       j=ResponseInfo();
-                       j=inb(CDi_status);
-               }
-               if (j&s_not_data_ready)
-               {
-                       if ((current_drive->ored_ctl_adr&0x40)==0)
-                               msg(DBG_INF, "CD contains no data tracks.\n");
-                       else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j);
-                       error_flag++;
-               }
-               SBPCD_STI;
-               if (error_flag) break;
-
-               msg(DBG_000, "sbp_data: beginning to read.\n");
-               p = current_drive->sbp_buf + frame *  CD_FRAMESIZE;
-               if (sbpro_type==1) OUT(CDo_sel_i_d,1);
-               if (cmd_type==READ_M2) {
-                        if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1);
-                        else insb(CDi_data, xa_head_buf, CD_XA_HEAD);
-               }
-               if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1);
-               else insb(CDi_data, p, CD_FRAMESIZE);
-               if (cmd_type==READ_M2) {
-                        if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1);
-                        else insb(CDi_data, xa_tail_buf, CD_XA_TAIL);
-               }
-               current_drive->sbp_current++;
-               if (sbpro_type==1) OUT(CDo_sel_i_d,0);
-               if (cmd_type==READ_M2)
-               {
-                       for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++)
-                               sprintf(&msgbuf[xa_count*3], " %02X", xa_head_buf[xa_count]);
-                       msgbuf[xa_count*3]=0;
-                       msg(DBG_XA1,"xa head:%s\n", msgbuf);
-               }
-               data_retrying = 0;
-               data_tries++;
-               if (data_tries >= 1000)
-               {
-                       msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries);
-                       data_waits = data_tries = 0;
-               }
-       }
-       duration=jiffies-duration;
-       msg(DBG_TEA,"time to read %d frames: %d jiffies .\n",frame,duration);
-       if (famT_drive)
-       {
-               wait=8;
-               do
-               {
-                       if (teac==2)
-                          {
-                            if ((i=CDi_stat_loop_T()) == -1) break;
-                          }
-                        else
-                          {
-                            sbp_sleep(1);
-                            OUT(CDo_sel_i_d,0);
-                            i=inb(CDi_status);
-                          }
-                       if (!(i&s_not_data_ready))
-                       {
-                               OUT(CDo_sel_i_d,1);
-                               j=0;
-                               do
-                               {
-                                       if (do_16bit) i=inw(CDi_data);
-                                       else i=inb(CDi_data);
-                                       j++;
-                                       i=inb(CDi_status);
-                               }
-                               while (!(i&s_not_data_ready));
-                               msg(DBG_TEA, "==========too much data (%d bytes/words)==============.\n", j);
-                       }
-                       if (!(i&s_not_result_ready))
-                       {
-                               OUT(CDo_sel_i_d,0);
-                               l=0;
-                               do
-                               {
-                                       infobuf[l++]=inb(CDi_info);
-                                       i=inb(CDi_status);
-                               }
-                               while (!(i&s_not_result_ready));
-                               if (infobuf[0]==0x00) success=1;
-#if 1
-                               for (j=0;j<l;j++) sprintf(&msgbuf[j*3], " %02X", infobuf[j]);
-                               msgbuf[j*3]=0;
-                               msg(DBG_TEA,"sbp_data info response:%s\n", msgbuf);
-#endif
-                               if (infobuf[0]==0x02)
-                               {
-                                       error_flag++;
-                                       do
-                                       {
-                                               ++recursion;
-                                               if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion);
-                                               else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n");
-                                               clr_cmdbuf();
-                                               drvcmd[0]=CMDT_READ_ERR;
-                                               j=cmd_out_T(); /* !!! recursive here !!! */
-                                               --recursion;
-                                               sbp_sleep(1);
-                                       }
-                                       while (j<0);
-                                       current_drive->error_state=infobuf[2];
-                                       current_drive->b3=infobuf[3];
-                                       current_drive->b4=infobuf[4];
-                               }
-                               break;
-                       }
-                       else
-                       {
-#if 0
-                               msg(DBG_TEA, "============= waiting for result=================.\n");
-                               sbp_sleep(1);
-#endif
-                       }
-               }
-               while (wait--);
-       }
-
-       if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
-       {
-               msg(DBG_TEA, "================error flag: %d=================.\n", error_flag);
-               msg(DBG_INF,"sbp_data: read aborted by drive.\n");
-#if 1
-               i=cc_DriveReset(); /* ugly fix to prevent a hang */
-#else
-               i=cc_ReadError();
-#endif
-               return (0);
-       }
-       
-       if (fam0LV_drive)
-       {
-               SBPCD_CLI;
-               i=maxtim_data;
-               for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--)
-               {
-                       for ( ;i!=0;i--)
-                       {
-                               j=inb(CDi_status);
-                               if (!(j&s_not_data_ready)) break;
-                               if (!(j&s_not_result_ready)) break;
-                               if (j&s_attention) break;
-                       }
-                       if (i != 0 || time_after_eq(jiffies, timeout)) break;
-                       sbp_sleep(0);
-                       i = 1;
-               }
-               if (i==0) msg(DBG_INF,"status timeout after READ.\n");
-               if (!(j&s_attention))
-               {
-                       msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n");
-                       i=cc_DriveReset();  /* ugly fix to prevent a hang */
-                       SBPCD_STI;
-                       return (0);
-               }
-               SBPCD_STI;
-       }
-
-#if 0
-       if (!success)
-#endif
-               do
-               {
-                       if (fam0LV_drive) cc_ReadStatus();
-#if 1
-                       if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i);
-#endif
-                       i=ResponseStatus();  /* builds status_bits, returns orig. status (old) or faked p_success (new) */
-#if 1
-                       if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i);
-#endif
-                       if (i<0)
-                       {
-                               msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", current_drive->status_bits);
-                               return (0);
-                       }
-               }
-               while ((fam0LV_drive)&&(!st_check)&&(!(i&p_success)));
-       if (st_check)
-       {
-               i=cc_ReadError();
-               msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i);
-               return (0);
-       }
-       if (fatal_err)
-       {
-               fatal_err=0;
-               current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1;      /* purge buffer */
-               current_drive->sbp_current = 0;
-               msg(DBG_INF,"sbp_data: fatal_err - retrying.\n");
-               return (0);
-       }
-       
-       current_drive->sbp_first_frame = req -> sector / 4;
-       current_drive->sbp_last_frame = current_drive->sbp_first_frame + current_drive->sbp_read_frames - 1;
-       sbp_transfer(req);
-       return (1);
-}
-/*==========================================================================*/
-
-static int sbpcd_block_open(struct inode *inode, struct file *file)
-{
-       struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_open(p->sbpcd_infop, inode, file);
-}
-
-static int sbpcd_block_release(struct inode *inode, struct file *file)
-{
-       struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_release(p->sbpcd_infop, file);
-}
-
-static int sbpcd_block_ioctl(struct inode *inode, struct file *file,
-                               unsigned cmd, unsigned long arg)
-{
-       struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
-       struct cdrom_device_info *cdi = p->sbpcd_infop;
-       int ret, i;
-
-       ret = cdrom_ioctl(file, p->sbpcd_infop, inode, cmd, arg);
-       if (ret != -ENOSYS)
-               return ret;
-
-       msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08lX)\n", cdi->name, cmd, arg);
-       if (p->drv_id==-1) {
-               msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name);
-               return (-ENXIO);             /* no such drive */
-       }
-       down(&ioctl_read_sem);
-       if (p != current_drive)
-               switch_drive(p);
-       
-       msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd);
-       switch (cmd)            /* Sun-compatible */
-       {
-       case DDIOCSDBG:         /* DDI Debug */
-               if (!capable(CAP_SYS_ADMIN)) RETURN_UP(-EPERM);
-               i=sbpcd_dbg_ioctl(arg,1);
-               RETURN_UP(i);
-       case CDROMRESET:      /* hard reset the drive */
-               msg(DBG_IOC,"ioctl: CDROMRESET entered.\n");
-               i=DriveReset();
-               current_drive->audio_state=0;
-               RETURN_UP(i);
-
-       case CDROMREADMODE1:
-               msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
-#ifdef SAFE_MIXED
-               if (current_drive->has_data>1) RETURN_UP(-EBUSY);
-#endif /* SAFE_MIXED */
-               cc_ModeSelect(CD_FRAMESIZE);
-               cc_ModeSense();
-               current_drive->mode=READ_M1;
-               RETURN_UP(0);
-
-       case CDROMREADMODE2: /* not usable at the moment */
-               msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
-#ifdef SAFE_MIXED
-               if (current_drive->has_data>1) RETURN_UP(-EBUSY);
-#endif /* SAFE_MIXED */
-               cc_ModeSelect(CD_FRAMESIZE_RAW1);
-               cc_ModeSense();
-               current_drive->mode=READ_M2;
-               RETURN_UP(0);
-
-       case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
-               msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
-               if (current_drive->sbp_audsiz>0)
-                       vfree(current_drive->aud_buf);
-               current_drive->aud_buf=NULL;
-               current_drive->sbp_audsiz=arg;
-
-               if (current_drive->sbp_audsiz>16)
-               {
-                       current_drive->sbp_audsiz = 0;
-                       RETURN_UP(current_drive->sbp_audsiz);
-               }
-       
-               if (current_drive->sbp_audsiz>0)
-               {
-                       current_drive->aud_buf=(u_char *) vmalloc(current_drive->sbp_audsiz*CD_FRAMESIZE_RAW);
-                       if (current_drive->aud_buf==NULL)
-                       {
-                               msg(DBG_INF,"audio buffer (%d frames) not available.\n",current_drive->sbp_audsiz);
-                               current_drive->sbp_audsiz=0;
-                       }
-                       else msg(DBG_INF,"audio buffer size: %d frames.\n",current_drive->sbp_audsiz);
-               }
-               RETURN_UP(current_drive->sbp_audsiz);
-
-       case CDROMREADAUDIO:
-       { /* start of CDROMREADAUDIO */
-               int i=0, j=0, frame, block=0;
-               u_int try=0;
-               u_long timeout;
-               u_char *p;
-               u_int data_tries = 0;
-               u_int data_waits = 0;
-               u_int data_retrying = 0;
-               int status_tries;
-               int error_flag;
-
-               msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n");
-               if (fam0_drive) RETURN_UP(-EINVAL);
-               if (famL_drive) RETURN_UP(-EINVAL);
-               if (famV_drive) RETURN_UP(-EINVAL);
-               if (famT_drive) RETURN_UP(-EINVAL);
-#ifdef SAFE_MIXED
-               if (current_drive->has_data>1) RETURN_UP(-EBUSY);
-#endif /* SAFE_MIXED */
-               if (current_drive->aud_buf==NULL) RETURN_UP(-EINVAL);
-               if (copy_from_user(&read_audio, (void __user *)arg,
-                                  sizeof(struct cdrom_read_audio)))
-                       RETURN_UP(-EFAULT);
-               if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL);
-               if (!access_ok(VERIFY_WRITE, read_audio.buf,
-                             read_audio.nframes*CD_FRAMESIZE_RAW))
-                       RETURN_UP(-EFAULT);
-
-               if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */
-                       block=msf2lba(&read_audio.addr.msf.minute);
-               else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */
-                       block=read_audio.addr.lba;
-               else RETURN_UP(-EINVAL);
-#if 000
-               i=cc_SetSpeed(speed_150,0,0);
-               if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i);
-#endif
-               msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n",
-                   block, blk2msf(block));
-               msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n");
-#if OLD_BUSY
-               while (busy_data) sbp_sleep(HZ/10); /* wait a bit */
-               busy_audio=1;
-#endif /* OLD_BUSY */
-               error_flag=0;
-               for (data_tries=5; data_tries>0; data_tries--)
-               {
-                       msg(DBG_AUD,"data_tries=%d ...\n", data_tries);
-                       current_drive->mode=READ_AU;
-                       cc_ModeSelect(CD_FRAMESIZE_RAW);
-                       cc_ModeSense();
-                       for (status_tries=3; status_tries > 0; status_tries--)
-                       {
-                               flags_cmd_out |= f_respo3;
-                               cc_ReadStatus();
-                               if (sbp_status() != 0) break;
-                               if (st_check) cc_ReadError();
-                               sbp_sleep(1);    /* wait a bit, try again */
-                       }
-                       if (status_tries == 0)
-                       {
-                               msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__);
-                               continue;
-                       }
-                       msg(DBG_AUD,"read_audio: sbp_status: ok.\n");
-
-                       flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
-                       if (fam0L_drive)
-                       {
-                               flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
-                               cmd_type=READ_M2;
-                               drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
-                               drvcmd[1]=(block>>16)&0x000000ff;
-                               drvcmd[2]=(block>>8)&0x000000ff;
-                               drvcmd[3]=block&0x000000ff;
-                               drvcmd[4]=0;
-                               drvcmd[5]=read_audio.nframes; /* # of frames */
-                               drvcmd[6]=0;
-                       }
-                       else if (fam1_drive)
-                       {
-                               drvcmd[0]=CMD1_READ; /* "read frames", new drives */
-                               lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-                               drvcmd[4]=0;
-                               drvcmd[5]=0;
-                               drvcmd[6]=read_audio.nframes; /* # of frames */
-                       }
-                       else if (fam2_drive)
-                       {
-                               drvcmd[0]=CMD2_READ_XA2;
-                               lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-                               drvcmd[4]=0;
-                               drvcmd[5]=read_audio.nframes; /* # of frames */
-                               drvcmd[6]=0x11; /* raw mode */
-                       }
-                       else if (famT_drive) /* CD-55A: not tested yet */
-                       {
-                       }
-                       msg(DBG_AUD,"read_audio: before giving \"read\" command.\n");
-                       flags_cmd_out=f_putcmd;
-                       response_count=0;
-                       i=cmd_out();
-                       if (i<0) msg(DBG_INF,"error giving READ AUDIO command: %0d\n", i);
-                       sbp_sleep(0);
-                       msg(DBG_AUD,"read_audio: after giving \"read\" command.\n");
-                       for (frame=1;frame<2 && !error_flag; frame++)
-                       {
-                               try=maxtim_data;
-                               for (timeout=jiffies+9*HZ; ; )
-                               {
-                                       for ( ; try!=0;try--)
-                                       {
-                                               j=inb(CDi_status);
-                                               if (!(j&s_not_data_ready)) break;
-                                               if (!(j&s_not_result_ready)) break;
-                                               if (fam0L_drive) if (j&s_attention) break;
-                                       }
-                                       if (try != 0 || time_after_eq(jiffies, timeout)) break;
-                                       if (data_retrying == 0) data_waits++;
-                                       data_retrying = 1;
-                                       sbp_sleep(1);
-                                       try = 1;
-                               }
-                               if (try==0)
-                               {
-                                       msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n");
-                                       error_flag++;
-                                       break;
-                               }
-                               msg(DBG_AUD,"read_audio: sbp_data: CDi_status ok.\n");
-                               if (j&s_not_data_ready)
-                               {
-                                       msg(DBG_INF, "read_audio: sbp_data: DATA_READY timeout.\n");
-                                       error_flag++;
-                                       break;
-                               }
-                               msg(DBG_AUD,"read_audio: before reading data.\n");
-                               error_flag=0;
-                               p = current_drive->aud_buf;
-                               if (sbpro_type==1) OUT(CDo_sel_i_d,1);
-                               if (do_16bit)
-                               {
-                                       u_short *p2 = (u_short *) p;
-
-                                       for (; (u_char *) p2 < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;)
-                                       {
-                                               if ((inb_p(CDi_status)&s_not_data_ready)) continue;
-
-                                               /* get one sample */
-                                               *p2++ = inw_p(CDi_data);
-                                               *p2++ = inw_p(CDi_data);
-                                       }
-                               } else {
-                                       for (; p < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;)
-                                       {
-                                               if ((inb_p(CDi_status)&s_not_data_ready)) continue;
-
-                                               /* get one sample */
-                                               *p++ = inb_p(CDi_data);
-                                               *p++ = inb_p(CDi_data);
-                                               *p++ = inb_p(CDi_data);
-                                               *p++ = inb_p(CDi_data);
-                                       }
-                               }
-                               if (sbpro_type==1) OUT(CDo_sel_i_d,0);
-                               data_retrying = 0;
-                       }
-                       msg(DBG_AUD,"read_audio: after reading data.\n");
-                       if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
-                       {
-                               msg(DBG_AUD,"read_audio: read aborted by drive\n");
-#if 0000
-                               i=cc_DriveReset();                /* ugly fix to prevent a hang */
-#else
-                               i=cc_ReadError();
-#endif
-                               continue;
-                       }
-                       if (fam0L_drive)
-                       {
-                               i=maxtim_data;
-                               for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); timeout--)
-                               {
-                                       for ( ;i!=0;i--)
-                                       {
-                                               j=inb(CDi_status);
-                                               if (!(j&s_not_data_ready)) break;
-                                               if (!(j&s_not_result_ready)) break;
-                                               if (j&s_attention) break;
-                                       }
-                                       if (i != 0 || time_after_eq(jiffies, timeout)) break;
-                                       sbp_sleep(0);
-                                       i = 1;
-                               }
-                               if (i==0) msg(DBG_AUD,"read_audio: STATUS TIMEOUT AFTER READ");
-                               if (!(j&s_attention))
-                               {
-                                       msg(DBG_AUD,"read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n");
-                                       i=cc_DriveReset();  /* ugly fix to prevent a hang */
-                                       continue;
-                               }
-                       }
-                       do
-                       {
-                               if (fam0L_drive) cc_ReadStatus();
-                               i=ResponseStatus();  /* builds status_bits, returns orig. status (old) or faked p_success (new) */
-                               if (i<0) { msg(DBG_AUD,
-                                              "read_audio: cc_ReadStatus error after read: %02X\n",
-                                              current_drive->status_bits);
-                                          continue; /* FIXME */
-                                  }
-                       }
-                       while ((fam0L_drive)&&(!st_check)&&(!(i&p_success)));
-                       if (st_check)
-                       {
-                               i=cc_ReadError();
-                               msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i);
-                               continue;
-                       }
-                       if (copy_to_user(read_audio.buf,
-                                        current_drive->aud_buf,
-                                        read_audio.nframes * CD_FRAMESIZE_RAW))
-                               RETURN_UP(-EFAULT);
-                       msg(DBG_AUD,"read_audio: copy_to_user done.\n");
-                       break;
-               }
-               cc_ModeSelect(CD_FRAMESIZE);
-               cc_ModeSense();
-               current_drive->mode=READ_M1;
-#if OLD_BUSY
-               busy_audio=0;
-#endif /* OLD_BUSY */
-               if (data_tries == 0)
-               {
-                       msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__);
-                       RETURN_UP(-EIO);
-               }
-               msg(DBG_AUD,"read_audio: successful return.\n");
-               RETURN_UP(0);
-       } /* end of CDROMREADAUDIO */
-
-       default:
-               msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
-               RETURN_UP(-EINVAL);
-       } /* end switch(cmd) */
-}
-
-static int sbpcd_block_media_changed(struct gendisk *disk)
-{
-       struct sbpcd_drive *p = disk->private_data;
-       return cdrom_media_changed(p->sbpcd_infop);
-}
-
-static struct block_device_operations sbpcd_bdops =
-{
-       .owner          = THIS_MODULE,
-       .open           = sbpcd_block_open,
-       .release        = sbpcd_block_release,
-       .ioctl          = sbpcd_block_ioctl,
-       .media_changed  = sbpcd_block_media_changed,
-};
-/*==========================================================================*/
-/*
- *  Open the device special file.  Check that a disk is in. Read TOC.
- */
-static int sbpcd_open(struct cdrom_device_info *cdi, int purpose)
-{
-       struct sbpcd_drive *p = cdi->handle;
-
-       down(&ioctl_read_sem);
-       switch_drive(p);
-
-       /*
-        * try to keep an "open" counter here and lock the door if 0->1.
-        */
-       msg(DBG_LCK,"open_count: %d -> %d\n",
-           current_drive->open_count,current_drive->open_count+1);
-       if (++current_drive->open_count<=1)
-       {
-               int i;
-               i=LockDoor();
-               current_drive->open_count=1;
-               if (famT_drive) msg(DBG_TEA,"sbpcd_open: before i=DiskInfo();.\n");
-               i=DiskInfo();
-               if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n");
-               if ((current_drive->ored_ctl_adr&0x40)==0)
-               {               
-                       msg(DBG_INF,"CD contains no data tracks.\n");
-#ifdef SAFE_MIXED
-                       current_drive->has_data=0;
-#endif /* SAFE_MIXED */
-               }
-#ifdef SAFE_MIXED
-               else if (current_drive->has_data<1) current_drive->has_data=1;
-#endif /* SAFE_MIXED */ 
-       }
-       if (!st_spinning) cc_SpinUp();
-       RETURN_UP(0);
-}
-/*==========================================================================*/
-/*
- *  On close, we flush all sbp blocks from the buffer cache.
- */
-static void sbpcd_release(struct cdrom_device_info * cdi)
-{
-       struct sbpcd_drive *p = cdi->handle;
-
-       if (p->drv_id==-1) {
-               msg(DBG_INF, "release: bad device: %s\n", cdi->name);
-               return;
-       }
-       down(&ioctl_read_sem);
-       switch_drive(p);
-       /*
-        * try to keep an "open" counter here and unlock the door if 1->0.
-        */
-       msg(DBG_LCK,"open_count: %d -> %d\n",
-           p->open_count,p->open_count-1);
-       if (p->open_count>-2) /* CDROMEJECT may have been done */
-       {
-               if (--p->open_count<=0) 
-               {
-                       p->sbp_first_frame=p->sbp_last_frame=-1;
-                       if (p->audio_state!=audio_playing)
-                               if (p->f_eject) cc_SpinDown();
-                       p->diskstate_flags &= ~cd_size_bit;
-                       p->open_count=0; 
-#ifdef SAFE_MIXED
-                       p->has_data=0;
-#endif /* SAFE_MIXED */ 
-               }
-       }
-       up(&ioctl_read_sem);
-       return ;
-}
-/*==========================================================================*/
-/*
- *
- */
-static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr);
-static struct cdrom_device_ops sbpcd_dops = {
-       .open                   = sbpcd_open,
-       .release                = sbpcd_release,
-       .drive_status           = sbpcd_drive_status,
-       .media_changed          = sbpcd_media_changed,
-       .tray_move              = sbpcd_tray_move,
-       .lock_door              = sbpcd_lock_door,
-       .select_speed           = sbpcd_select_speed,
-       .get_last_session       = sbpcd_get_last_session,
-       .get_mcn                = sbpcd_get_mcn,
-       .reset                  = sbpcd_reset,
-       .audio_ioctl            = sbpcd_audio_ioctl,
-       .capability             = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
-                               CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
-                               CDC_MCN | CDC_PLAY_AUDIO,
-       .n_minors               = 1,
-};
-
-/*==========================================================================*/
-/*
- * accept "kernel command line" parameters 
- * (suggested by Peter MacDonald with SLS 1.03)
- *
- * This is only implemented for the first controller. Should be enough to
- * allow installing with a "strange" distribution kernel.
- *
- * use: tell LILO:
- *                 sbpcd=0x230,SoundBlaster
- *             or
- *                 sbpcd=0x300,LaserMate
- *             or
- *                 sbpcd=0x338,SoundScape
- *             or
- *                 sbpcd=0x2C0,Teac16bit
- *
- * (upper/lower case sensitive here - but all-lowercase is ok!!!).
- *
- * the address value has to be the CDROM PORT ADDRESS -
- * not the soundcard base address.
- * For the SPEA/SoundScape setup, DO NOT specify the "configuration port"
- * address, but the address which is really used for the CDROM (usually 8
- * bytes above).
- *
- */
-
-int sbpcd_setup(char *s)
-{
-#ifndef MODULE
-       int p[4];
-       (void)get_options(s, ARRAY_SIZE(p), p);
-       setup_done++;
-       msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s);
-       sbpro_type=0; /* default: "LaserMate" */
-       if (p[0]>1) sbpro_type=p[2];
-       else if (!strcmp(s,str_sb)) sbpro_type=1;
-       else if (!strcmp(s,str_sb_l)) sbpro_type=1;
-       else if (!strcmp(s,str_sp)) sbpro_type=2;
-       else if (!strcmp(s,str_sp_l)) sbpro_type=2;
-       else if (!strcmp(s,str_ss)) sbpro_type=2;
-       else if (!strcmp(s,str_ss_l)) sbpro_type=2;
-       else if (!strcmp(s,str_t16)) sbpro_type=3;
-       else if (!strcmp(s,str_t16_l)) sbpro_type=3;
-       if (p[0]>0) sbpcd_ioaddr=p[1];
-       if (p[0]>2) max_drives=p[3];
-#else
-       sbpcd_ioaddr = sbpcd[0];
-       sbpro_type = sbpcd[1];
-#endif
-       
-       CDo_command=sbpcd_ioaddr;
-       CDi_info=sbpcd_ioaddr;
-       CDi_status=sbpcd_ioaddr+1;
-       CDo_sel_i_d=sbpcd_ioaddr+1;
-       CDo_reset=sbpcd_ioaddr+2;
-       CDo_enable=sbpcd_ioaddr+3; 
-       f_16bit=0;
-       if ((sbpro_type==1)||(sbpro_type==3))
-       {
-               CDi_data=sbpcd_ioaddr;
-               if (sbpro_type==3)
-                {
-                        f_16bit=1;
-                        sbpro_type=1;
-                }
-       }
-       else CDi_data=sbpcd_ioaddr+2;
-
-       return 1;
-}
-
-__setup("sbpcd=", sbpcd_setup);
-
-
-/*==========================================================================*/
-/*
- * Sequoia S-1000 CD-ROM Interface Configuration
- * as used within SPEA Media FX, Ensonic SoundScape and some Reveal cards
- * The soundcard has to get jumpered for the interface type "Panasonic"
- * (not Sony or Mitsumi) and to get soft-configured for
- *     -> configuration port address
- *     -> CDROM port offset (num_ports): has to be 8 here. Possibly this
- *        offset value determines the interface type (none, Panasonic,
- *        Mitsumi, Sony).
- *        The interface uses a configuration port (0x320, 0x330, 0x340, 0x350)
- *        some bytes below the real CDROM address.
- *         
- *        For the Panasonic style (LaserMate) interface and the configuration
- *        port 0x330, we have to use an offset of 8; so, the real CDROM port
- *        address is 0x338.
- */
-static int __init config_spea(void)
-{
-       /*
-         * base address offset between configuration port and CDROM port,
-        * this probably defines the interface type
-         *   2 (type=??): 0x00
-         *   8 (type=LaserMate):0x10
-         *  16 (type=??):0x20
-         *  32 (type=??):0x30
-         */
-       int n_ports=0x10;
-
-       int irq_number=0; /* off:0x00, 2/9:0x01, 7:0x03, 12:0x05, 15:0x07 */
-       int dma_channel=0; /* off: 0x00, 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68 */
-       int dack_polarity=0; /* L:0x00, H:0x80 */
-       int drq_polarity=0x40; /* L:0x00, H:0x40 */
-       int i;
-
-#define SPEA_REG_1 sbpcd_ioaddr-0x08+4
-#define SPEA_REG_2 sbpcd_ioaddr-0x08+5
-       
-       OUT(SPEA_REG_1,0xFF);
-       i=inb(SPEA_REG_1);
-       if (i!=0x0F)
-       {
-               msg(DBG_SEQ,"no SPEA interface at %04X present.\n", sbpcd_ioaddr);
-               return (-1); /* no interface found */
-       }
-       OUT(SPEA_REG_1,0x04);
-       OUT(SPEA_REG_2,0xC0);
-       
-       OUT(SPEA_REG_1,0x05);
-       OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity);
-       
-#if 1
-#define SPEA_PATTERN 0x80
-#else
-#define SPEA_PATTERN 0x00
-#endif
-       OUT(SPEA_REG_1,0x06);
-       OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
-       OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
-       
-       OUT(SPEA_REG_1,0x09);
-       i=(inb(SPEA_REG_2)&0xCF)|n_ports;
-       OUT(SPEA_REG_2,i);
-       
-       sbpro_type = 0; /* acts like a LaserMate interface now */
-       msg(DBG_SEQ,"found SoundScape interface at %04X.\n", sbpcd_ioaddr);
-       return (0);
-}
-
-/*==========================================================================*/
-/*
- *  Test for presence of drive and initialize it.
- *  Called once at boot or load time.
- */
-
-/* FIXME: cleanups after failed allocations are too ugly for words */
-#ifdef MODULE
-int __init __sbpcd_init(void)
-#else
-int __init sbpcd_init(void)
-#endif
-{
-       int i=0, j=0;
-       int addr[2]={1, CDROM_PORT};
-       int port_index;
-
-       sti();
-       
-       msg(DBG_INF,"sbpcd.c %s\n", VERSION);
-#ifndef MODULE
-#if DISTRIBUTION
-       if (!setup_done)
-       {
-               msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, Longshine, TEAC CD-ROM drives\n");
-               msg(DBG_INF,"= = = = = = = = = = W A R N I N G = = = = = = = = = =\n");
-               msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an NE2000 card).\n");
-               msg(DBG_INF,"If that happens, you have to reboot and use the\n");
-               msg(DBG_INF,"LILO (kernel) command line feature like:\n");
-               msg(DBG_INF,"   LILO boot: ... sbpcd=0x230,SoundBlaster\n");
-               msg(DBG_INF,"or like:\n");
-               msg(DBG_INF,"   LILO boot: ... sbpcd=0x300,LaserMate\n");
-               msg(DBG_INF,"or like:\n");
-               msg(DBG_INF,"   LILO boot: ... sbpcd=0x338,SoundScape\n");
-               msg(DBG_INF,"with your REAL address.\n");
-               msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n");
-       }
-#endif /* DISTRIBUTION */
-       sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
-       sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */
-#endif /* MODULE */
-       
-       for (port_index=0;port_index<NUM_PROBE;port_index+=2)
-       {
-               addr[1]=sbpcd[port_index];
-               if (addr[1]==0) break;
-               if (check_region(addr[1],4))
-               {
-                       msg(DBG_INF,"check_region: %03X is not free.\n",addr[1]);
-                       continue;
-               }
-               if (sbpcd[port_index+1]==2) type=str_sp;
-               else if (sbpcd[port_index+1]==1) type=str_sb;
-               else if (sbpcd[port_index+1]==3) type=str_t16;
-               else type=str_lm;
-               sbpcd_setup((char *)type);
-#if DISTRIBUTION
-               msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type);
-#endif /* DISTRIBUTION */
-               if (sbpcd[port_index+1]==2)
-               {
-                       i=config_spea();
-                       if (i<0) continue;
-               }
-#ifdef PATH_CHECK
-               if (check_card(addr[1])) continue;
-#endif /* PATH_CHECK */ 
-               i=check_drives();
-               msg(DBG_INI,"check_drives done.\n");
-               if (i>=0) break; /* drive found */
-       } /* end of cycling through the set of possible I/O port addresses */
-       
-       if (ndrives==0)
-       {
-               msg(DBG_INF, "No drive found.\n");
-#ifdef MODULE
-               return -EIO;
-#else
-               goto init_done;
-#endif /* MODULE */
-       }
-       
-       if (port_index>0)
-          {
-            msg(DBG_INF, "You should read Documentation/cdrom/sbpcd\n");
-            msg(DBG_INF, "and then configure sbpcd.h for your hardware.\n");
-          }
-       check_datarate();
-       msg(DBG_INI,"check_datarate done.\n");
-       
-       for (j=0;j<NR_SBPCD;j++)
-       {
-               struct sbpcd_drive *p = D_S + j;
-               if (p->drv_id==-1)
-                       continue;
-               switch_drive(p);
-#if 1
-               if (!famL_drive) cc_DriveReset();
-#endif
-               if (!st_spinning) cc_SpinUp();
-               p->sbp_first_frame = -1;  /* First frame in buffer */
-               p->sbp_last_frame = -1;   /* Last frame in buffer  */
-               p->sbp_read_frames = 0;   /* Number of frames being read to buffer */
-               p->sbp_current = 0;       /* Frame being currently read */
-               p->CD_changed=1;
-               p->frame_size=CD_FRAMESIZE;
-               p->f_eject=0;
-#if EJECT
-               if (!fam0_drive) p->f_eject=1;
-#endif /* EJECT */ 
-               cc_ReadStatus();
-               i=ResponseStatus();  /* returns orig. status or p_busy_new */
-               if (famT_drive) i=ResponseStatus();  /* returns orig. status or p_busy_new */
-               if (i<0)
-               {
-                       if (i!=-402)
-                               msg(DBG_INF,"init: ResponseStatus returns %d.\n",i);
-               }
-               else
-               {
-                       if (st_check)
-                       {
-                               i=cc_ReadError();
-                               msg(DBG_INI,"init: cc_ReadError returns %d\n",i);
-                       }
-               }
-               msg(DBG_INI,"init: first GetStatus: %d\n",i);
-               msg(DBG_LCS,"init: first GetStatus: error_byte=%d\n",
-                   p->error_byte);
-               if (p->error_byte==aud_12)
-               {
-                       timeout=jiffies+2*HZ;
-                       do
-                       {
-                               i=GetStatus();
-                               msg(DBG_INI,"init: second GetStatus: %02X\n",i);
-                               msg(DBG_LCS,
-                                   "init: second GetStatus: error_byte=%d\n",
-                                   p->error_byte);
-                               if (i<0) break;
-                               if (!st_caddy_in) break;
-                               }
-                       while ((!st_diskok)||time_after(jiffies, timeout));
-               }
-               i=SetSpeed();
-               if (i>=0) p->CD_changed=1;
-       }
-
-       if (!request_region(CDo_command,4,major_name))
-       {
-               printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command);
-               return -EIO;
-       }
-
-       /*
-        * Turn on the CD audio channels.
-        * The addresses are obtained from SOUND_BASE (see sbpcd.h).
-        */
-#if SOUND_BASE
-       OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */
-       OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */
-#endif /* SOUND_BASE */
-
-       if (register_blkdev(MAJOR_NR, major_name)) {
-#ifdef MODULE
-               return -EIO;
-#else
-               goto init_done;
-#endif /* MODULE */
-       }
-
-       /*
-        * init error handling is broken beyond belief in this driver...
-        */
-       sbpcd_queue = blk_init_queue(do_sbpcd_request, &sbpcd_lock);
-       if (!sbpcd_queue) {
-               release_region(CDo_command,4);
-               unregister_blkdev(MAJOR_NR, major_name);
-               return -ENOMEM;
-       }
-
-       for (j=0;j<NR_SBPCD;j++)
-       {
-               struct cdrom_device_info * sbpcd_infop;
-               struct gendisk *disk;
-               struct sbpcd_drive *p = D_S + j;
-
-               if (p->drv_id==-1) continue;
-               switch_drive(p);
-#ifdef SAFE_MIXED
-               p->has_data=0;
-#endif /* SAFE_MIXED */ 
-               /*
-                * allocate memory for the frame buffers
-                */
-               p->aud_buf=NULL;
-               p->sbp_audsiz=0;
-               p->sbp_bufsiz=buffers;
-               if (p->drv_type&drv_fam1)
-                       if (READ_AUDIO>0)
-                               p->sbp_audsiz = READ_AUDIO;
-               p->sbp_buf=(u_char *) vmalloc(buffers*CD_FRAMESIZE);
-               if (!p->sbp_buf) {
-                       msg(DBG_INF,"data buffer (%d frames) not available.\n",
-                               buffers);
-                       if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
-                       {
-                               printk("Can't unregister %s\n", major_name);
-                       }
-                       release_region(CDo_command,4);
-                       blk_cleanup_queue(sbpcd_queue);
-                       return -EIO;
-               }
-#ifdef MODULE
-               msg(DBG_INF,"data buffer size: %d frames.\n",buffers);
-#endif /* MODULE */
-               if (p->sbp_audsiz>0)
-               {
-                       p->aud_buf=(u_char *) vmalloc(p->sbp_audsiz*CD_FRAMESIZE_RAW);
-                       if (p->aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",p->sbp_audsiz);
-                       else msg(DBG_INF,"audio buffer size: %d frames.\n",p->sbp_audsiz);
-               }
-                sbpcd_infop = vmalloc(sizeof (struct cdrom_device_info));
-               if (sbpcd_infop == NULL)
-               {
-                        release_region(CDo_command,4);
-                       blk_cleanup_queue(sbpcd_queue);
-                        return -ENOMEM;
-               }
-               memset(sbpcd_infop, 0, sizeof(struct cdrom_device_info));
-               sbpcd_infop->ops = &sbpcd_dops;
-               sbpcd_infop->speed = 2;
-               sbpcd_infop->capacity = 1;
-               sprintf(sbpcd_infop->name, "sbpcd%d", j);
-               sbpcd_infop->handle = p;
-               p->sbpcd_infop = sbpcd_infop;
-               disk = alloc_disk(1);
-               disk->major = MAJOR_NR;
-               disk->first_minor = j;
-               disk->fops = &sbpcd_bdops;
-               strcpy(disk->disk_name, sbpcd_infop->name);
-               disk->flags = GENHD_FL_CD;
-               p->disk = disk;
-               if (register_cdrom(sbpcd_infop))
-               {
-                       printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n");
-               }
-               disk->private_data = p;
-               disk->queue = sbpcd_queue;
-               add_disk(disk);
-       }
-       blk_queue_hardsect_size(sbpcd_queue, CD_FRAMESIZE);
-
-#ifndef MODULE
- init_done:
-#endif
-       return 0;
-}
-/*==========================================================================*/
-#ifdef MODULE
-static void sbpcd_exit(void)
-{
-       int j;
-       
-       if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
-       {
-               msg(DBG_INF, "What's that: can't unregister %s.\n", major_name);
-               return;
-       }
-       release_region(CDo_command,4);
-       blk_cleanup_queue(sbpcd_queue);
-       for (j=0;j<NR_SBPCD;j++)
-       {
-               if (D_S[j].drv_id==-1) continue;
-               del_gendisk(D_S[j].disk);
-               put_disk(D_S[j].disk);
-               vfree(D_S[j].sbp_buf);
-               if (D_S[j].sbp_audsiz>0)
-                       vfree(D_S[j].aud_buf);
-               if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL))
-               {
-                       msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name);
-                       return;
-               }
-               vfree(D_S[j].sbpcd_infop);
-       }
-       msg(DBG_INF, "%s module released.\n", major_name);
-}
-
-
-module_init(__sbpcd_init) /*HACK!*/;
-module_exit(sbpcd_exit);
-
-
-#endif /* MODULE */
-static int sbpcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-{
-       struct sbpcd_drive *p = cdi->handle;
-       msg(DBG_CHK,"media_check (%s) called\n", cdi->name);
-       
-       if (p->CD_changed==0xFF)
-        {
-                p->CD_changed=0;
-                msg(DBG_CHK,"medium changed (drive %s)\n", cdi->name);
-               current_drive->diskstate_flags &= ~toc_bit;
-               /* we *don't* need invalidate here, it's done by caller */
-               current_drive->diskstate_flags &= ~cd_size_bit;
-#ifdef SAFE_MIXED
-               current_drive->has_data=0;
-#endif /* SAFE_MIXED */ 
-
-                return (1);
-        }
-        else
-                return (0);
-}
-
-MODULE_LICENSE("GPL");
-/* FIXME: Old modules.conf claims MATSUSHITA_CDROM2_MAJOR and CDROM3, but
-   AFAICT this doesn't support those majors, so why? --RR 30 Jul 2003 */
-MODULE_ALIAS_BLOCKDEV_MAJOR(MATSUSHITA_CDROM_MAJOR);
-
-/*==========================================================================*/
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file. 
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
-
diff --git a/drivers/cdrom/sbpcd.h b/drivers/cdrom/sbpcd.h
deleted file mode 100644 (file)
index 2f2225f..0000000
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- * sbpcd.h   Specify interface address and interface type here.
- */
-
-/*
- * Attention! This file contains user-serviceable parts!
- * I recommend to make use of it...
- * If you feel helpless, look into Documentation/cdrom/sbpcd
- * (good idea anyway, at least before mailing me).
- *
- * The definitions for the first controller can get overridden by
- * the kernel command line ("lilo boot option").
- * Examples:
- *                                 sbpcd=0x300,LaserMate
- *                             or
- *                                 sbpcd=0x230,SoundBlaster
- *                             or
- *                                 sbpcd=0x338,SoundScape
- *                             or
- *                                 sbpcd=0x2C0,Teac16bit
- *
- * If sbpcd gets used as a module, you can load it with
- *     insmod sbpcd.o sbpcd=0x300,0
- * or
- *     insmod sbpcd.o sbpcd=0x230,1
- * or
- *     insmod sbpcd.o sbpcd=0x338,2
- * or
- *     insmod sbpcd.o sbpcd=0x2C0,3
- * respective to override the configured address and type.
- */
-
-/*
- * define your CDROM port base address as CDROM_PORT
- * and specify the type of your interface card as SBPRO.
- *
- * address:
- * ========
- * SBPRO type addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
- * LASERMATE type (CI-101P, WDH-7001C) addresses typically are 0x0300, ...
- * SOUNDSCAPE addresses are from the LASERMATE type and range. You have to
- * specify the REAL address here, not the configuration port address. Look
- * at the CDROM driver's invoking line within your DOS CONFIG.SYS, or let
- * sbpcd auto-probe, if you are not firm with the address.
- * There are some soundcards on the market with 0x0630, 0x0650, ...; their
- * type is not obvious (both types are possible).
- *
- * example: if your SBPRO audio address is 0x220, specify 0x230 and SBPRO 1.
- *          if your soundcard has its CDROM port above 0x300, specify
- *          that address and try SBPRO 0 first.
- *          if your SoundScape configuration port is at 0x330, specify
- *          0x338 and SBPRO 2.
- *
- * interface type:
- * ===============
- * set SBPRO to 1 for "true" SoundBlaster card
- * set SBPRO to 0 for "compatible" soundcards and
- *                for "poor" (no sound) interface cards.
- * set SBPRO to 2 for Ensonic SoundScape or SPEA Media FX cards
- * set SBPRO to 3 for Teac 16bit interface cards
- *
- * Almost all "compatible" sound boards need to set SBPRO to 0.
- * If SBPRO is set wrong, the drives will get found - but any
- * data access will give errors (audio access will work).
- * The "OmniCD" no-sound interface card from CreativeLabs and most Teac
- * interface cards need SBPRO 1.
- *
- * sound base:
- * ===========
- * The SOUND_BASE definition tells if we should try to turn the CD sound
- * channels on. It will only be of use regarding soundcards with a SbPro
- * compatible mixer.
- *
- * Example: #define SOUND_BASE 0x220 enables the sound card's CD channels
- *          #define SOUND_BASE 0     leaves the soundcard untouched
- */
-#define CDROM_PORT 0x340 /* <-----------<< port address                      */
-#define SBPRO      0     /* <-----------<< interface type                    */
-#define MAX_DRIVES 4     /* set to 1 if the card does not use "drive select" */
-#define SOUND_BASE 0x220 /* <-----------<< sound address of this card or 0   */
-
-/*
- * some more or less user dependent definitions - service them!
- */
-
-/* Set this to 0 once you have configured your interface definitions right. */
-#define DISTRIBUTION 1
-
-/*
- * Time to wait after giving a message.
- * This gets important if you enable non-standard DBG_xxx flags.
- * You will see what happens if you omit the pause or make it
- * too short. Be warned!
- */
-#define KLOGD_PAUSE 1
-
-/* tray control: eject tray if no disk is in */
-#if DISTRIBUTION
-#define JUKEBOX 0
-#else
-#define JUKEBOX 1
-#endif /* DISTRIBUTION */
-
-/* tray control: eject tray after last use */
-#if DISTRIBUTION
-#define EJECT 0
-#else
-#define EJECT 1
-#endif /* DISTRIBUTION */
-
-/* max. number of audio frames to read with one     */
-/* request (allocates n* 2352 bytes kernel memory!) */
-/* may be freely adjusted, f.e. 75 (= 1 sec.), at   */
-/* runtime by use of the CDROMAUDIOBUFSIZ ioctl.    */
-#define READ_AUDIO 0
-
-/* Optimizations for the Teac CD-55A drive read performance.
- * SBP_TEAC_SPEED can be changed here, or one can set the 
- * variable "teac" when loading as a module.
- * Valid settings are:
- *   0 - very slow - the recommended "DISTRIBUTION 1" setup.
- *   1 - 2x performance with little overhead. No busy waiting.
- *   2 - 4x performance with 5ms overhead per read. Busy wait.
- *
- * Setting SBP_TEAC_SPEED or the variable 'teac' to anything
- * other than 0 may cause problems. If you run into them, first
- * change SBP_TEAC_SPEED back to 0 and see if your drive responds
- * normally. If yes, you are "allowed" to report your case - to help
- * me with the driver, not to solve your hassle. Don´t mail if you
- * simply are stuck into your own "tuning" experiments, you know?
- */
-#define SBP_TEAC_SPEED 1
-
-/*==========================================================================*/
-/*==========================================================================*/
-/*
- * nothing to change below here if you are not fully aware what you're doing
- */
-#ifndef _LINUX_SBPCD_H
-
-#define _LINUX_SBPCD_H
-/*==========================================================================*/
-/*==========================================================================*/
-/*
- * driver's own read_ahead, data mode
- */
-#define SBP_BUFFER_FRAMES 8 
-
-#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
-#undef  FUTURE
-#undef SAFE_MIXED
-
-#define TEST_UPC 0
-#define SPEA_TEST 0
-#define TEST_STI 0
-#define OLD_BUSY 0
-#undef PATH_CHECK
-#ifndef SOUND_BASE
-#define SOUND_BASE 0
-#endif
-#if DISTRIBUTION
-#undef SBP_TEAC_SPEED
-#define SBP_TEAC_SPEED 0
-#endif
-/*==========================================================================*/
-/*
- * DDI interface definitions
- * "invented" by Fred N. van Kempen..
- */
-#define DDIOCSDBG      0x9000
-
-/*==========================================================================*/
-/*
- * "private" IOCTL functions
- */
-#define CDROMAUDIOBUFSIZ       0x5382 /* set the audio buffer size */
-
-/*==========================================================================*/
-/*
- * Debug output levels
- */
-#define DBG_INF        1       /* necessary information */
-#define DBG_BSZ        2       /* BLOCK_SIZE trace */
-#define DBG_REA        3       /* READ status trace */
-#define DBG_CHK        4       /* MEDIA CHECK trace */
-#define DBG_TIM        5       /* datarate timer test */
-#define DBG_INI        6       /* initialization trace */
-#define DBG_TOC        7       /* tell TocEntry values */
-#define DBG_IOC        8       /* ioctl trace */
-#define DBG_STA        9       /* ResponseStatus() trace */
-#define DBG_ERR        10      /* cc_ReadError() trace */
-#define DBG_CMD        11      /* cmd_out() trace */
-#define DBG_WRN        12      /* give explanation before auto-probing */
-#define DBG_MUL        13      /* multi session code test */
-#define DBG_IDX        14      /* test code for drive_id !=0 */
-#define DBG_IOX        15      /* some special information */
-#define DBG_DID        16      /* drive ID test */
-#define DBG_RES        17      /* drive reset info */
-#define DBG_SPI        18      /* SpinUp test */
-#define DBG_IOS        19      /* ioctl trace: subchannel functions */
-#define DBG_IO2        20      /* ioctl trace: general */
-#define DBG_UPC        21      /* show UPC information */
-#define DBG_XA1        22      /* XA mode debugging */
-#define DBG_LCK        23      /* door (un)lock info */
-#define DBG_SQ1        24      /* dump SubQ frame */
-#define DBG_AUD        25      /* READ AUDIO debugging */
-#define DBG_SEQ        26      /* Sequoia interface configuration trace */
-#define DBG_LCS        27      /* Longshine LCS-7260 debugging trace */
-#define DBG_CD2        28      /* MKE/Funai CD200 debugging trace */
-#define DBG_TEA        29      /* TEAC CD-55A debugging trace */
-#define DBG_ECS        30      /* ECS-AT (Vertos 100) debugging trace */
-#define DBG_000        31      /* unnecessary information */
-
-/*==========================================================================*/
-/*==========================================================================*/
-
-/*
- * bits of flags_cmd_out:
- */
-#define f_respo3               0x100
-#define f_putcmd               0x80
-#define f_respo2               0x40
-#define f_lopsta               0x20
-#define f_getsta               0x10
-#define f_ResponseStatus       0x08
-#define f_obey_p_check         0x04
-#define f_bit1                 0x02
-#define f_wait_if_busy         0x01
-
-/*
- * diskstate_flags:
- */
-#define x80_bit                        0x80
-#define upc_bit                        0x40
-#define volume_bit             0x20
-#define toc_bit                        0x10
-#define multisession_bit       0x08
-#define cd_size_bit            0x04
-#define subq_bit               0x02
-#define frame_size_bit         0x01
-
-/*
- * disk states (bits of diskstate_flags):
- */
-#define upc_valid              (current_drive->diskstate_flags&upc_bit)
-#define volume_valid           (current_drive->diskstate_flags&volume_bit)
-#define toc_valid              (current_drive->diskstate_flags&toc_bit)
-#define cd_size_valid          (current_drive->diskstate_flags&cd_size_bit)
-#define subq_valid             (current_drive->diskstate_flags&subq_bit)
-#define frame_size_valid       (current_drive->diskstate_flags&frame_size_bit)
-
-/*
- * the status_bits variable
- */
-#define p_success      0x100
-#define p_door_closed  0x80
-#define p_caddy_in     0x40
-#define p_spinning     0x20
-#define p_check                0x10
-#define p_busy_new     0x08
-#define p_door_locked  0x04
-#define p_disk_ok      0x01
-
-/*
- * LCS-7260 special status result bits:
- */
-#define p_lcs_door_locked      0x02
-#define p_lcs_door_closed      0x01 /* probably disk_in */
-
-/*
- * CR-52x special status result bits:
- */
-#define p_caddin_old   0x40
-#define p_success_old  0x08
-#define p_busy_old     0x04
-#define p_bit_1                0x02    /* hopefully unused now */
-
-/*
- * "generation specific" defs of the status result bits:
- */
-#define p0_door_closed 0x80
-#define p0_caddy_in    0x40
-#define p0_spinning    0x20
-#define p0_check       0x10
-#define p0_success     0x08 /* unused */
-#define p0_busy                0x04
-#define p0_bit_1       0x02 /* unused */
-#define p0_disk_ok     0x01
-
-#define pL_disk_in     0x40
-#define pL_spinning    0x20
-#define pL_check       0x10
-#define pL_success     0x08 /* unused ?? */
-#define pL_busy                0x04
-#define pL_door_locked 0x02
-#define pL_door_closed 0x01
-
-#define pV_door_closed 0x40
-#define pV_spinning    0x20
-#define pV_check       0x10
-#define pV_success     0x08
-#define pV_busy                0x04
-#define pV_door_locked 0x02
-#define pV_disk_ok     0x01
-
-#define p1_door_closed 0x80
-#define p1_disk_in     0x40
-#define p1_spinning    0x20
-#define p1_check       0x10
-#define p1_busy                0x08
-#define p1_door_locked 0x04
-#define p1_bit_1       0x02 /* unused */
-#define p1_disk_ok     0x01
-
-#define p2_disk_ok     0x80
-#define p2_door_locked 0x40
-#define p2_spinning    0x20
-#define p2_busy2       0x10
-#define p2_busy1       0x08
-#define p2_door_closed 0x04
-#define p2_disk_in     0x02
-#define p2_check       0x01
-
-/*
- * used drive states:
- */
-#define st_door_closed (current_drive->status_bits&p_door_closed)
-#define st_caddy_in    (current_drive->status_bits&p_caddy_in)
-#define st_spinning    (current_drive->status_bits&p_spinning)
-#define st_check       (current_drive->status_bits&p_check)
-#define st_busy                (current_drive->status_bits&p_busy_new)
-#define st_door_locked (current_drive->status_bits&p_door_locked)
-#define st_diskok      (current_drive->status_bits&p_disk_ok)
-
-/*
- * bits of the CDi_status register:
- */
-#define s_not_result_ready     0x04 /* 0: "result ready" */
-#define s_not_data_ready       0x02 /* 0: "data ready"   */
-#define s_attention            0x01 /* 1: "attention required" */
-/*
- * usable as:
- */
-#define DRV_ATTN       ((inb(CDi_status)&s_attention)!=0)
-#define DATA_READY     ((inb(CDi_status)&s_not_data_ready)==0)
-#define RESULT_READY   ((inb(CDi_status)&s_not_result_ready)==0)
-
-/*
- * drive families and types (firmware versions):
- */
-#define drv_fam0       0x0100          /* CR-52x family */
-#define drv_199                (drv_fam0+0x01) /* <200 */
-#define drv_200                (drv_fam0+0x02) /* <201 */
-#define drv_201                (drv_fam0+0x03) /* <210 */
-#define drv_210                (drv_fam0+0x04) /* <211 */
-#define drv_211                (drv_fam0+0x05) /* <300 */
-#define drv_300                (drv_fam0+0x06) /* >=300 */
-
-#define drv_fam1       0x0200          /* CR-56x family */
-#define drv_099                (drv_fam1+0x01) /* <100 */
-#define drv_100                (drv_fam1+0x02) /* >=100, only 1.02 and 5.00 known */
-
-#define drv_fam2       0x0400          /* CD200 family */
-
-#define drv_famT       0x0800          /* TEAC CD-55A */
-
-#define drv_famL       0x1000          /* Longshine family */
-#define drv_260                (drv_famL+0x01) /* LCS-7260 */
-#define drv_e1         (drv_famL+0x01) /* LCS-7260, firmware "A E1" */
-#define drv_f4         (drv_famL+0x02) /* LCS-7260, firmware "A4F4" */
-
-#define drv_famV       0x2000          /* ECS-AT (vertos-100) family */
-#define drv_at         (drv_famV+0x01) /* ECS-AT, firmware "1.00" */
-
-#define fam0_drive     (current_drive->drv_type&drv_fam0)
-#define famL_drive     (current_drive->drv_type&drv_famL)
-#define famV_drive     (current_drive->drv_type&drv_famV)
-#define fam1_drive     (current_drive->drv_type&drv_fam1)
-#define fam2_drive     (current_drive->drv_type&drv_fam2)
-#define famT_drive     (current_drive->drv_type&drv_famT)
-#define fam0L_drive    (current_drive->drv_type&(drv_fam0|drv_famL))
-#define fam0V_drive    (current_drive->drv_type&(drv_fam0|drv_famV))
-#define famLV_drive    (current_drive->drv_type&(drv_famL|drv_famV))
-#define fam0LV_drive   (current_drive->drv_type&(drv_fam0|drv_famL|drv_famV))
-#define fam1L_drive    (current_drive->drv_type&(drv_fam1|drv_famL))
-#define fam1V_drive    (current_drive->drv_type&(drv_fam1|drv_famV))
-#define fam1LV_drive   (current_drive->drv_type&(drv_fam1|drv_famL|drv_famV))
-#define fam01_drive    (current_drive->drv_type&(drv_fam0|drv_fam1))
-#define fam12_drive    (current_drive->drv_type&(drv_fam1|drv_fam2))
-#define fam2T_drive    (current_drive->drv_type&(drv_fam2|drv_famT))
-
-/*
- * audio states:
- */
-#define audio_completed        3 /* Forgot this one! --AJK */
-#define audio_playing  2
-#define audio_pausing  1
-
-/*
- * drv_pattern, drv_options:
- */
-#define speed_auto     0x80
-#define speed_300      0x40
-#define speed_150      0x20
-#define audio_mono     0x04
-
-/*
- * values of cmd_type (0 else):
- */
-#define READ_M1        0x01    /* "data mode 1": 2048 bytes per frame */
-#define READ_M2        0x02    /* "data mode 2": 12+2048+280 bytes per frame */
-#define READ_SC        0x04    /* "subchannel info": 96 bytes per frame */
-#define READ_AU        0x08    /* "audio frame": 2352 bytes per frame */
-
-/*
- * sense_byte:
- *
- *          values: 00
- *                  01
- *                  81
- *                  82 "raw audio" mode
- *                  xx from infobuf[0] after 85 00 00 00 00 00 00
- */
-
-/* audio status (bin) */
-#define aud_00 0x00 /* Audio status byte not supported or not valid */
-#define audx11 0x0b /* Audio play operation in progress             */
-#define audx12 0x0c /* Audio play operation paused                  */
-#define audx13 0x0d /* Audio play operation successfully completed  */
-#define audx14 0x0e /* Audio play operation stopped due to error    */
-#define audx15 0x0f /* No current audio status to return            */
-/* audio status (bcd) */
-#define aud_11 0x11 /* Audio play operation in progress             */
-#define aud_12 0x12 /* Audio play operation paused                  */
-#define aud_13 0x13 /* Audio play operation successfully completed  */
-#define aud_14 0x14 /* Audio play operation stopped due to error    */
-#define aud_15 0x15 /* No current audio status to return            */
-
-/*
- * highest allowed drive number (MINOR+1)
- */
-#define NR_SBPCD       4
-
-/*
- * we try to never disable interrupts - seems to work
- */
-#define SBPCD_DIS_IRQ  0
-
-/*
- * "write byte to port"
- */
-#define OUT(x,y)       outb(y,x)
-
-/*==========================================================================*/
-
-#define MIXER_addr SOUND_BASE+4 /* sound card's address register */
-#define MIXER_data SOUND_BASE+5 /* sound card's data register */
-#define MIXER_CD_Volume        0x28    /* internal SB Pro register address */
-
-/*==========================================================================*/
-
-#define MAX_TRACKS     99
-
-#define ERR_DISKCHANGE 615
-
-/*==========================================================================*/
-/*
- * To make conversions easier (machine dependent!)
- */
-typedef union _msf
-{
-       u_int n;
-       u_char c[4];
-} MSF;
-
-typedef union _blk
-{
-       u_int n;
-       u_char c[4];
-} BLK;
-
-/*==========================================================================*/
-
-/*============================================================================
-==============================================================================
-
-COMMAND SET of "old" drives like CR-521, CR-522
-               (the CR-562 family is different):
-
-No.    Command                        Code
---------------------------------------------
-
-Drive Commands:
- 1     Seek                            01      
- 2     Read Data                       02
- 3     Read XA-Data                    03
- 4     Read Header                     04
- 5     Spin Up                         05
- 6     Spin Down                       06
- 7     Diagnostic                      07
- 8     Read UPC                        08
- 9     Read ISRC                       09
-10     Play Audio                      0A
-11     Play Audio MSF                  0B
-12     Play Audio Track/Index          0C
-
-Status Commands:
-13     Read Status                     81      
-14     Read Error                      82
-15     Read Drive Version              83
-16     Mode Select                     84
-17     Mode Sense                      85
-18     Set XA Parameter                86
-19     Read XA Parameter               87
-20     Read Capacity                   88
-21     Read SUB_Q                      89
-22     Read Disc Code                  8A
-23     Read Disc Information           8B
-24     Read TOC                        8C
-25     Pause/Resume                    8D
-26     Read Packet                     8E
-27     Read Path Check                 00
-all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first
-
-mnemo     7-byte command        #bytes response (r0...rn)
-________ ____________________  ____ 
-
-Read Status:
-status:  81.                    (1)  one-byte command, gives the main
-                                                          status byte
-Read Error:
-check1:  82 00 00 00 00 00 00.  (6)  r1: audio status
-
-Read Packet:
-check2:  8e xx 00 00 00 00 00. (xx)  gets xx bytes response, relating
-                                        to commands 01 04 05 07 08 09
-
-Play Audio:
-play:    0a ll-bb-aa nn-nn-nn.  (0)  play audio, ll-bb-aa: starting block (lba),
-                                                 nn-nn-nn: #blocks
-Play Audio MSF:
-         0b mm-ss-ff mm-ss-ff   (0)  play audio from/to
-
-Play Audio Track/Index:
-         0c ...
-
-Pause/Resume:
-pause:   8d pr 00 00 00 00 00.  (0)  pause (pr=00) 
-                                     resume (pr=80) audio playing
-
-Mode Select:
-         84 00 nn-nn ??.?? 00   (0)  nn-nn: 2048 or 2340
-                                     possibly defines transfer size
-
-set_vol: 84 83 00 00 sw le 00.  (0)  sw(itch): lrxxxxxx (off=1)
-                                     le(vel): min=0, max=FF, else half
-                                    (firmware 2.11)
-
-Mode Sense:
-get_vol: 85 03 00 00 00 00 00.  (2)  tell current audio volume setting
-
-Read Disc Information:
-tocdesc: 8b 00 00 00 00 00 00.  (6)  read the toc descriptor ("msf-bin"-format)
-
-Read TOC:
-tocent:  8c fl nn 00 00 00 00.  (8)  read toc entry #nn
-                                       (fl=0:"lba"-, =2:"msf-bin"-format)
-
-Read Capacity:
-capacit: 88 00 00 00 00 00 00.  (5)  "read CD-ROM capacity"
-
-
-Read Path Check:
-ping:    00 00 00 00 00 00 00.  (2)  r0=AA, r1=55
-                                     ("ping" if the drive is connected)
-
-Read Drive Version:
-ident:   83 00 00 00 00 00 00. (12)  gives "MATSHITAn.nn" 
-                                     (n.nn = 2.01, 2.11., 3.00, ...)
-
-Seek:
-seek:    01 00 ll-bb-aa 00 00.  (0)  
-seek:    01 02 mm-ss-ff 00 00.  (0)  
-
-Read Data:
-read:    02 xx-xx-xx nn-nn fl.  (?)  read nn-nn blocks of 2048 bytes,
-                                     starting at block xx-xx-xx  
-                                     fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx
-
-Read XA-Data:
-read:    03 xx-xx-xx nn-nn fl.  (?)  read nn-nn blocks of 2340 bytes, 
-                                     starting at block xx-xx-xx
-                                     fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx
-
-Read SUB_Q:
-         89 fl 00 00 00 00 00. (13)  r0: audio status, r4-r7: lba/msf, 
-                                       fl=0: "lba", fl=2: "msf"
-
-Read Disc Code:
-         8a 00 00 00 00 00 00. (14)  possibly extended "check condition"-info
-
-Read Header:
-         04 00 ll-bb-aa 00 00.  (0)   4 bytes response with "check2"
-         04 02 mm-ss-ff 00 00.  (0)   4 bytes response with "check2"
-
-Spin Up:
-         05 00 ll-bb-aa 00 00.  (0)  possibly implies a "seek"
-
-Spin Down:
-         06 ...
-
-Diagnostic:
-         07 00 ll-bb-aa 00 00.  (2)   2 bytes response with "check2"
-         07 02 mm-ss-ff 00 00.  (2)   2 bytes response with "check2"
-
-Read UPC:
-         08 00 ll-bb-aa 00 00. (16)  
-         08 02 mm-ss-ff 00 00. (16)  
-
-Read ISRC:
-         09 00 ll-bb-aa 00 00. (15)  15 bytes response with "check2"
-         09 02 mm-ss-ff 00 00. (15)  15 bytes response with "check2"
-
-Set XA Parameter:
-         86 ...
-
-Read XA Parameter:
-         87 ...
-
-==============================================================================
-============================================================================*/
-
-/*
- * commands
- *
- * CR-52x:      CMD0_
- * CR-56x:      CMD1_
- * CD200:       CMD2_
- * LCS-7260:    CMDL_
- * TEAC CD-55A: CMDT_
- * ECS-AT:      CMDV_
- */
-#define CMD1_RESET     0x0a
-#define CMD2_RESET     0x01
-#define CMDT_RESET     0xc0
-
-#define CMD1_LOCK_CTL  0x0c
-#define CMD2_LOCK_CTL  0x1e
-#define CMDT_LOCK_CTL  CMD2_LOCK_CTL
-#define CMDL_LOCK_CTL  0x0e
-#define CMDV_LOCK_CTL  CMDL_LOCK_CTL
-
-#define CMD1_TRAY_CTL  0x07
-#define CMD2_TRAY_CTL  0x1b
-#define CMDT_TRAY_CTL  CMD2_TRAY_CTL
-#define CMDL_TRAY_CTL  0x0d
-#define CMDV_TRAY_CTL  CMDL_TRAY_CTL
-
-#define CMD1_MULTISESS 0x8d
-#define CMDL_MULTISESS 0x8c
-#define CMDV_MULTISESS CMDL_MULTISESS
-
-#define CMD1_SUBCHANINF        0x11
-#define CMD2_SUBCHANINF        0x??
-
-#define CMD1_ABORT     0x08
-#define CMD2_ABORT     0x08
-#define CMDT_ABORT     0x08
-
-#define CMD2_x02       0x02
-
-#define CMD2_SETSPEED  0xda
-
-#define CMD0_PATH_CHECK        0x00
-#define CMD1_PATH_CHECK        0x???
-#define CMD2_PATH_CHECK        0x???
-#define CMDT_PATH_CHECK        0x???
-#define CMDL_PATH_CHECK        CMD0_PATH_CHECK
-#define CMDV_PATH_CHECK        CMD0_PATH_CHECK
-
-#define CMD0_SEEK      0x01
-#define CMD1_SEEK      CMD0_SEEK
-#define CMD2_SEEK      0x2b
-#define CMDT_SEEK      CMD2_SEEK
-#define CMDL_SEEK      CMD0_SEEK
-#define CMDV_SEEK      CMD0_SEEK
-
-#define CMD0_READ      0x02
-#define CMD1_READ      0x10
-#define CMD2_READ      0x28
-#define CMDT_READ      CMD2_READ
-#define CMDL_READ      CMD0_READ
-#define CMDV_READ      CMD0_READ
-
-#define CMD0_READ_XA   0x03
-#define CMD2_READ_XA   0xd4
-#define CMD2_READ_XA2  0xd5
-#define CMDL_READ_XA   CMD0_READ_XA /* really ?? */
-#define CMDV_READ_XA   CMD0_READ_XA
-
-#define CMD0_READ_HEAD 0x04
-
-#define CMD0_SPINUP    0x05
-#define CMD1_SPINUP    0x02
-#define CMD2_SPINUP    CMD2_TRAY_CTL
-#define CMDL_SPINUP    CMD0_SPINUP
-#define CMDV_SPINUP    CMD0_SPINUP
-
-#define CMD0_SPINDOWN  0x06 /* really??? */
-#define CMD1_SPINDOWN  0x06
-#define CMD2_SPINDOWN  CMD2_TRAY_CTL
-#define CMDL_SPINDOWN  0x0d
-#define CMDV_SPINDOWN  CMD0_SPINDOWN
-
-#define CMD0_DIAG      0x07
-
-#define CMD0_READ_UPC  0x08
-#define CMD1_READ_UPC  0x88
-#define CMD2_READ_UPC  0x???
-#define CMDL_READ_UPC  CMD0_READ_UPC
-#define CMDV_READ_UPC  0x8f
-
-#define CMD0_READ_ISRC 0x09
-
-#define CMD0_PLAY      0x0a
-#define CMD1_PLAY      0x???
-#define CMD2_PLAY      0x???
-#define CMDL_PLAY      CMD0_PLAY
-#define CMDV_PLAY      CMD0_PLAY
-
-#define CMD0_PLAY_MSF  0x0b
-#define CMD1_PLAY_MSF  0x0e
-#define CMD2_PLAY_MSF  0x47
-#define CMDT_PLAY_MSF  CMD2_PLAY_MSF
-#define CMDL_PLAY_MSF  0x???
-
-#define CMD0_PLAY_TI   0x0c
-#define CMD1_PLAY_TI   0x0f
-
-#define CMD0_STATUS    0x81
-#define CMD1_STATUS    0x05
-#define CMD2_STATUS    0x00
-#define CMDT_STATUS    CMD2_STATUS
-#define CMDL_STATUS    CMD0_STATUS
-#define CMDV_STATUS    CMD0_STATUS
-#define CMD2_SEEK_LEADIN 0x00
-
-#define CMD0_READ_ERR  0x82
-#define CMD1_READ_ERR  CMD0_READ_ERR
-#define CMD2_READ_ERR  0x03
-#define CMDT_READ_ERR  CMD2_READ_ERR /* get audio status */
-#define CMDL_READ_ERR  CMD0_READ_ERR
-#define CMDV_READ_ERR  CMD0_READ_ERR
-
-#define CMD0_READ_VER  0x83
-#define CMD1_READ_VER  CMD0_READ_VER
-#define CMD2_READ_VER  0x12
-#define CMDT_READ_VER  CMD2_READ_VER /* really ?? */
-#define CMDL_READ_VER  CMD0_READ_VER
-#define CMDV_READ_VER  CMD0_READ_VER
-
-#define CMD0_SETMODE   0x84
-#define CMD1_SETMODE   0x09
-#define CMD2_SETMODE   0x55
-#define CMDT_SETMODE   CMD2_SETMODE
-#define CMDL_SETMODE   CMD0_SETMODE
-
-#define CMD0_GETMODE   0x85
-#define CMD1_GETMODE   0x84
-#define CMD2_GETMODE   0x5a
-#define CMDT_GETMODE   CMD2_GETMODE
-#define CMDL_GETMODE   CMD0_GETMODE
-
-#define CMD0_SET_XA    0x86
-
-#define CMD0_GET_XA    0x87
-
-#define CMD0_CAPACITY  0x88
-#define CMD1_CAPACITY  0x85
-#define CMD2_CAPACITY  0x25
-#define CMDL_CAPACITY  CMD0_CAPACITY /* missing in some firmware versions */
-
-#define CMD0_READSUBQ  0x89
-#define CMD1_READSUBQ  0x87
-#define CMD2_READSUBQ  0x42
-#define CMDT_READSUBQ  CMD2_READSUBQ
-#define CMDL_READSUBQ  CMD0_READSUBQ
-#define CMDV_READSUBQ  CMD0_READSUBQ
-
-#define CMD0_DISKCODE  0x8a
-
-#define CMD0_DISKINFO  0x8b
-#define CMD1_DISKINFO  CMD0_DISKINFO
-#define CMD2_DISKINFO  0x43
-#define CMDT_DISKINFO  CMD2_DISKINFO
-#define CMDL_DISKINFO  CMD0_DISKINFO
-#define CMDV_DISKINFO  CMD0_DISKINFO
-
-#define CMD0_READTOC   0x8c
-#define CMD1_READTOC   CMD0_READTOC
-#define CMD2_READTOC   0x???
-#define CMDL_READTOC   CMD0_READTOC
-#define CMDV_READTOC   CMD0_READTOC
-
-#define CMD0_PAU_RES   0x8d
-#define CMD1_PAU_RES   0x0d
-#define CMD2_PAU_RES   0x4b
-#define CMDT_PAUSE     CMD2_PAU_RES
-#define CMDL_PAU_RES   CMD0_PAU_RES
-#define CMDV_PAUSE     CMD0_PAU_RES
-
-#define CMD0_PACKET    0x8e
-#define CMD1_PACKET    CMD0_PACKET
-#define CMD2_PACKET    0x???
-#define CMDL_PACKET    CMD0_PACKET
-#define CMDV_PACKET    0x???
-
-/*==========================================================================*/
-/*==========================================================================*/
-#endif /* _LINUX_SBPCD_H */
-/*==========================================================================*/
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file. 
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
deleted file mode 100644 (file)
index 5409fca..0000000
+++ /dev/null
@@ -1,1815 +0,0 @@
-/* -- sjcd.c
- *
- *   Sanyo CD-ROM device driver implementation, Version 1.6
- *   Copyright (C) 1995  Vadim V. Model
- *
- *   model@cecmow.enet.dec.com
- *   vadim@rbrf.ru
- *   vadim@ipsun.ras.ru
- *
- *
- *  This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de);
- *  it was developed under use of mcd.c from Martin Harriss, with help of
- *  Eric van der Maarel (H.T.M.v.d.Maarel@marin.nl).
- *
- *  It is planned to include these routines into sbpcd.c later - to make
- *  a "mixed use" on one cable possible for all kinds of drives which use
- *  the SoundBlaster/Panasonic style CDROM interface. But today, the
- *  ability to install directly from CDROM is more important than flexibility.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  History:
- *  1.1 First public release with kernel version 1.3.7.
- *      Written by Vadim Model.
- *  1.2 Added detection and configuration of cdrom interface
- *      on ISP16 soundcard.
- *      Allow for command line options: sjcd=<io_base>,<irq>,<dma>
- *  1.3 Some minor changes to README.sjcd.
- *  1.4 MSS Sound support!! Listen to a CD through the speakers.
- *  1.5 Module support and bugfixes.
- *      Tray locking.
- *  1.6 Removed ISP16 code from this driver.
- *      Allow only to set io base address on command line: sjcd=<io_base>
- *      Changes to Documentation/cdrom/sjcd
- *      Added cleanup after any error in the initialisation.
- *  1.7 Added code to set the sector size tables to prevent the bug present in 
- *      the previous version of this driver.  Coded added by Anthony Barbachan 
- *      from bugfix tip originally suggested by Alan Cox.
- *
- *  November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                  Removed init_module & cleanup_module in favor of 
- *                  module_init & module_exit.
- *                  Torben Mathiasen <tmm@image.dk>
- */
-
-#define SJCD_VERSION_MAJOR 1
-#define SJCD_VERSION_MINOR 7
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/major.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/blkdev.h>
-#include "sjcd.h"
-
-static int sjcd_present = 0;
-static struct request_queue *sjcd_queue;
-
-#define MAJOR_NR SANYO_CDROM_MAJOR
-#define QUEUE (sjcd_queue)
-#define CURRENT elv_next_request(sjcd_queue)
-
-#define SJCD_BUF_SIZ 32                /* cdr-h94a has internal 64K buffer */
-
-/*
- * buffer for block size conversion
- */
-static char sjcd_buf[2048 * SJCD_BUF_SIZ];
-static volatile int sjcd_buf_bn[SJCD_BUF_SIZ], sjcd_next_bn;
-static volatile int sjcd_buf_in, sjcd_buf_out = -1;
-
-/*
- * Status.
- */
-static unsigned short sjcd_status_valid = 0;
-static unsigned short sjcd_door_closed;
-static unsigned short sjcd_door_was_open;
-static unsigned short sjcd_media_is_available;
-static unsigned short sjcd_media_is_changed;
-static unsigned short sjcd_toc_uptodate = 0;
-static unsigned short sjcd_command_failed;
-static volatile unsigned char sjcd_completion_status = 0;
-static volatile unsigned char sjcd_completion_error = 0;
-static unsigned short sjcd_command_is_in_progress = 0;
-static unsigned short sjcd_error_reported = 0;
-static DEFINE_SPINLOCK(sjcd_lock);
-
-static int sjcd_open_count;
-
-static int sjcd_audio_status;
-static struct sjcd_play_msf sjcd_playing;
-
-static int sjcd_base = SJCD_BASE_ADDR;
-
-module_param(sjcd_base, int, 0);
-
-static DECLARE_WAIT_QUEUE_HEAD(sjcd_waitq);
-
-/*
- * Data transfer.
- */
-static volatile unsigned short sjcd_transfer_is_active = 0;
-
-enum sjcd_transfer_state {
-       SJCD_S_IDLE = 0,
-       SJCD_S_START = 1,
-       SJCD_S_MODE = 2,
-       SJCD_S_READ = 3,
-       SJCD_S_DATA = 4,
-       SJCD_S_STOP = 5,
-       SJCD_S_STOPPING = 6
-};
-static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE;
-static long sjcd_transfer_timeout = 0;
-static int sjcd_read_count = 0;
-static unsigned char sjcd_mode = 0;
-
-#define SJCD_READ_TIMEOUT 5000
-
-#if defined( SJCD_GATHER_STAT )
-/*
- * Statistic.
- */
-static struct sjcd_stat statistic;
-#endif
-
-/*
- * Timer.
- */
-static DEFINE_TIMER(sjcd_delay_timer, NULL, 0, 0);
-
-#define SJCD_SET_TIMER( func, tmout )           \
-    ( sjcd_delay_timer.expires = jiffies+tmout,         \
-      sjcd_delay_timer.function = ( void * )func, \
-      add_timer( &sjcd_delay_timer ) )
-
-#define CLEAR_TIMER del_timer( &sjcd_delay_timer )
-
-/*
- * Set up device, i.e., use command line data to set
- * base address.
- */
-#ifndef MODULE
-static int __init sjcd_setup(char *str)
-{
-       int ints[2];
-       (void) get_options(str, ARRAY_SIZE(ints), ints);
-       if (ints[0] > 0)
-               sjcd_base = ints[1];
-
-       return 1;
-}
-
-__setup("sjcd=", sjcd_setup);
-
-#endif
-
-/*
- * Special converters.
- */
-static unsigned char bin2bcd(int bin)
-{
-       int u, v;
-
-       u = bin % 10;
-       v = bin / 10;
-       return (u | (v << 4));
-}
-
-static int bcd2bin(unsigned char bcd)
-{
-       return ((bcd >> 4) * 10 + (bcd & 0x0F));
-}
-
-static long msf2hsg(struct msf *mp)
-{
-       return (bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75
-               + bcd2bin(mp->min) * 4500 - 150);
-}
-
-static void hsg2msf(long hsg, struct msf *msf)
-{
-       hsg += 150;
-       msf->min = hsg / 4500;
-       hsg %= 4500;
-       msf->sec = hsg / 75;
-       msf->frame = hsg % 75;
-       msf->min = bin2bcd(msf->min);   /* convert to BCD */
-       msf->sec = bin2bcd(msf->sec);
-       msf->frame = bin2bcd(msf->frame);
-}
-
-/*
- * Send a command to cdrom. Invalidate status.
- */
-static void sjcd_send_cmd(unsigned char cmd)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: send_cmd( 0x%x )\n", cmd);
-#endif
-       outb(cmd, SJCDPORT(0));
-       sjcd_command_is_in_progress = 1;
-       sjcd_status_valid = 0;
-       sjcd_command_failed = 0;
-}
-
-/*
- * Send a command with one arg to cdrom. Invalidate status.
- */
-static void sjcd_send_1_cmd(unsigned char cmd, unsigned char a)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: send_1_cmd( 0x%x, 0x%x )\n", cmd, a);
-#endif
-       outb(cmd, SJCDPORT(0));
-       outb(a, SJCDPORT(0));
-       sjcd_command_is_in_progress = 1;
-       sjcd_status_valid = 0;
-       sjcd_command_failed = 0;
-}
-
-/*
- * Send a command with four args to cdrom. Invalidate status.
- */
-static void sjcd_send_4_cmd(unsigned char cmd, unsigned char a,
-                           unsigned char b, unsigned char c,
-                           unsigned char d)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: send_4_cmd( 0x%x )\n", cmd);
-#endif
-       outb(cmd, SJCDPORT(0));
-       outb(a, SJCDPORT(0));
-       outb(b, SJCDPORT(0));
-       outb(c, SJCDPORT(0));
-       outb(d, SJCDPORT(0));
-       sjcd_command_is_in_progress = 1;
-       sjcd_status_valid = 0;
-       sjcd_command_failed = 0;
-}
-
-/*
- * Send a play or read command to cdrom. Invalidate Status.
- */
-static void sjcd_send_6_cmd(unsigned char cmd, struct sjcd_play_msf *pms)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: send_long_cmd( 0x%x )\n", cmd);
-#endif
-       outb(cmd, SJCDPORT(0));
-       outb(pms->start.min, SJCDPORT(0));
-       outb(pms->start.sec, SJCDPORT(0));
-       outb(pms->start.frame, SJCDPORT(0));
-       outb(pms->end.min, SJCDPORT(0));
-       outb(pms->end.sec, SJCDPORT(0));
-       outb(pms->end.frame, SJCDPORT(0));
-       sjcd_command_is_in_progress = 1;
-       sjcd_status_valid = 0;
-       sjcd_command_failed = 0;
-}
-
-/*
- * Get a value from the data port. Should not block, so we use a little
- * wait for a while. Returns 0 if OK.
- */
-static int sjcd_load_response(void *buf, int len)
-{
-       unsigned char *resp = (unsigned char *) buf;
-
-       for (; len; --len) {
-               int i;
-               for (i = 200;
-                    i-- && !SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1))););
-               if (i > 0)
-                       *resp++ = (unsigned char) inb(SJCDPORT(0));
-               else
-                       break;
-       }
-       return (len);
-}
-
-/*
- * Load and parse command completion status (drive info byte and maybe error).
- * Sorry, no error classification yet.
- */
-static void sjcd_load_status(void)
-{
-       sjcd_media_is_changed = 0;
-       sjcd_completion_error = 0;
-       sjcd_completion_status = inb(SJCDPORT(0));
-       if (sjcd_completion_status & SST_DOOR_OPENED) {
-               sjcd_door_closed = sjcd_media_is_available = 0;
-       } else {
-               sjcd_door_closed = 1;
-               if (sjcd_completion_status & SST_MEDIA_CHANGED)
-                       sjcd_media_is_available = sjcd_media_is_changed =
-                           1;
-               else if (sjcd_completion_status & 0x0F) {
-                       /*
-                        * OK, we seem to catch an error ...
-                        */
-                       while (!SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1))));
-                       sjcd_completion_error = inb(SJCDPORT(0));
-                       if ((sjcd_completion_status & 0x08) &&
-                           (sjcd_completion_error & 0x40))
-                               sjcd_media_is_available = 0;
-                       else
-                               sjcd_command_failed = 1;
-               } else
-                       sjcd_media_is_available = 1;
-       }
-       /*
-        * Ok, status loaded successfully.
-        */
-       sjcd_status_valid = 1, sjcd_error_reported = 0;
-       sjcd_command_is_in_progress = 0;
-
-       /*
-        * If the disk is changed, the TOC is not valid.
-        */
-       if (sjcd_media_is_changed)
-               sjcd_toc_uptodate = 0;
-#if defined( SJCD_TRACE )
-       printk("SJCD: status %02x.%02x loaded.\n",
-              (int) sjcd_completion_status, (int) sjcd_completion_error);
-#endif
-}
-
-/*
- * Read status from cdrom. Check to see if the status is available.
- */
-static int sjcd_check_status(void)
-{
-       /*
-        * Try to load the response from cdrom into buffer.
-        */
-       if (SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))) {
-               sjcd_load_status();
-               return (1);
-       } else {
-               /*
-                * No status is available.
-                */
-               return (0);
-       }
-}
-
-/*
- * This is just timeout counter, and nothing more. Surprised ? :-)
- */
-static volatile long sjcd_status_timeout;
-
-/*
- * We need about 10 seconds to wait. The longest command takes about 5 seconds
- * to probe the disk (usually after tray closed or drive reset). Other values
- * should be thought of for other commands.
- */
-#define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000
-
-static void sjcd_status_timer(void)
-{
-       if (sjcd_check_status()) {
-               /*
-                * The command completed and status is loaded, stop waiting.
-                */
-               wake_up(&sjcd_waitq);
-       } else if (--sjcd_status_timeout <= 0) {
-               /*
-                * We are timed out. 
-                */
-               wake_up(&sjcd_waitq);
-       } else {
-               /*
-                * We have still some time to wait. Try again.
-                */
-               SJCD_SET_TIMER(sjcd_status_timer, 1);
-       }
-}
-
-/*
- * Wait for status for 10 sec approx. Returns non-positive when timed out.
- * Should not be used while reading data CDs.
- */
-static int sjcd_wait_for_status(void)
-{
-       sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT;
-       SJCD_SET_TIMER(sjcd_status_timer, 1);
-       sleep_on(&sjcd_waitq);
-#if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE )
-       if (sjcd_status_timeout <= 0)
-               printk("SJCD: Error Wait For Status.\n");
-#endif
-       return (sjcd_status_timeout);
-}
-
-static int sjcd_receive_status(void)
-{
-       int i;
-#if defined( SJCD_TRACE )
-       printk("SJCD: receive_status\n");
-#endif
-       /*
-        * Wait a bit for status available.
-        */
-       for (i = 200; i-- && (sjcd_check_status() == 0););
-       if (i < 0) {
-#if defined( SJCD_TRACE )
-               printk("SJCD: long wait for status\n");
-#endif
-               if (sjcd_wait_for_status() <= 0)
-                       printk("SJCD: Timeout when read status.\n");
-               else
-                       i = 0;
-       }
-       return (i);
-}
-
-/*
- * Load the status. Issue get status command and wait for status available.
- */
-static void sjcd_get_status(void)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: get_status\n");
-#endif
-       sjcd_send_cmd(SCMD_GET_STATUS);
-       sjcd_receive_status();
-}
-
-/*
- * Check the drive if the disk is changed. Should be revised.
- */
-static int sjcd_disk_change(struct gendisk *disk)
-{
-#if 0
-       printk("SJCD: sjcd_disk_change(%s)\n", disk->disk_name);
-#endif
-       if (!sjcd_command_is_in_progress)
-               sjcd_get_status();
-       return (sjcd_status_valid ? sjcd_media_is_changed : 0);
-}
-
-/*
- * Read the table of contents (TOC) and TOC header if necessary.
- * We assume that the drive contains no more than 99 toc entries.
- */
-static struct sjcd_hw_disk_info sjcd_table_of_contents[SJCD_MAX_TRACKS];
-static unsigned char sjcd_first_track_no, sjcd_last_track_no;
-#define sjcd_disk_length  sjcd_table_of_contents[0].un.track_msf
-
-static int sjcd_update_toc(void)
-{
-       struct sjcd_hw_disk_info info;
-       int i;
-#if defined( SJCD_TRACE )
-       printk("SJCD: update toc:\n");
-#endif
-       /*
-        * check to see if we need to do anything
-        */
-       if (sjcd_toc_uptodate)
-               return (0);
-
-       /*
-        * Get the TOC start information.
-        */
-       sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK);
-       sjcd_receive_status();
-
-       if (!sjcd_status_valid) {
-               printk("SJCD: cannot load status.\n");
-               return (-1);
-       }
-
-       if (!sjcd_media_is_available) {
-               printk("SJCD: no disk in drive\n");
-               return (-1);
-       }
-
-       if (!sjcd_command_failed) {
-               if (sjcd_load_response(&info, sizeof(info)) != 0) {
-                       printk
-                           ("SJCD: cannot load response about TOC start.\n");
-                       return (-1);
-               }
-               sjcd_first_track_no = bcd2bin(info.un.track_no);
-       } else {
-               printk("SJCD: get first failed\n");
-               return (-1);
-       }
-#if defined( SJCD_TRACE )
-       printk("SJCD: TOC start 0x%02x ", sjcd_first_track_no);
-#endif
-       /*
-        * Get the TOC finish information.
-        */
-       sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK);
-       sjcd_receive_status();
-
-       if (!sjcd_status_valid) {
-               printk("SJCD: cannot load status.\n");
-               return (-1);
-       }
-
-       if (!sjcd_media_is_available) {
-               printk("SJCD: no disk in drive\n");
-               return (-1);
-       }
-
-       if (!sjcd_command_failed) {
-               if (sjcd_load_response(&info, sizeof(info)) != 0) {
-                       printk
-                           ("SJCD: cannot load response about TOC finish.\n");
-                       return (-1);
-               }
-               sjcd_last_track_no = bcd2bin(info.un.track_no);
-       } else {
-               printk("SJCD: get last failed\n");
-               return (-1);
-       }
-#if defined( SJCD_TRACE )
-       printk("SJCD: TOC finish 0x%02x ", sjcd_last_track_no);
-#endif
-       for (i = sjcd_first_track_no; i <= sjcd_last_track_no; i++) {
-               /*
-                * Get the first track information.
-                */
-               sjcd_send_1_cmd(SCMD_GET_DISK_INFO, bin2bcd(i));
-               sjcd_receive_status();
-
-               if (!sjcd_status_valid) {
-                       printk("SJCD: cannot load status.\n");
-                       return (-1);
-               }
-
-               if (!sjcd_media_is_available) {
-                       printk("SJCD: no disk in drive\n");
-                       return (-1);
-               }
-
-               if (!sjcd_command_failed) {
-                       if (sjcd_load_response(&sjcd_table_of_contents[i],
-                                              sizeof(struct
-                                                     sjcd_hw_disk_info))
-                           != 0) {
-                               printk
-                                   ("SJCD: cannot load info for %d track\n",
-                                    i);
-                               return (-1);
-                       }
-               } else {
-                       printk("SJCD: get info %d failed\n", i);
-                       return (-1);
-               }
-       }
-
-       /*
-        * Get the disk length info.
-        */
-       sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE);
-       sjcd_receive_status();
-
-       if (!sjcd_status_valid) {
-               printk("SJCD: cannot load status.\n");
-               return (-1);
-       }
-
-       if (!sjcd_media_is_available) {
-               printk("SJCD: no disk in drive\n");
-               return (-1);
-       }
-
-       if (!sjcd_command_failed) {
-               if (sjcd_load_response(&info, sizeof(info)) != 0) {
-                       printk
-                           ("SJCD: cannot load response about disk size.\n");
-                       return (-1);
-               }
-               sjcd_disk_length.min = info.un.track_msf.min;
-               sjcd_disk_length.sec = info.un.track_msf.sec;
-               sjcd_disk_length.frame = info.un.track_msf.frame;
-       } else {
-               printk("SJCD: get size failed\n");
-               return (1);
-       }
-#if defined( SJCD_TRACE )
-       printk("SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min,
-              sjcd_disk_length.sec, sjcd_disk_length.frame);
-#endif
-       return (0);
-}
-
-/*
- * Load subchannel information.
- */
-static int sjcd_get_q_info(struct sjcd_hw_qinfo *qp)
-{
-       int s;
-#if defined( SJCD_TRACE )
-       printk("SJCD: load sub q\n");
-#endif
-       sjcd_send_cmd(SCMD_GET_QINFO);
-       s = sjcd_receive_status();
-       if (s < 0 || sjcd_command_failed || !sjcd_status_valid) {
-               sjcd_send_cmd(0xF2);
-               s = sjcd_receive_status();
-               if (s < 0 || sjcd_command_failed || !sjcd_status_valid)
-                       return (-1);
-               sjcd_send_cmd(SCMD_GET_QINFO);
-               s = sjcd_receive_status();
-               if (s < 0 || sjcd_command_failed || !sjcd_status_valid)
-                       return (-1);
-       }
-       if (sjcd_media_is_available)
-               if (sjcd_load_response(qp, sizeof(*qp)) == 0)
-                       return (0);
-       return (-1);
-}
-
-/*
- * Start playing from the specified position.
- */
-static int sjcd_play(struct sjcd_play_msf *mp)
-{
-       struct sjcd_play_msf msf;
-
-       /*
-        * Turn the device to play mode.
-        */
-       sjcd_send_1_cmd(SCMD_SET_MODE, SCMD_MODE_PLAY);
-       if (sjcd_receive_status() < 0)
-               return (-1);
-
-       /*
-        * Seek to the starting point.
-        */
-       msf.start = mp->start;
-       msf.end.min = msf.end.sec = msf.end.frame = 0x00;
-       sjcd_send_6_cmd(SCMD_SEEK, &msf);
-       if (sjcd_receive_status() < 0)
-               return (-1);
-
-       /*
-        * Start playing.
-        */
-       sjcd_send_6_cmd(SCMD_PLAY, mp);
-       return (sjcd_receive_status());
-}
-
-/*
- * Tray control functions.
- */
-static int sjcd_tray_close(void)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: tray_close\n");
-#endif
-       sjcd_send_cmd(SCMD_CLOSE_TRAY);
-       return (sjcd_receive_status());
-}
-
-static int sjcd_tray_lock(void)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: tray_lock\n");
-#endif
-       sjcd_send_cmd(SCMD_LOCK_TRAY);
-       return (sjcd_receive_status());
-}
-
-static int sjcd_tray_unlock(void)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: tray_unlock\n");
-#endif
-       sjcd_send_cmd(SCMD_UNLOCK_TRAY);
-       return (sjcd_receive_status());
-}
-
-static int sjcd_tray_open(void)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: tray_open\n");
-#endif
-       sjcd_send_cmd(SCMD_EJECT_TRAY);
-       return (sjcd_receive_status());
-}
-
-/*
- * Do some user commands.
- */
-static int sjcd_ioctl(struct inode *ip, struct file *fp,
-                     unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-#if defined( SJCD_TRACE )
-       printk("SJCD:ioctl\n");
-#endif
-
-       sjcd_get_status();
-       if (!sjcd_status_valid)
-               return (-EIO);
-       if (sjcd_update_toc() < 0)
-               return (-EIO);
-
-       switch (cmd) {
-       case CDROMSTART:{
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: start\n");
-#endif
-                       return (0);
-               }
-
-       case CDROMSTOP:{
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: stop\n");
-#endif
-                       sjcd_send_cmd(SCMD_PAUSE);
-                       (void) sjcd_receive_status();
-                       sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
-                       return (0);
-               }
-
-       case CDROMPAUSE:{
-                       struct sjcd_hw_qinfo q_info;
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: pause\n");
-#endif
-                       if (sjcd_audio_status == CDROM_AUDIO_PLAY) {
-                               sjcd_send_cmd(SCMD_PAUSE);
-                               (void) sjcd_receive_status();
-                               if (sjcd_get_q_info(&q_info) < 0) {
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_NO_STATUS;
-                               } else {
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_PAUSED;
-                                       sjcd_playing.start = q_info.abs;
-                               }
-                               return (0);
-                       } else
-                               return (-EINVAL);
-               }
-
-       case CDROMRESUME:{
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: resume\n");
-#endif
-                       if (sjcd_audio_status == CDROM_AUDIO_PAUSED) {
-                               /*
-                                * continue play starting at saved location
-                                */
-                               if (sjcd_play(&sjcd_playing) < 0) {
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_ERROR;
-                                       return (-EIO);
-                               } else {
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_PLAY;
-                                       return (0);
-                               }
-                       } else
-                               return (-EINVAL);
-               }
-
-       case CDROMPLAYTRKIND:{
-                       struct cdrom_ti ti;
-                       int s = -EFAULT;
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: playtrkind\n");
-#endif
-                       if (!copy_from_user(&ti, argp, sizeof(ti))) {
-                               s = 0;
-                               if (ti.cdti_trk0 < sjcd_first_track_no)
-                                       return (-EINVAL);
-                               if (ti.cdti_trk1 > sjcd_last_track_no)
-                                       ti.cdti_trk1 = sjcd_last_track_no;
-                               if (ti.cdti_trk0 > ti.cdti_trk1)
-                                       return (-EINVAL);
-
-                               sjcd_playing.start =
-                                   sjcd_table_of_contents[ti.cdti_trk0].
-                                   un.track_msf;
-                               sjcd_playing.end =
-                                   (ti.cdti_trk1 <
-                                    sjcd_last_track_no) ?
-                                   sjcd_table_of_contents[ti.cdti_trk1 +
-                                                          1].un.
-                                   track_msf : sjcd_table_of_contents[0].
-                                   un.track_msf;
-
-                               if (sjcd_play(&sjcd_playing) < 0) {
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_ERROR;
-                                       return (-EIO);
-                               } else
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_PLAY;
-                       }
-                       return (s);
-               }
-
-       case CDROMPLAYMSF:{
-                       struct cdrom_msf sjcd_msf;
-                       int s;
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: playmsf\n");
-#endif
-                       if ((s =
-                            access_ok(VERIFY_READ, argp, sizeof(sjcd_msf))
-                                       ? 0 : -EFAULT) == 0) {
-                               if (sjcd_audio_status == CDROM_AUDIO_PLAY) {
-                                       sjcd_send_cmd(SCMD_PAUSE);
-                                       (void) sjcd_receive_status();
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_NO_STATUS;
-                               }
-
-                               if (copy_from_user(&sjcd_msf, argp,
-                                              sizeof(sjcd_msf)))
-                                       return (-EFAULT);
-
-                               sjcd_playing.start.min =
-                                   bin2bcd(sjcd_msf.cdmsf_min0);
-                               sjcd_playing.start.sec =
-                                   bin2bcd(sjcd_msf.cdmsf_sec0);
-                               sjcd_playing.start.frame =
-                                   bin2bcd(sjcd_msf.cdmsf_frame0);
-                               sjcd_playing.end.min =
-                                   bin2bcd(sjcd_msf.cdmsf_min1);
-                               sjcd_playing.end.sec =
-                                   bin2bcd(sjcd_msf.cdmsf_sec1);
-                               sjcd_playing.end.frame =
-                                   bin2bcd(sjcd_msf.cdmsf_frame1);
-
-                               if (sjcd_play(&sjcd_playing) < 0) {
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_ERROR;
-                                       return (-EIO);
-                               } else
-                                       sjcd_audio_status =
-                                           CDROM_AUDIO_PLAY;
-                       }
-                       return (s);
-               }
-
-       case CDROMREADTOCHDR:{
-                       struct cdrom_tochdr toc_header;
-#if defined (SJCD_TRACE )
-                       printk("SJCD: ioctl: readtocheader\n");
-#endif
-                       toc_header.cdth_trk0 = sjcd_first_track_no;
-                       toc_header.cdth_trk1 = sjcd_last_track_no;
-                       if (copy_to_user(argp, &toc_header,
-                                        sizeof(toc_header)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       case CDROMREADTOCENTRY:{
-                       struct cdrom_tocentry toc_entry;
-                       int s;
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: readtocentry\n");
-#endif
-                       if ((s =
-                            access_ok(VERIFY_WRITE, argp, sizeof(toc_entry))
-                                       ? 0 : -EFAULT) == 0) {
-                               struct sjcd_hw_disk_info *tp;
-
-                               if (copy_from_user(&toc_entry, argp,
-                                              sizeof(toc_entry)))
-                                       return (-EFAULT);
-                               if (toc_entry.cdte_track == CDROM_LEADOUT)
-                                       tp = &sjcd_table_of_contents[0];
-                               else if (toc_entry.cdte_track <
-                                        sjcd_first_track_no)
-                                       return (-EINVAL);
-                               else if (toc_entry.cdte_track >
-                                        sjcd_last_track_no)
-                                       return (-EINVAL);
-                               else
-                                       tp = &sjcd_table_of_contents
-                                           [toc_entry.cdte_track];
-
-                               toc_entry.cdte_adr =
-                                   tp->track_control & 0x0F;
-                               toc_entry.cdte_ctrl =
-                                   tp->track_control >> 4;
-
-                               switch (toc_entry.cdte_format) {
-                               case CDROM_LBA:
-                                       toc_entry.cdte_addr.lba =
-                                           msf2hsg(&(tp->un.track_msf));
-                                       break;
-                               case CDROM_MSF:
-                                       toc_entry.cdte_addr.msf.minute =
-                                           bcd2bin(tp->un.track_msf.min);
-                                       toc_entry.cdte_addr.msf.second =
-                                           bcd2bin(tp->un.track_msf.sec);
-                                       toc_entry.cdte_addr.msf.frame =
-                                           bcd2bin(tp->un.track_msf.
-                                                   frame);
-                                       break;
-                               default:
-                                       return (-EINVAL);
-                               }
-                               if (copy_to_user(argp, &toc_entry,
-                                                sizeof(toc_entry)))
-                                       s = -EFAULT;
-                       }
-                       return (s);
-               }
-
-       case CDROMSUBCHNL:{
-                       struct cdrom_subchnl subchnl;
-                       int s;
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: subchnl\n");
-#endif
-                       if ((s =
-                            access_ok(VERIFY_WRITE, argp, sizeof(subchnl))
-                                       ? 0 : -EFAULT) == 0) {
-                               struct sjcd_hw_qinfo q_info;
-
-                               if (copy_from_user(&subchnl, argp,
-                                              sizeof(subchnl)))
-                                       return (-EFAULT);
-
-                               if (sjcd_get_q_info(&q_info) < 0)
-                                       return (-EIO);
-
-                               subchnl.cdsc_audiostatus =
-                                   sjcd_audio_status;
-                               subchnl.cdsc_adr =
-                                   q_info.track_control & 0x0F;
-                               subchnl.cdsc_ctrl =
-                                   q_info.track_control >> 4;
-                               subchnl.cdsc_trk =
-                                   bcd2bin(q_info.track_no);
-                               subchnl.cdsc_ind = bcd2bin(q_info.x);
-
-                               switch (subchnl.cdsc_format) {
-                               case CDROM_LBA:
-                                       subchnl.cdsc_absaddr.lba =
-                                           msf2hsg(&(q_info.abs));
-                                       subchnl.cdsc_reladdr.lba =
-                                           msf2hsg(&(q_info.rel));
-                                       break;
-                               case CDROM_MSF:
-                                       subchnl.cdsc_absaddr.msf.minute =
-                                           bcd2bin(q_info.abs.min);
-                                       subchnl.cdsc_absaddr.msf.second =
-                                           bcd2bin(q_info.abs.sec);
-                                       subchnl.cdsc_absaddr.msf.frame =
-                                           bcd2bin(q_info.abs.frame);
-                                       subchnl.cdsc_reladdr.msf.minute =
-                                           bcd2bin(q_info.rel.min);
-                                       subchnl.cdsc_reladdr.msf.second =
-                                           bcd2bin(q_info.rel.sec);
-                                       subchnl.cdsc_reladdr.msf.frame =
-                                           bcd2bin(q_info.rel.frame);
-                                       break;
-                               default:
-                                       return (-EINVAL);
-                               }
-                               if (copy_to_user(argp, &subchnl,
-                                                sizeof(subchnl)))
-                                       s = -EFAULT;
-                       }
-                       return (s);
-               }
-
-       case CDROMVOLCTRL:{
-                       struct cdrom_volctrl vol_ctrl;
-                       int s;
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: volctrl\n");
-#endif
-                       if ((s =
-                            access_ok(VERIFY_READ, argp, sizeof(vol_ctrl))
-                                       ? 0 : -EFAULT) == 0) {
-                               unsigned char dummy[4];
-
-                               if (copy_from_user(&vol_ctrl, argp,
-                                              sizeof(vol_ctrl)))
-                                       return (-EFAULT);
-                               sjcd_send_4_cmd(SCMD_SET_VOLUME,
-                                               vol_ctrl.channel0, 0xFF,
-                                               vol_ctrl.channel1, 0xFF);
-                               if (sjcd_receive_status() < 0)
-                                       return (-EIO);
-                               (void) sjcd_load_response(dummy, 4);
-                       }
-                       return (s);
-               }
-
-       case CDROMEJECT:{
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: eject\n");
-#endif
-                       if (!sjcd_command_is_in_progress) {
-                               sjcd_tray_unlock();
-                               sjcd_send_cmd(SCMD_EJECT_TRAY);
-                               (void) sjcd_receive_status();
-                       }
-                       return (0);
-               }
-
-#if defined( SJCD_GATHER_STAT )
-       case 0xABCD:{
-#if defined( SJCD_TRACE )
-                       printk("SJCD: ioctl: statistic\n");
-#endif
-                       if (copy_to_user(argp, &statistic, sizeof(statistic)))
-                               return -EFAULT;
-                       return 0;
-               }
-#endif
-
-       default:
-               return (-EINVAL);
-       }
-}
-
-/*
- * Invalidate internal buffers of the driver.
- */
-static void sjcd_invalidate_buffers(void)
-{
-       int i;
-       for (i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[i++] = -1);
-       sjcd_buf_out = -1;
-}
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-
-static int current_valid(void)
-{
-        return CURRENT &&
-               CURRENT->cmd == READ &&
-               CURRENT->sector != -1;
-}
-
-static void sjcd_transfer(void)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: transfer:\n");
-#endif
-       if (current_valid()) {
-               while (CURRENT->nr_sectors) {
-                       int i, bn = CURRENT->sector / 4;
-                       for (i = 0;
-                            i < SJCD_BUF_SIZ && sjcd_buf_bn[i] != bn;
-                            i++);
-                       if (i < SJCD_BUF_SIZ) {
-                               int offs =
-                                   (i * 4 + (CURRENT->sector & 3)) * 512;
-                               int nr_sectors = 4 - (CURRENT->sector & 3);
-                               if (sjcd_buf_out != i) {
-                                       sjcd_buf_out = i;
-                                       if (sjcd_buf_bn[i] != bn) {
-                                               sjcd_buf_out = -1;
-                                               continue;
-                                       }
-                               }
-                               if (nr_sectors > CURRENT->nr_sectors)
-                                       nr_sectors = CURRENT->nr_sectors;
-#if defined( SJCD_TRACE )
-                               printk("SJCD: copy out\n");
-#endif
-                               memcpy(CURRENT->buffer, sjcd_buf + offs,
-                                      nr_sectors * 512);
-                               CURRENT->nr_sectors -= nr_sectors;
-                               CURRENT->sector += nr_sectors;
-                               CURRENT->buffer += nr_sectors * 512;
-                       } else {
-                               sjcd_buf_out = -1;
-                               break;
-                       }
-               }
-       }
-#if defined( SJCD_TRACE )
-       printk("SJCD: transfer: done\n");
-#endif
-}
-
-static void sjcd_poll(void)
-{
-#if defined( SJCD_GATHER_STAT )
-       /*
-        * Update total number of ticks.
-        */
-       statistic.ticks++;
-       statistic.tticks[sjcd_transfer_state]++;
-#endif
-
-      ReSwitch:switch (sjcd_transfer_state) {
-
-       case SJCD_S_IDLE:{
-#if defined( SJCD_GATHER_STAT )
-                       statistic.idle_ticks++;
-#endif
-#if defined( SJCD_TRACE )
-                       printk("SJCD_S_IDLE\n");
-#endif
-                       return;
-               }
-
-       case SJCD_S_START:{
-#if defined( SJCD_GATHER_STAT )
-                       statistic.start_ticks++;
-#endif
-                       sjcd_send_cmd(SCMD_GET_STATUS);
-                       sjcd_transfer_state =
-                           sjcd_mode ==
-                           SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE;
-                       sjcd_transfer_timeout = 500;
-#if defined( SJCD_TRACE )
-                       printk("SJCD_S_START: goto SJCD_S_%s mode\n",
-                              sjcd_transfer_state ==
-                              SJCD_S_READ ? "READ" : "MODE");
-#endif
-                       break;
-               }
-
-       case SJCD_S_MODE:{
-                       if (sjcd_check_status()) {
-                               /*
-                                * Previous command is completed.
-                                */
-                               if (!sjcd_status_valid
-                                   || sjcd_command_failed) {
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n");
-#endif
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-
-                               sjcd_mode = 0;  /* unknown mode; should not be valid when failed */
-                               sjcd_send_1_cmd(SCMD_SET_MODE,
-                                               SCMD_MODE_COOKED);
-                               sjcd_transfer_state = SJCD_S_READ;
-                               sjcd_transfer_timeout = 1000;
-#if defined( SJCD_TRACE )
-                               printk
-                                   ("SJCD_S_MODE: goto SJCD_S_READ mode\n");
-#endif
-                       }
-#if defined( SJCD_GATHER_STAT )
-                       else
-                               statistic.mode_ticks++;
-#endif
-                       break;
-               }
-
-       case SJCD_S_READ:{
-                       if (sjcd_status_valid ? 1 : sjcd_check_status()) {
-                               /*
-                                * Previous command is completed.
-                                */
-                               if (!sjcd_status_valid
-                                   || sjcd_command_failed) {
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n");
-#endif
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-                               if (!sjcd_media_is_available) {
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n");
-#endif
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-                               if (sjcd_mode != SCMD_MODE_COOKED) {
-                                       /*
-                                        * We seem to come from set mode. So discard one byte of result.
-                                        */
-                                       if (sjcd_load_response
-                                           (&sjcd_mode, 1) != 0) {
-#if defined( SJCD_TRACE )
-                                               printk
-                                                   ("SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n");
-#endif
-                                               sjcd_transfer_state =
-                                                   SJCD_S_STOP;
-                                               goto ReSwitch;
-                                       }
-                                       if (sjcd_mode != SCMD_MODE_COOKED) {
-#if defined( SJCD_TRACE )
-                                               printk
-                                                   ("SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n");
-#endif
-                                               sjcd_transfer_state =
-                                                   SJCD_S_STOP;
-                                               goto ReSwitch;
-                                       }
-                               }
-
-                               if (current_valid()) {
-                                       struct sjcd_play_msf msf;
-
-                                       sjcd_next_bn = CURRENT->sector / 4;
-                                       hsg2msf(sjcd_next_bn, &msf.start);
-                                       msf.end.min = 0;
-                                       msf.end.sec = 0;
-                                       msf.end.frame = sjcd_read_count =
-                                           SJCD_BUF_SIZ;
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD: ---reading msf-address %x:%x:%x  %x:%x:%x\n",
-                                            msf.start.min, msf.start.sec,
-                                            msf.start.frame, msf.end.min,
-                                            msf.end.sec, msf.end.frame);
-                                       printk
-                                           ("sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n",
-                                            sjcd_next_bn, sjcd_buf_in,
-                                            sjcd_buf_out,
-                                            sjcd_buf_bn[sjcd_buf_in]);
-#endif
-                                       sjcd_send_6_cmd(SCMD_DATA_READ,
-                                                       &msf);
-                                       sjcd_transfer_state = SJCD_S_DATA;
-                                       sjcd_transfer_timeout = 500;
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_READ: go to SJCD_S_DATA mode\n");
-#endif
-                               } else {
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n");
-#endif
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-                       }
-#if defined( SJCD_GATHER_STAT )
-                       else
-                               statistic.read_ticks++;
-#endif
-                       break;
-               }
-
-       case SJCD_S_DATA:{
-                       unsigned char stat;
-
-                     sjcd_s_data:stat =
-                           inb(SJCDPORT
-                               (1));
-#if defined( SJCD_TRACE )
-                       printk("SJCD_S_DATA: status = 0x%02x\n", stat);
-#endif
-                       if (SJCD_STATUS_AVAILABLE(stat)) {
-                               /*
-                                * No data is waiting for us in the drive buffer. Status of operation
-                                * completion is available. Read and parse it.
-                                */
-                               sjcd_load_status();
-
-                               if (!sjcd_status_valid
-                                   || sjcd_command_failed) {
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD: read block %d failed, maybe audio disk? Giving up\n",
-                                            sjcd_next_bn);
-#endif
-                                       if (current_valid())
-                                               end_request(CURRENT, 0);
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n");
-#endif
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-
-                               if (!sjcd_media_is_available) {
-                                       printk
-                                           ("SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n");
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-
-                               sjcd_transfer_state = SJCD_S_READ;
-                               goto ReSwitch;
-                       } else if (SJCD_DATA_AVAILABLE(stat)) {
-                               /*
-                                * One frame is read into device buffer. We must copy it to our memory.
-                                * Otherwise cdrom hangs up. Check to see if we have something to copy
-                                * to.
-                                */
-                               if (!current_valid()
-                                   && sjcd_buf_in == sjcd_buf_out) {
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n");
-                                       printk
-                                           (" ... all the date would be discarded\n");
-#endif
-                                       sjcd_transfer_state = SJCD_S_STOP;
-                                       goto ReSwitch;
-                               }
-
-                               /*
-                                * Everything seems to be OK. Just read the frame and recalculate
-                                * indices.
-                                */
-                               sjcd_buf_bn[sjcd_buf_in] = -1;  /* ??? */
-                               insb(SJCDPORT(2),
-                                    sjcd_buf + 2048 * sjcd_buf_in, 2048);
-#if defined( SJCD_TRACE )
-                               printk
-                                   ("SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n",
-                                    sjcd_next_bn, sjcd_buf_in,
-                                    sjcd_buf_out,
-                                    sjcd_buf_bn[sjcd_buf_in]);
-#endif
-                               sjcd_buf_bn[sjcd_buf_in] = sjcd_next_bn++;
-                               if (sjcd_buf_out == -1)
-                                       sjcd_buf_out = sjcd_buf_in;
-                               if (++sjcd_buf_in == SJCD_BUF_SIZ)
-                                       sjcd_buf_in = 0;
-
-                               /*
-                                * Only one frame is ready at time. So we should turn over to wait for
-                                * another frame. If we need that, of course.
-                                */
-                               if (--sjcd_read_count == 0) {
-                                       /*
-                                        * OK, request seems to be precessed. Continue transferring...
-                                        */
-                                       if (!sjcd_transfer_is_active) {
-                                               while (current_valid()) {
-                                                       /*
-                                                        * Continue transferring.
-                                                        */
-                                                       sjcd_transfer();
-                                                       if (CURRENT->
-                                                           nr_sectors ==
-                                                           0)
-                                                               end_request
-                                                                   (CURRENT, 1);
-                                                       else
-                                                               break;
-                                               }
-                                       }
-                                       if (current_valid() &&
-                                           (CURRENT->sector / 4 <
-                                            sjcd_next_bn
-                                            || CURRENT->sector / 4 >
-                                            sjcd_next_bn +
-                                            SJCD_BUF_SIZ)) {
-#if defined( SJCD_TRACE )
-                                               printk
-                                                   ("SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n");
-#endif
-                                               sjcd_transfer_state =
-                                                   SJCD_S_STOP;
-                                               goto ReSwitch;
-                                       }
-                               }
-                               /*
-                                * Now we should turn around rather than wait for while.
-                                */
-                               goto sjcd_s_data;
-                       }
-#if defined( SJCD_GATHER_STAT )
-                       else
-                               statistic.data_ticks++;
-#endif
-                       break;
-               }
-
-       case SJCD_S_STOP:{
-                       sjcd_read_count = 0;
-                       sjcd_send_cmd(SCMD_STOP);
-                       sjcd_transfer_state = SJCD_S_STOPPING;
-                       sjcd_transfer_timeout = 500;
-#if defined( SJCD_GATHER_STAT )
-                       statistic.stop_ticks++;
-#endif
-                       break;
-               }
-
-       case SJCD_S_STOPPING:{
-                       unsigned char stat;
-
-                       stat = inb(SJCDPORT(1));
-#if defined( SJCD_TRACE )
-                       printk("SJCD_S_STOP: status = 0x%02x\n", stat);
-#endif
-                       if (SJCD_DATA_AVAILABLE(stat)) {
-                               int i;
-#if defined( SJCD_TRACE )
-                               printk("SJCD_S_STOP: discard data\n");
-#endif
-                               /*
-                                * Discard all the data from the pipe. Foolish method.
-                                */
-                               for (i = 2048; i--;
-                                    (void) inb(SJCDPORT(2)));
-                               sjcd_transfer_timeout = 500;
-                       } else if (SJCD_STATUS_AVAILABLE(stat)) {
-                               sjcd_load_status();
-                               if (sjcd_status_valid
-                                   && sjcd_media_is_changed) {
-                                       sjcd_toc_uptodate = 0;
-                                       sjcd_invalidate_buffers();
-                               }
-                               if (current_valid()) {
-                                       if (sjcd_status_valid)
-                                               sjcd_transfer_state =
-                                                   SJCD_S_READ;
-                                       else
-                                               sjcd_transfer_state =
-                                                   SJCD_S_START;
-                               } else
-                                       sjcd_transfer_state = SJCD_S_IDLE;
-                               goto ReSwitch;
-                       }
-#if defined( SJCD_GATHER_STAT )
-                       else
-                               statistic.stopping_ticks++;
-#endif
-                       break;
-               }
-
-       default:
-               printk("SJCD: poll: invalid state %d\n",
-                      sjcd_transfer_state);
-               return;
-       }
-
-       if (--sjcd_transfer_timeout == 0) {
-               printk("SJCD: timeout in state %d\n", sjcd_transfer_state);
-               while (current_valid())
-                       end_request(CURRENT, 0);
-               sjcd_send_cmd(SCMD_STOP);
-               sjcd_transfer_state = SJCD_S_IDLE;
-               goto ReSwitch;
-       }
-
-       /*
-        * Get back in some time. 1 should be replaced with count variable to
-        * avoid unnecessary testings.
-        */
-       SJCD_SET_TIMER(sjcd_poll, 1);
-}
-
-static void do_sjcd_request(request_queue_t * q)
-{
-#if defined( SJCD_TRACE )
-       printk("SJCD: do_sjcd_request(%ld+%ld)\n",
-              CURRENT->sector, CURRENT->nr_sectors);
-#endif
-       sjcd_transfer_is_active = 1;
-       while (current_valid()) {
-               sjcd_transfer();
-               if (CURRENT->nr_sectors == 0)
-                       end_request(CURRENT, 1);
-               else {
-                       sjcd_buf_out = -1;      /* Want to read a block not in buffer */
-                       if (sjcd_transfer_state == SJCD_S_IDLE) {
-                               if (!sjcd_toc_uptodate) {
-                                       if (sjcd_update_toc() < 0) {
-                                               printk
-                                                   ("SJCD: transfer: discard\n");
-                                               while (current_valid())
-                                                       end_request(CURRENT, 0);
-                                               break;
-                                       }
-                               }
-                               sjcd_transfer_state = SJCD_S_START;
-                               SJCD_SET_TIMER(sjcd_poll, HZ / 100);
-                       }
-                       break;
-               }
-       }
-       sjcd_transfer_is_active = 0;
-#if defined( SJCD_TRACE )
-       printk
-           ("sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n",
-            sjcd_next_bn, sjcd_buf_in, sjcd_buf_out,
-            sjcd_buf_bn[sjcd_buf_in]);
-       printk("do_sjcd_request ends\n");
-#endif
-}
-
-/*
- * Open the device special file. Check disk is in.
- */
-static int sjcd_open(struct inode *ip, struct file *fp)
-{
-       /*
-        * Check the presence of device.
-        */
-       if (!sjcd_present)
-               return (-ENXIO);
-
-       /*
-        * Only read operations are allowed. Really? (:-)
-        */
-       if (fp->f_mode & 2)
-               return (-EROFS);
-
-       if (sjcd_open_count == 0) {
-               int s, sjcd_open_tries;
-/* We don't know that, do we? */
-/*
-    sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
-*/
-               sjcd_mode = 0;
-               sjcd_door_was_open = 0;
-               sjcd_transfer_state = SJCD_S_IDLE;
-               sjcd_invalidate_buffers();
-               sjcd_status_valid = 0;
-
-               /*
-                * Strict status checking.
-                */
-               for (sjcd_open_tries = 4; --sjcd_open_tries;) {
-                       if (!sjcd_status_valid)
-                               sjcd_get_status();
-                       if (!sjcd_status_valid) {
-#if defined( SJCD_DIAGNOSTIC )
-                               printk
-                                   ("SJCD: open: timed out when check status.\n");
-#endif
-                               goto err_out;
-                       } else if (!sjcd_media_is_available) {
-#if defined( SJCD_DIAGNOSTIC )
-                               printk("SJCD: open: no disk in drive\n");
-#endif
-                               if (!sjcd_door_closed) {
-                                       sjcd_door_was_open = 1;
-#if defined( SJCD_TRACE )
-                                       printk
-                                           ("SJCD: open: close the tray\n");
-#endif
-                                       s = sjcd_tray_close();
-                                       if (s < 0 || !sjcd_status_valid
-                                           || sjcd_command_failed) {
-#if defined( SJCD_DIAGNOSTIC )
-                                               printk
-                                                   ("SJCD: open: tray close attempt failed\n");
-#endif
-                                               goto err_out;
-                                       }
-                                       continue;
-                               } else
-                                       goto err_out;
-                       }
-                       break;
-               }
-               s = sjcd_tray_lock();
-               if (s < 0 || !sjcd_status_valid || sjcd_command_failed) {
-#if defined( SJCD_DIAGNOSTIC )
-                       printk("SJCD: open: tray lock attempt failed\n");
-#endif
-                       goto err_out;
-               }
-#if defined( SJCD_TRACE )
-               printk("SJCD: open: done\n");
-#endif
-       }
-
-       ++sjcd_open_count;
-       return (0);
-
-      err_out:
-       return (-EIO);
-}
-
-/*
- * On close, we flush all sjcd blocks from the buffer cache.
- */
-static int sjcd_release(struct inode *inode, struct file *file)
-{
-       int s;
-
-#if defined( SJCD_TRACE )
-       printk("SJCD: release\n");
-#endif
-       if (--sjcd_open_count == 0) {
-               sjcd_invalidate_buffers();
-               s = sjcd_tray_unlock();
-               if (s < 0 || !sjcd_status_valid || sjcd_command_failed) {
-#if defined( SJCD_DIAGNOSTIC )
-                       printk
-                           ("SJCD: release: tray unlock attempt failed.\n");
-#endif
-               }
-               if (sjcd_door_was_open) {
-                       s = sjcd_tray_open();
-                       if (s < 0 || !sjcd_status_valid
-                           || sjcd_command_failed) {
-#if defined( SJCD_DIAGNOSTIC )
-                               printk
-                                   ("SJCD: release: tray unload attempt failed.\n");
-#endif
-                       }
-               }
-       }
-       return 0;
-}
-
-/*
- * A list of file operations allowed for this cdrom.
- */
-static struct block_device_operations sjcd_fops = {
-       .owner          = THIS_MODULE,
-       .open           = sjcd_open,
-       .release        = sjcd_release,
-       .ioctl          = sjcd_ioctl,
-       .media_changed  = sjcd_disk_change,
-};
-
-/*
- * Following stuff is intended for initialization of the cdrom. It
- * first looks for presence of device. If the device is present, it
- * will be reset. Then read the version of the drive and load status.
- * The version is two BCD-coded bytes.
- */
-static struct {
-       unsigned char major, minor;
-} sjcd_version;
-
-static struct gendisk *sjcd_disk;
-
-/*
- * Test for presence of drive and initialize it. Called at boot time.
- * Probe cdrom, find out version and status.
- */
-static int __init sjcd_init(void)
-{
-       int i;
-
-       printk(KERN_INFO
-              "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n",
-              SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR);
-
-#if defined( SJCD_TRACE )
-       printk("SJCD: sjcd=0x%x: ", sjcd_base);
-#endif
-
-       if (register_blkdev(MAJOR_NR, "sjcd"))
-               return -EIO;
-
-       sjcd_queue = blk_init_queue(do_sjcd_request, &sjcd_lock);
-       if (!sjcd_queue)
-               goto out0;
-
-       blk_queue_hardsect_size(sjcd_queue, 2048);
-
-       sjcd_disk = alloc_disk(1);
-       if (!sjcd_disk) {
-               printk(KERN_ERR "SJCD: can't allocate disk");
-               goto out1;
-       }
-       sjcd_disk->major = MAJOR_NR,
-       sjcd_disk->first_minor = 0,
-       sjcd_disk->fops = &sjcd_fops,
-       sprintf(sjcd_disk->disk_name, "sjcd");
-
-       if (!request_region(sjcd_base, 4,"sjcd")) {
-               printk
-                   ("SJCD: Init failed, I/O port (%X) is already in use\n",
-                    sjcd_base);
-               goto out2;
-       }
-
-       /*
-        * Check for card. Since we are booting now, we can't use standard
-        * wait algorithm.
-        */
-       printk(KERN_INFO "SJCD: Resetting: ");
-       sjcd_send_cmd(SCMD_RESET);
-       for (i = 1000; i > 0 && !sjcd_status_valid; --i) {
-               unsigned long timer;
-
-               /*
-                * Wait 10ms approx.
-                */
-               for (timer = jiffies; time_before_eq(jiffies, timer););
-               if ((i % 100) == 0)
-                       printk(".");
-               (void) sjcd_check_status();
-       }
-       if (i == 0 || sjcd_command_failed) {
-               printk(" reset failed, no drive found.\n");
-               goto out3;
-       } else
-               printk("\n");
-
-       /*
-        * Get and print out cdrom version.
-        */
-       printk(KERN_INFO "SJCD: Getting version: ");
-       sjcd_send_cmd(SCMD_GET_VERSION);
-       for (i = 1000; i > 0 && !sjcd_status_valid; --i) {
-               unsigned long timer;
-
-               /*
-                * Wait 10ms approx.
-                */
-               for (timer = jiffies; time_before_eq(jiffies, timer););
-               if ((i % 100) == 0)
-                       printk(".");
-               (void) sjcd_check_status();
-       }
-       if (i == 0 || sjcd_command_failed) {
-               printk(" get version failed, no drive found.\n");
-               goto out3;
-       }
-
-       if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) {
-               printk(" %1x.%02x\n", (int) sjcd_version.major,
-                      (int) sjcd_version.minor);
-       } else {
-               printk(" read version failed, no drive found.\n");
-               goto out3;
-       }
-
-       /*
-        * Check and print out the tray state. (if it is needed?).
-        */
-       if (!sjcd_status_valid) {
-               printk(KERN_INFO "SJCD: Getting status: ");
-               sjcd_send_cmd(SCMD_GET_STATUS);
-               for (i = 1000; i > 0 && !sjcd_status_valid; --i) {
-                       unsigned long timer;
-
-                       /*
-                        * Wait 10ms approx.
-                        */
-                       for (timer = jiffies;
-                            time_before_eq(jiffies, timer););
-                       if ((i % 100) == 0)
-                               printk(".");
-                       (void) sjcd_check_status();
-               }
-               if (i == 0 || sjcd_command_failed) {
-                       printk(" get status failed, no drive found.\n");
-                       goto out3;
-               } else
-                       printk("\n");
-       }
-
-       printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base);
-       sjcd_disk->queue = sjcd_queue;
-       add_disk(sjcd_disk);
-
-       sjcd_present++;
-       return (0);
-out3:
-       release_region(sjcd_base, 4);
-out2:
-       put_disk(sjcd_disk);
-out1:
-       blk_cleanup_queue(sjcd_queue);
-out0:
-       if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL))
-               printk("SJCD: cannot unregister device.\n");
-       return (-EIO);
-}
-
-static void __exit sjcd_exit(void)
-{
-       del_gendisk(sjcd_disk);
-       put_disk(sjcd_disk);
-       release_region(sjcd_base, 4);
-       blk_cleanup_queue(sjcd_queue);
-       if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL))
-               printk("SJCD: cannot unregister device.\n");
-       printk(KERN_INFO "SJCD: module: removed.\n");
-}
-
-module_init(sjcd_init);
-module_exit(sjcd_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(SANYO_CDROM_MAJOR);
diff --git a/drivers/cdrom/sjcd.h b/drivers/cdrom/sjcd.h
deleted file mode 100644 (file)
index 0aa5e71..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Definitions for a Sanyo CD-ROM interface.
- *
- *   Copyright (C) 1995  Vadim V. Model
- *                                       model@cecmow.enet.dec.com
- *                                       vadim@rbrf.msk.su
- *                                       vadim@ipsun.ras.ru
- *                       Eric van der Maarel
- *                                       H.T.M.v.d.Maarel@marin.nl
- *
- *  This information is based on mcd.c from M. Harriss and sjcd102.lst from
- *  E. Moenkeberg.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __SJCD_H__
-#define __SJCD_H__
-
-/*
- * Change this to set the I/O port address as default. More flexibility
- * come with setup implementation.
- */
-#define SJCD_BASE_ADDR      0x340
-
-/*
- * Change this to set the irq as default. Really SANYO do not use interrupts
- * at all.
- */
-#define SJCD_INTR_NR        0
-
-/*
- * Change this to set the dma as default value. really SANYO does not use
- * direct memory access at all.
- */
-#define SJCD_DMA_NR         0
-
-/*
- * Macros which allow us to find out the status of the drive.
- */
-#define SJCD_STATUS_AVAILABLE( x ) (((x)&0x02)==0)
-#define SJCD_DATA_AVAILABLE( x )   (((x)&0x01)==0)
-
-/*
- * Port access macro. Three ports are available: S-data port (command port),
- * status port (read only) and D-data port (read only).
- */
-#define SJCDPORT( x )       ( sjcd_base + ( x ) )
-#define SJCD_STATUS_PORT    SJCDPORT( 1 )
-#define SJCD_S_DATA_PORT    SJCDPORT( 0 )
-#define SJCD_COMMAND_PORT   SJCDPORT( 0 )
-#define SJCD_D_DATA_PORT    SJCDPORT( 2 )
-
-/*
- * Drive info bits. Drive info available as first (mandatory) byte of
- * command completion status.
- */
-#define SST_NOT_READY       0x10        /* no disk in the drive (???) */
-#define SST_MEDIA_CHANGED   0x20        /* disk is changed */
-#define SST_DOOR_OPENED     0x40        /* door is open */
-
-/* commands */
-
-#define SCMD_EJECT_TRAY     0xD0        /* eject tray if not locked */
-#define SCMD_LOCK_TRAY      0xD2        /* lock tray when in */
-#define SCMD_UNLOCK_TRAY    0xD4        /* unlock tray when in */
-#define SCMD_CLOSE_TRAY     0xD6        /* load tray in */
-
-#define SCMD_RESET          0xFA        /* soft reset */
-#define SCMD_GET_STATUS     0x80
-#define SCMD_GET_VERSION    0xCC
-
-#define SCMD_DATA_READ      0xA0        /* are the same, depend on mode&args */
-#define SCMD_SEEK           0xA0
-#define SCMD_PLAY           0xA0
-
-#define SCMD_GET_QINFO      0xA8
-
-#define SCMD_SET_MODE       0xC4
-#define SCMD_MODE_PLAY      0xE0
-#define SCMD_MODE_COOKED    (0xF8 & ~0x20)
-#define SCMD_MODE_RAW       0xF9
-#define SCMD_MODE_x20_BIT   0x20        /* What is it for ? */
-
-#define SCMD_SET_VOLUME     0xAE
-#define SCMD_PAUSE          0xE0
-#define SCMD_STOP           0xE0
-
-#define SCMD_GET_DISK_INFO  0xAA
-
-/*
- * Some standard arguments for SCMD_GET_DISK_INFO.
- */
-#define SCMD_GET_1_TRACK    0xA0    /* get the first track information */
-#define SCMD_GET_L_TRACK    0xA1    /* get the last track information */
-#define SCMD_GET_D_SIZE     0xA2    /* get the whole disk information */
-
-/*
- * Borrowed from hd.c. Allows to optimize multiple port read commands.
- */
-#define S_READ_DATA( port, buf, nr )      insb( port, buf, nr )
-
-/*
- * We assume that there are no audio disks with TOC length more than this
- * number (I personally have never seen disks with more than 20 fragments).
- */
-#define SJCD_MAX_TRACKS                100
-
-struct msf {
-  unsigned char   min;
-  unsigned char   sec;
-  unsigned char   frame;
-};
-
-struct sjcd_hw_disk_info {
-  unsigned char track_control;
-  unsigned char track_no;
-  unsigned char x, y, z;
-  union {
-    unsigned char track_no;
-    struct msf track_msf;
-  } un;
-};
-
-struct sjcd_hw_qinfo {
-  unsigned char track_control;
-  unsigned char track_no;
-  unsigned char x;
-  struct msf rel;
-  struct msf abs;
-};
-
-struct sjcd_play_msf {
-  struct msf  start;
-  struct msf  end;
-};
-
-struct sjcd_disk_info {
-  unsigned char   first;
-  unsigned char   last;
-  struct msf      disk_length;
-  struct msf      first_track;
-};
-
-struct sjcd_toc {
-  unsigned char   ctrl_addr;
-  unsigned char   track;
-  unsigned char   point_index;
-  struct msf      track_time;
-  struct msf      disk_time;
-};
-
-#if defined( SJCD_GATHER_STAT )
-
-struct sjcd_stat {
-  int ticks;
-  int tticks[ 8 ];
-  int idle_ticks;
-  int start_ticks;
-  int mode_ticks;
-  int read_ticks;
-  int data_ticks;
-  int stop_ticks;
-  int stopping_ticks;
-};
-
-#endif
-
-#endif
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
deleted file mode 100644 (file)
index f77ada9..0000000
+++ /dev/null
@@ -1,1689 +0,0 @@
-/*
- * Sony CDU-535 interface device driver
- *
- * This is a modified version of the CDU-31A device driver (see below).
- * Changes were made using documentation for the CDU-531 (which Sony
- * assures me is very similar to the 535) and partial disassembly of the
- * DOS driver.  I used Minyard's driver and replaced the CDU-31A
- * commands with the CDU-531 commands.  This was complicated by a different
- * interface protocol with the drive.  The driver is still polled.
- *
- * Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec.
- * I tried polling without the sony_sleep during the data transfers but
- * it did not speed things up any.
- *
- * 1993-05-23 (rgj) changed the major number to 21 to get rid of conflict
- * with CDU-31A driver.  This is the also the number from the Linux
- * Device Driver Registry for the Sony Drive.  Hope nobody else is using it.
- *
- * 1993-08-29 (rgj) remove the configuring of the interface board address
- * from the top level configuration, you have to modify it in this file.
- *
- * 1995-01-26 Made module-capable (Joel Katz <Stimpson@Panix.COM>)
- *
- * 1995-05-20
- *  Modified to support CDU-510/515 series
- *      (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>)
- *  Fixed to report verify_area() failures
- *      (Heiko Eissfeldt <heiko@colossus.escape.de>)
- *
- * 1995-06-01
- *  More changes to support CDU-510/515 series
- *      (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>)
- *
- * November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                 Removed init_module & cleanup_module in favor of 
- *                 module_init & module_exit.
- *                  Torben Mathiasen <tmm@image.dk>
- *
- * September 2003 - Fix SMP support by removing cli/sti calls.
- *                  Using spinlocks with a wait_queue instead.
- *                  Felipe Damasio <felipewd@terra.com.br>
- *
- * Things to do:
- *  - handle errors and status better, put everything into a single word
- *  - use interrupts (code mostly there, but a big hole still missing)
- *  - handle multi-session CDs?
- *  - use DMA?
- *
- *  Known Bugs:
- *  -
- *
- *   Ken Pizzini (ken@halcyon.com)
- *
- * Original by:
- *   Ron Jeppesen (ronj.an@site007.saic.com)
- *
- *
- *------------------------------------------------------------------------
- * Sony CDROM interface device driver.
- *
- * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above)
- *
- * Colossians 3:17
- *
- * The Sony interface device driver handles Sony interface CDROM
- * drives and provides a complete block-level interface as well as an
- * ioctl() interface compatible with the Sun (as specified in
- * include/linux/cdrom.h).  With this interface, CDROMs can be
- * accessed and standard audio CDs can be played back normally.
- *
- * This interface is (unfortunately) a polled interface.  This is
- * because most Sony interfaces are set up with DMA and interrupts
- * disables.  Some (like mine) do not even have the capability to
- * handle interrupts or DMA.  For this reason you will see a bit of
- * the following:
- *
- *   snap = jiffies;
- *   while (jiffies-snap < SONY_JIFFIES_TIMEOUT)
- *   {
- *             if (some_condition())
- *         break;
- *      sony_sleep();
- *   }
- *   if (some_condition not met)
- *   {
- *      return an_error;
- *   }
- *
- * This ugly hack waits for something to happen, sleeping a little
- * between every try.  (The conditional is written so that jiffies
- * wrap-around is handled properly.)
- *
- * One thing about these drives: They talk in MSF (Minute Second Frame) format.
- * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a
- * disk.  The funny thing is that these are sent to the drive in BCD, but the
- * interface wants to see them in decimal.  A lot of conversion goes on.
- *
- *  Copyright (C) 1993  Corey Minyard
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-
-# include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#define REALLY_SLOW_IO
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include <linux/cdrom.h>
-
-#define MAJOR_NR CDU535_CDROM_MAJOR
-#include <linux/blkdev.h>
-
-#define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */
-#include "sonycd535.h"
-
-/*
- * this is the base address of the interface card for the Sony CDU-535
- * CDROM drive.  If your jumpers are set for an address other than
- * this one (the default), change the following line to the
- * proper address.
- */
-#ifndef CDU535_ADDRESS
-# define CDU535_ADDRESS                        0x340
-#endif
-#ifndef CDU535_INTERRUPT
-# define CDU535_INTERRUPT              0
-#endif
-#ifndef CDU535_HANDLE
-# define CDU535_HANDLE                 "cdu535"
-#endif
-#ifndef CDU535_MESSAGE_NAME
-# define CDU535_MESSAGE_NAME   "Sony CDU-535"
-#endif
-
-#define CDU535_BLOCK_SIZE      2048 
-#ifndef MAX_SPINUP_RETRY
-# define MAX_SPINUP_RETRY              3       /* 1 is sufficient for most drives... */
-#endif
-#ifndef RETRY_FOR_BAD_STATUS
-# define RETRY_FOR_BAD_STATUS  100     /* in 10th of second */
-#endif
-
-#ifndef DEBUG
-# define DEBUG 1
-#endif
-
-/*
- *  SONY535_BUFFER_SIZE determines the size of internal buffer used
- *  by the drive.  It must be at least 2K and the larger the buffer
- *  the better the transfer rate.  It does however take system memory.
- *  On my system I get the following transfer rates using dd to read
- *  10 Mb off /dev/cdrom.
- *
- *    8K buffer      43 Kb/sec
- *   16K buffer      66 Kb/sec
- *   32K buffer      91 Kb/sec
- *   64K buffer     111 Kb/sec
- *  128K buffer     123 Kb/sec
- *  512K buffer     123 Kb/sec
- */
-#define SONY535_BUFFER_SIZE    (64*1024)
-
-/*
- *  if LOCK_DOORS is defined then the eject button is disabled while
- * the device is open.
- */
-#ifndef NO_LOCK_DOORS
-# define LOCK_DOORS
-#endif
-
-static int read_subcode(void);
-static void sony_get_toc(void);
-static int cdu_open(struct inode *inode, struct file *filp);
-static inline unsigned int int_to_bcd(unsigned int val);
-static unsigned int bcd_to_int(unsigned int bcd);
-static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2],
-                                          Byte * response, int n_response, int ignoreStatusBit7);
-
-/* The base I/O address of the Sony Interface.  This is a variable (not a
-   #define) so it can be easily changed via some future ioctl() */
-static unsigned int sony535_cd_base_io = CDU535_ADDRESS;
-module_param(sony535_cd_base_io, int, 0);
-
-/*
- * The following are I/O addresses of the various registers for the drive.  The
- * comment for the base address also applies here.
- */
-static unsigned short select_unit_reg;
-static unsigned short result_reg;
-static unsigned short command_reg;
-static unsigned short read_status_reg;
-static unsigned short data_reg;
-
-static DEFINE_SPINLOCK(sonycd535_lock); /* queue lock */
-static struct request_queue *sonycd535_queue;
-
-static int initialized;                        /* Has the drive been initialized? */
-static int sony_disc_changed = 1;      /* Has the disk been changed
-                                          since the last check? */
-static int sony_toc_read;              /* Has the table of contents been
-                                          read? */
-static unsigned int sony_buffer_size;  /* Size in bytes of the read-ahead
-                                          buffer. */
-static unsigned int sony_buffer_sectors;       /* Size (in 2048 byte records) of
-                                                  the read-ahead buffer. */
-static unsigned int sony_usage;                /* How many processes have the
-                                          drive open. */
-
-static int sony_first_block = -1;      /* First OS block (512 byte) in
-                                          the read-ahead buffer */
-static int sony_last_block = -1;       /* Last OS block (512 byte) in
-                                          the read-ahead buffer */
-
-static struct s535_sony_toc *sony_toc; /* Points to the table of
-                                          contents. */
-
-static struct s535_sony_subcode *last_sony_subcode;            /* Points to the last
-                                                                  subcode address read */
-static Byte **sony_buffer;             /* Points to the pointers
-                                          to the sector buffers */
-
-static int sony_inuse;                 /* is the drive in use? Only one
-                                          open at a time allowed */
-
-/*
- * The audio status uses the values from read subchannel data as specified
- * in include/linux/cdrom.h.
- */
-static int sony_audio_status = CDROM_AUDIO_NO_STATUS;
-
-/*
- * The following are a hack for pausing and resuming audio play.  The drive
- * does not work as I would expect it, if you stop it then start it again,
- * the drive seeks back to the beginning and starts over.  This holds the
- * position during a pause so a resume can restart it.  It uses the
- * audio status variable above to tell if it is paused.
- *   I just kept the CDU-31A driver behavior rather than using the PAUSE
- * command on the CDU-535.
- */
-static Byte cur_pos_msf[3];
-static Byte final_pos_msf[3];
-
-/* What IRQ is the drive using?  0 if none. */
-static int sony535_irq_used = CDU535_INTERRUPT;
-
-/* The interrupt handler will wake this queue up when it gets an interrupt. */
-static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait);
-
-
-/*
- * This routine returns 1 if the disk has been changed since the last
- * check or 0 if it hasn't.  Setting flag to 0 resets the changed flag.
- */
-static int
-cdu535_check_media_change(struct gendisk *disk)
-{
-       /* if driver is not initialized, always return 0 */
-       int retval = initialized ? sony_disc_changed : 0;
-       sony_disc_changed = 0;
-       return retval;
-}
-
-static inline void
-enable_interrupts(void)
-{
-#ifdef USE_IRQ
-       /*
-        * This code was taken from cdu31a.c; it will not
-        * directly work for the cdu535 as written...
-        */
-       curr_control_reg |= ( SONY_ATTN_INT_EN_BIT
-                                               | SONY_RES_RDY_INT_EN_BIT
-                                               | SONY_DATA_RDY_INT_EN_BIT);
-       outb(curr_control_reg, sony_cd_control_reg);
-#endif
-}
-
-static inline void
-disable_interrupts(void)
-{
-#ifdef USE_IRQ
-       /*
-        * This code was taken from cdu31a.c; it will not
-        * directly work for the cdu535 as written...
-        */
-       curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT
-                                               | SONY_RES_RDY_INT_EN_BIT
-                                               | SONY_DATA_RDY_INT_EN_BIT);
-       outb(curr_control_reg, sony_cd_control_reg);
-#endif
-}
-
-static irqreturn_t
-cdu535_interrupt(int irq, void *dev_id)
-{
-       disable_interrupts();
-       if (waitqueue_active(&cdu535_irq_wait)) {
-               wake_up(&cdu535_irq_wait);
-               return IRQ_HANDLED;
-       }
-       printk(CDU535_MESSAGE_NAME
-                       ": Got an interrupt but nothing was waiting\n");
-       return IRQ_NONE;
-}
-
-
-/*
- * Wait a little while.
- */
-static inline void
-sony_sleep(void)
-{
-       if (sony535_irq_used <= 0) {    /* poll */
-               yield();
-       } else {        /* Interrupt driven */
-               DEFINE_WAIT(wait);
-               
-               spin_lock_irq(&sonycd535_lock);
-               enable_interrupts();
-               prepare_to_wait(&cdu535_irq_wait, &wait, TASK_INTERRUPTIBLE);
-               spin_unlock_irq(&sonycd535_lock);
-               schedule();
-               finish_wait(&cdu535_irq_wait, &wait);
-       }
-}
-
-/*------------------start of SONY CDU535 very specific ---------------------*/
-
-/****************************************************************************
- * void select_unit( int unit_no )
- *
- *  Select the specified unit (0-3) so that subsequent commands reference it
- ****************************************************************************/
-static void
-select_unit(int unit_no)
-{
-       unsigned int select_mask = ~(1 << unit_no);
-       outb(select_mask, select_unit_reg);
-}
-
-/***************************************************************************
- * int read_result_reg( Byte *data_ptr )
- *
- *  Read a result byte from the Sony CDU controller, store in location pointed
- * to by data_ptr.  Return zero on success, TIME_OUT if we did not receive
- * data.
- ***************************************************************************/
-static int
-read_result_reg(Byte *data_ptr)
-{
-       unsigned long snap;
-       int read_status;
-
-       snap = jiffies;
-       while (jiffies-snap < SONY_JIFFIES_TIMEOUT) {
-               read_status = inb(read_status_reg);
-               if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) {
-#if DEBUG > 1
-                       printk(CDU535_MESSAGE_NAME
-                                       ": read_result_reg(): readStatReg = 0x%x\n", read_status);
-#endif
-                       *data_ptr = inb(result_reg);
-                       return 0;
-               } else {
-                       sony_sleep();
-               }
-       }
-       printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n");
-       return TIME_OUT;
-}
-
-/****************************************************************************
- * int read_exec_status( Byte status[2] )
- *
- *  Read the execution status of the last command and put into status.
- * Handles reading second status word if available.  Returns 0 on success,
- * TIME_OUT on failure.
- ****************************************************************************/
-static int
-read_exec_status(Byte status[2])
-{
-       status[1] = 0;
-       if (read_result_reg(&(status[0])) != 0)
-               return TIME_OUT;
-       if ((status[0] & 0x80) != 0) {  /* byte two follows */
-               if (read_result_reg(&(status[1])) != 0)
-                       return TIME_OUT;
-       }
-#if DEBUG > 1
-       printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n",
-                       status[0], status[1]);
-#endif
-       return 0;
-}
-
-/****************************************************************************
- * int check_drive_status( void )
- *
- *  Check the current drive status.  Using this before executing a command
- * takes care of the problem of unsolicited drive status-2 messages.
- * Add a check of the audio status if we think the disk is playing.
- ****************************************************************************/
-static int
-check_drive_status(void)
-{
-       Byte status, e_status[2];
-       int  CDD, ATN;
-       Byte cmd;
-
-       select_unit(0);
-       if (sony_audio_status == CDROM_AUDIO_PLAY) {    /* check status */
-               outb(SONY535_REQUEST_AUDIO_STATUS, command_reg);
-               if (read_result_reg(&status) == 0) {
-                       switch (status) {
-                       case 0x0:
-                               break;          /* play in progress */
-                       case 0x1:
-                               break;          /* paused */
-                       case 0x3:               /* audio play completed */
-                       case 0x5:               /* play not requested */
-                               sony_audio_status = CDROM_AUDIO_COMPLETED;
-                               read_subcode();
-                               break;
-                       case 0x4:               /* error during play */
-                               sony_audio_status = CDROM_AUDIO_ERROR;
-                               break;
-                       }
-               }
-       }
-       /* now check drive status */
-       outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg);
-       if (read_result_reg(&status) != 0)
-               return TIME_OUT;
-
-#if DEBUG > 1
-       printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status);
-#endif
-
-       if (status == 0)
-               return 0;
-
-       ATN = status & 0xf;
-       CDD = (status >> 4) & 0xf;
-
-       switch (ATN) {
-       case 0x0:
-               break;                                  /* go on to CDD stuff */
-       case SONY535_ATN_BUSY:
-               if (initialized)
-                       printk(CDU535_MESSAGE_NAME " error: drive busy\n");
-               return CD_BUSY;
-       case SONY535_ATN_EJECT_IN_PROGRESS:
-               printk(CDU535_MESSAGE_NAME " error: eject in progress\n");
-               sony_audio_status = CDROM_AUDIO_INVALID;
-               return CD_BUSY;
-       case SONY535_ATN_RESET_OCCURRED:
-       case SONY535_ATN_DISC_CHANGED:
-       case SONY535_ATN_RESET_AND_DISC_CHANGED:
-#if DEBUG > 0
-               printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n");
-#endif
-               sony_disc_changed = 1;
-               sony_toc_read = 0;
-               sony_audio_status = CDROM_AUDIO_NO_STATUS;
-               sony_first_block = -1;
-               sony_last_block = -1;
-               if (initialized) {
-                       cmd = SONY535_SPIN_UP;
-                       do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0);
-                       sony_get_toc();
-               }
-               return 0;
-       default:
-               printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN);
-               return CD_BUSY;
-       }
-       switch (CDD) {                  /* the 531 docs are not helpful in decoding this */
-       case 0x0:                               /* just use the values from the DOS driver */
-       case 0x2:
-       case 0xa:
-               break;                          /* no error */
-       case 0xc:
-               printk(CDU535_MESSAGE_NAME
-                               ": check_drive_status(): CDD = 0xc! Not properly handled!\n");
-               return CD_BUSY;         /* ? */
-       default:
-               return CD_BUSY;
-       }
-       return 0;
-}      /* check_drive_status() */
-
-/*****************************************************************************
- * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2],
- *                Byte *response, int n_response, int ignore_status_bit7 )
- *
- *  Generic routine for executing commands.  The command and its parameters
- *  should be placed in the cmd[] array, number of bytes in the command is
- *  stored in nCmd.  The response from the command will be stored in the
- *  response array.  The number of bytes you expect back (excluding status)
- *  should be passed in n_response.  Finally, some
- *  commands set bit 7 of the return status even when there is no second
- *  status byte, on these commands set ignoreStatusBit7 TRUE.
- *    If the command was sent and data received back, then we return 0,
- *  else we return TIME_OUT.  You still have to check the status yourself.
- *    You should call check_drive_status() before calling this routine
- *  so that you do not lose notifications of disk changes, etc.
- ****************************************************************************/
-static int
-do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2],
-                       Byte * response, int n_response, int ignore_status_bit7)
-{
-       int i;
-
-       /* write out the command */
-       for (i = 0; i < n_cmd; i++)
-               outb(cmd[i], command_reg);
-
-       /* read back the status */
-       if (read_result_reg(status) != 0)
-               return TIME_OUT;
-       if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) {
-               /* get second status byte */
-               if (read_result_reg(status + 1) != 0)
-                       return TIME_OUT;
-       } else {
-               status[1] = 0;
-       }
-#if DEBUG > 2
-       printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n",
-                       *cmd, status[0], status[1]);
-#endif
-
-       /* do not know about when I should read set of data and when not to */
-       if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0)
-               return 0;
-
-       /* else, read in rest of data */
-       for (i = 0; 0 < n_response; n_response--, i++)
-               if (read_result_reg(response + i) != 0)
-                       return TIME_OUT;
-       return 0;
-}      /* do_sony_cmd() */
-
-/**************************************************************************
- * int set_drive_mode( int mode, Byte status[2] )
- *
- *  Set the drive mode to the specified value (mode=0 is audio, mode=e0
- * is mode-1 CDROM
- **************************************************************************/
-static int
-set_drive_mode(int mode, Byte status[2])
-{
-       Byte cmd_buff[2];
-       Byte ret_buff[1];
-
-       cmd_buff[0] = SONY535_SET_DRIVE_MODE;
-       cmd_buff[1] = mode;
-       return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1);
-}
-
-/***************************************************************************
- * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2],
- *                             Byte *data_buff, int buff_size )
- *
- *  Read n_blocks of data from the CDROM starting at position params[0:2],
- *  number of blocks in stored in params[3:5] -- both these are already
- *  int bcd format.
- *  Transfer the data into the buffer pointed at by data_buff.  buff_size
- *  gives the number of bytes available in the buffer.
- *    The routine returns number of bytes read in if successful, otherwise
- *  it returns one of the standard error returns.
- ***************************************************************************/
-static int
-seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
-                                          Byte **buff, int buf_size)
-{
-       Byte cmd_buff[7];
-       int  i;
-       int  read_status;
-       unsigned long snap;
-       Byte *data_buff;
-       int  sector_count = 0;
-
-       if (buf_size < CDU535_BLOCK_SIZE * n_blocks)
-               return NO_ROOM;
-
-       set_drive_mode(SONY535_CDROM_DRIVE_MODE, status);
-
-       /* send command to read the data */
-       cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1;
-       for (i = 0; i < 6; i++)
-               cmd_buff[i + 1] = params[i];
-       for (i = 0; i < 7; i++)
-               outb(cmd_buff[i], command_reg);
-
-       /* read back the data one block at a time */
-       while (0 < n_blocks--) {
-               /* wait for data to be ready */
-               int data_valid = 0;
-               snap = jiffies;
-               while (jiffies-snap < SONY_JIFFIES_TIMEOUT) {
-                       read_status = inb(read_status_reg);
-                       if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) {
-                               read_exec_status(status);
-                               return BAD_STATUS;
-                       }
-                       if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) {
-                               /* data is ready, read it */
-                               data_buff = buff[sector_count++];
-                               for (i = 0; i < CDU535_BLOCK_SIZE; i++)
-                                       *data_buff++ = inb(data_reg);   /* unrolling this loop does not seem to help */
-                               data_valid = 1;
-                               break;                  /* exit the timeout loop */
-                       }
-                       sony_sleep();           /* data not ready, sleep a while */
-               }
-               if (!data_valid)
-                       return TIME_OUT;        /* if we reach this stage */
-       }
-
-       /* read all the data, now read the status */
-       if ((i = read_exec_status(status)) != 0)
-               return i;
-       return CDU535_BLOCK_SIZE * sector_count;
-}      /* seek_and_read_N_blocks() */
-
-/****************************************************************************
- * int request_toc_data( Byte status[2], struct s535_sony_toc *toc )
- *
- *  Read in the table of contents data.  Converts all the bcd data
- * into integers in the toc structure.
- ****************************************************************************/
-static int
-request_toc_data(Byte status[2], struct s535_sony_toc *toc)
-{
-       int  to_status;
-       int  i, j, n_tracks, track_no;
-       int  first_track_num, last_track_num;
-       Byte cmd_no = 0xb2;
-       Byte track_address_buffer[5];
-
-       /* read the fixed portion of the table of contents */
-       if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0)
-               return to_status;
-
-       /* convert the data into integers so we can use them */
-       first_track_num = bcd_to_int(toc->first_track_num);
-       last_track_num = bcd_to_int(toc->last_track_num);
-       n_tracks = last_track_num - first_track_num + 1;
-
-       /* read each of the track address descriptors */
-       for (i = 0; i < n_tracks; i++) {
-               /* read the descriptor into a temporary buffer */
-               for (j = 0; j < 5; j++) {
-                       if (read_result_reg(track_address_buffer + j) != 0)
-                               return TIME_OUT;
-                       if (j == 1)             /* need to convert from bcd */
-                               track_no = bcd_to_int(track_address_buffer[j]);
-               }
-               /* copy the descriptor to proper location - sonycd.c just fills */
-               memcpy(toc->tracks + i, track_address_buffer, 5);
-       }
-       return 0;
-}      /* request_toc_data() */
-
-/***************************************************************************
- * int spin_up_drive( Byte status[2] )
- *
- *  Spin up the drive (unless it is already spinning).
- ***************************************************************************/
-static int
-spin_up_drive(Byte status[2])
-{
-       Byte cmd;
-
-       /* first see if the drive is already spinning */
-       cmd = SONY535_REQUEST_DRIVE_STATUS_1;
-       if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0)
-               return TIME_OUT;
-       if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0)
-               return 0;       /* it's already spinning */
-
-       /* otherwise, give the spin-up command */
-       cmd = SONY535_SPIN_UP;
-       return do_sony_cmd(&cmd, 1, status, NULL, 0, 0);
-}
-
-/*--------------------end of SONY CDU535 very specific ---------------------*/
-
-/* Convert from an integer 0-99 to BCD */
-static inline unsigned int
-int_to_bcd(unsigned int val)
-{
-       int retval;
-
-       retval = (val / 10) << 4;
-       retval = retval | val % 10;
-       return retval;
-}
-
-
-/* Convert from BCD to an integer from 0-99 */
-static unsigned int
-bcd_to_int(unsigned int bcd)
-{
-       return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f);
-}
-
-
-/*
- * Convert a logical sector value (like the OS would want to use for
- * a block device) to an MSF format.
- */
-static void
-log_to_msf(unsigned int log, Byte *msf)
-{
-       log = log + LOG_START_OFFSET;
-       msf[0] = int_to_bcd(log / 4500);
-       log = log % 4500;
-       msf[1] = int_to_bcd(log / 75);
-       msf[2] = int_to_bcd(log % 75);
-}
-
-
-/*
- * Convert an MSF format to a logical sector.
- */
-static unsigned int
-msf_to_log(Byte *msf)
-{
-       unsigned int log;
-
-
-       log = bcd_to_int(msf[2]);
-       log += bcd_to_int(msf[1]) * 75;
-       log += bcd_to_int(msf[0]) * 4500;
-       log = log - LOG_START_OFFSET;
-
-       return log;
-}
-
-
-/*
- * Take in integer size value and put it into a buffer like
- * the drive would want to see a number-of-sector value.
- */
-static void
-size_to_buf(unsigned int size, Byte *buf)
-{
-       buf[0] = size / 65536;
-       size = size % 65536;
-       buf[1] = size / 256;
-       buf[2] = size % 256;
-}
-
-
-/*
- * The OS calls this to perform a read or write operation to the drive.
- * Write obviously fail.  Reads to a read ahead of sony_buffer_size
- * bytes to help speed operations.  This especially helps since the OS
- * may use 1024 byte blocks and the drive uses 2048 byte blocks.  Since most
- * data access on a CD is done sequentially, this saves a lot of operations.
- */
-static void
-do_cdu535_request(request_queue_t * q)
-{
-       struct request *req;
-       unsigned int read_size;
-       int  block;
-       int  nsect;
-       int  copyoff;
-       int  spin_up_retry;
-       Byte params[10];
-       Byte status[2];
-       Byte cmd[2];
-
-       while (1) {
-               req = elv_next_request(q);
-               if (!req)
-                       return;
-
-               block = req->sector;
-               nsect = req->nr_sectors;
-               if (!blk_fs_request(req)) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (rq_data_dir(req) == WRITE) {
-                       end_request(req, 0);
-                       continue;
-               }
-               /*
-                * If the block address is invalid or the request goes beyond
-                * the end of the media, return an error.
-                */
-               if (sony_toc->lead_out_start_lba <= (block/4)) {
-                       end_request(req, 0);
-                       return;
-               }
-               if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) {
-                       end_request(req, 0);
-                       return;
-               }
-               while (0 < nsect) {
-                       /*
-                        * If the requested sector is not currently in
-                        * the read-ahead buffer, it must be read in.
-                        */
-                       if ((block < sony_first_block) || (sony_last_block < block)) {
-                               sony_first_block = (block / 4) * 4;
-                               log_to_msf(block / 4, params);
-                               
-                               /*
-                                * If the full read-ahead would go beyond the end of the media, trim
-                                * it back to read just till the end of the media.
-                                */
-                               if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) {
-                                       sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
-                                       read_size = sony_toc->lead_out_start_lba - (block / 4);
-                               } else {
-                                       sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
-                                       read_size = sony_buffer_sectors;
-                               }
-                               size_to_buf(read_size, &params[3]);
-                               
-                               /*
-                                * Read the data.  If the drive was not spinning,
-                                * spin it up and try some more.
-                                */
-                               for (spin_up_retry=0 ;; ++spin_up_retry) {
-                                       /* This loop has been modified to support the Sony
-                                        * CDU-510/515 series, thanks to Claudio Porfiri 
-                                        * <C.Porfiri@nisms.tei.ericsson.se>.
-                                        */
-                                       /*
-                                        * This part is to deal with very slow hardware.  We
-                                        * try at most MAX_SPINUP_RETRY times to read the same
-                                        * block.  A check for seek_and_read_N_blocks' result is
-                                        * performed; if the result is wrong, the CDROM's engine
-                                        * is restarted and the operation is tried again.
-                                        */
-                                       /*
-                                        * 1995-06-01: The system got problems when downloading
-                                        * from Slackware CDROM, the problem seems to be:
-                                        * seek_and_read_N_blocks returns BAD_STATUS and we
-                                        * should wait for a while before retrying, so a new
-                                        * part was added to discriminate the return value from
-                                        * seek_and_read_N_blocks for the various cases.
-                                        */
-                                       int readStatus = seek_and_read_N_blocks(params, read_size,
-                                                                               status, sony_buffer, (read_size * CDU535_BLOCK_SIZE));
-                                       if (0 <= readStatus)    /* Good data; common case, placed first */
-                                               break;
-                                       if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) {
-                                               /* give up */
-                                               if (readStatus == NO_ROOM)
-                                                       printk(CDU535_MESSAGE_NAME " No room to read from CD\n");
-                                               else
-                                                       printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
-                                                              status[0]);
-                                               sony_first_block = -1;
-                                               sony_last_block = -1;
-                                               end_request(req, 0);
-                                               return;
-                                       }
-                                       if (readStatus == BAD_STATUS) {
-                                               /* Sleep for a while, then retry */
-                                               set_current_state(TASK_INTERRUPTIBLE);
-                                               spin_unlock_irq(&sonycd535_lock);
-                                               schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
-                                               spin_lock_irq(&sonycd535_lock);
-                                       }
-#if DEBUG > 0
-                                       printk(CDU535_MESSAGE_NAME
-                                              " debug: calling spin up when reading data!\n");
-#endif
-                                       cmd[0] = SONY535_SPIN_UP;
-                                       do_sony_cmd(cmd, 1, status, NULL, 0, 0);
-                               }
-                       }
-                       /*
-                        * The data is in memory now, copy it to the buffer and advance to the
-                        * next block to read.
-                        */
-                       copyoff = block - sony_first_block;
-                       memcpy(req->buffer,
-                              sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
-                       
-                       block += 1;
-                       nsect -= 1;
-                       req->buffer += 512;
-               }
-
-               end_request(req, 1);
-       }
-}
-
-/*
- * Read the table of contents from the drive and set sony_toc_read if
- * successful.
- */
-static void
-sony_get_toc(void)
-{
-       Byte status[2];
-       if (!sony_toc_read) {
-               /* do not call check_drive_status() from here since it can call this routine */
-               if (request_toc_data(status, sony_toc) < 0)
-                       return;
-               sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf);
-               sony_toc_read = 1;
-       }
-}
-
-
-/*
- * Search for a specific track in the table of contents.  track is
- * passed in bcd format
- */
-static int
-find_track(int track)
-{
-       int i;
-       int num_tracks;
-
-
-       num_tracks = bcd_to_int(sony_toc->last_track_num) -
-               bcd_to_int(sony_toc->first_track_num) + 1;
-       for (i = 0; i < num_tracks; i++) {
-               if (sony_toc->tracks[i].track == track) {
-                       return i;
-               }
-       }
-
-       return -1;
-}
-
-/*
- * Read the subcode and put it int last_sony_subcode for future use.
- */
-static int
-read_subcode(void)
-{
-       Byte cmd = SONY535_REQUEST_SUB_Q_DATA;
-       Byte status[2];
-       int  dsc_status;
-
-       if (check_drive_status() != 0)
-               return -EIO;
-
-       if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode,
-                                                          sizeof(struct s535_sony_subcode), 1)) != 0) {
-               printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n",
-                               status[0], dsc_status);
-               return -EIO;
-       }
-       return 0;
-}
-
-
-/*
- * Get the subchannel info like the CDROMSUBCHNL command wants to see it.  If
- * the drive is playing, the subchannel needs to be read (since it would be
- * changing).  If the drive is paused or completed, the subcode information has
- * already been stored, just use that.  The ioctl call wants things in decimal
- * (not BCD), so all the conversions are done.
- */
-static int
-sony_get_subchnl_info(void __user *arg)
-{
-       struct cdrom_subchnl schi;
-
-       /* Get attention stuff */
-       if (check_drive_status() != 0)
-               return -EIO;
-
-       sony_get_toc();
-       if (!sony_toc_read) {
-               return -EIO;
-       }
-       if (copy_from_user(&schi, arg, sizeof schi))
-               return -EFAULT;
-
-       switch (sony_audio_status) {
-       case CDROM_AUDIO_PLAY:
-               if (read_subcode() < 0) {
-                       return -EIO;
-               }
-               break;
-
-       case CDROM_AUDIO_PAUSED:
-       case CDROM_AUDIO_COMPLETED:
-               break;
-
-       case CDROM_AUDIO_NO_STATUS:
-               schi.cdsc_audiostatus = sony_audio_status;
-               if (copy_to_user(arg, &schi, sizeof schi))
-                       return -EFAULT;
-               return 0;
-               break;
-
-       case CDROM_AUDIO_INVALID:
-       case CDROM_AUDIO_ERROR:
-       default:
-               return -EIO;
-       }
-
-       schi.cdsc_audiostatus = sony_audio_status;
-       schi.cdsc_adr = last_sony_subcode->address;
-       schi.cdsc_ctrl = last_sony_subcode->control;
-       schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num);
-       schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num);
-       if (schi.cdsc_format == CDROM_MSF) {
-               schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]);
-               schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]);
-               schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]);
-
-               schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]);
-               schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]);
-               schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]);
-       } else if (schi.cdsc_format == CDROM_LBA) {
-               schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
-               schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
-       }
-       return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0;
-}
-
-
-/*
- * The big ugly ioctl handler.
- */
-static int
-cdu_ioctl(struct inode *inode,
-                 struct file *file,
-                 unsigned int cmd,
-                 unsigned long arg)
-{
-       Byte status[2];
-       Byte cmd_buff[10], params[10];
-       int  i;
-       int  dsc_status;
-       void __user *argp = (void __user *)arg;
-
-       if (check_drive_status() != 0)
-               return -EIO;
-
-       switch (cmd) {
-       case CDROMSTART:                        /* Spin up the drive */
-               if (spin_up_drive(status) < 0) {
-                       printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n",
-                                       status[0]);
-                       return -EIO;
-               }
-               return 0;
-               break;
-
-       case CDROMSTOP:                 /* Spin down the drive */
-               cmd_buff[0] = SONY535_HOLD;
-               do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-
-               /*
-                * Spin the drive down, ignoring the error if the disk was
-                * already not spinning.
-                */
-               sony_audio_status = CDROM_AUDIO_NO_STATUS;
-               cmd_buff[0] = SONY535_SPIN_DOWN;
-               dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-               if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) ||
-                       ((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) {
-                       printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n",
-                                       status[0]);
-                       return -EIO;
-               }
-               return 0;
-               break;
-
-       case CDROMPAUSE:                        /* Pause the drive */
-               cmd_buff[0] = SONY535_HOLD;             /* CDU-31 driver uses AUDIO_STOP, not pause */
-               if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
-                       printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n",
-                                       status[0]);
-                       return -EIO;
-               }
-               /* Get the current position and save it for resuming */
-               if (read_subcode() < 0) {
-                       return -EIO;
-               }
-               cur_pos_msf[0] = last_sony_subcode->abs_msf[0];
-               cur_pos_msf[1] = last_sony_subcode->abs_msf[1];
-               cur_pos_msf[2] = last_sony_subcode->abs_msf[2];
-               sony_audio_status = CDROM_AUDIO_PAUSED;
-               return 0;
-               break;
-
-       case CDROMRESUME:                       /* Start the drive after being paused */
-               set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status);
-
-               if (sony_audio_status != CDROM_AUDIO_PAUSED) {
-                       return -EINVAL;
-               }
-               spin_up_drive(status);
-
-               /* Start the drive at the saved position. */
-               cmd_buff[0] = SONY535_PLAY_AUDIO;
-               cmd_buff[1] = 0;                /* play back starting at this address */
-               cmd_buff[2] = cur_pos_msf[0];
-               cmd_buff[3] = cur_pos_msf[1];
-               cmd_buff[4] = cur_pos_msf[2];
-               cmd_buff[5] = SONY535_PLAY_AUDIO;
-               cmd_buff[6] = 2;                /* set ending address */
-               cmd_buff[7] = final_pos_msf[0];
-               cmd_buff[8] = final_pos_msf[1];
-               cmd_buff[9] = final_pos_msf[2];
-               if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
-                       (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
-                       printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n",
-                                       status[0]);
-                       return -EIO;
-               }
-               sony_audio_status = CDROM_AUDIO_PLAY;
-               return 0;
-               break;
-
-       case CDROMPLAYMSF:                      /* Play starting at the given MSF address. */
-               if (copy_from_user(params, argp, 6))
-                       return -EFAULT;
-               spin_up_drive(status);
-               set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status);
-
-               /* The parameters are given in int, must be converted */
-               for (i = 0; i < 3; i++) {
-                       cmd_buff[2 + i] = int_to_bcd(params[i]);
-                       cmd_buff[7 + i] = int_to_bcd(params[i + 3]);
-               }
-               cmd_buff[0] = SONY535_PLAY_AUDIO;
-               cmd_buff[1] = 0;                /* play back starting at this address */
-               /* cmd_buff[2-4] are filled in for loop above */
-               cmd_buff[5] = SONY535_PLAY_AUDIO;
-               cmd_buff[6] = 2;                /* set ending address */
-               /* cmd_buff[7-9] are filled in for loop above */
-               if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
-                       (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
-                       printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n",
-                                       status[0]);
-                       return -EIO;
-               }
-               /* Save the final position for pauses and resumes */
-               final_pos_msf[0] = cmd_buff[7];
-               final_pos_msf[1] = cmd_buff[8];
-               final_pos_msf[2] = cmd_buff[9];
-               sony_audio_status = CDROM_AUDIO_PLAY;
-               return 0;
-               break;
-
-       case CDROMREADTOCHDR:           /* Read the table of contents header */
-               {
-                       struct cdrom_tochdr __user *hdr = argp;
-                       struct cdrom_tochdr loc_hdr;
-
-                       sony_get_toc();
-                       if (!sony_toc_read)
-                               return -EIO;
-                       loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
-                       loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
-                       if (copy_to_user(hdr, &loc_hdr, sizeof *hdr))
-                               return -EFAULT;
-               }
-               return 0;
-               break;
-
-       case CDROMREADTOCENTRY: /* Read a given table of contents entry */
-               {
-                       struct cdrom_tocentry __user *entry = argp;
-                       struct cdrom_tocentry loc_entry;
-                       int  track_idx;
-                       Byte *msf_val = NULL;
-
-                       sony_get_toc();
-                       if (!sony_toc_read) {
-                               return -EIO;
-                       }
-
-                       if (copy_from_user(&loc_entry, entry, sizeof loc_entry))
-                               return -EFAULT;
-
-                       /* Lead out is handled separately since it is special. */
-                       if (loc_entry.cdte_track == CDROM_LEADOUT) {
-                               loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ;
-                               loc_entry.cdte_ctrl = sony_toc->control2;
-                               msf_val = sony_toc->lead_out_start_msf;
-                       } else {
-                               track_idx = find_track(int_to_bcd(loc_entry.cdte_track));
-                               if (track_idx < 0)
-                                       return -EINVAL;
-                               loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ;
-                               loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control;
-                               msf_val = sony_toc->tracks[track_idx].track_start_msf;
-                       }
-
-                       /* Logical buffer address or MSF format requested? */
-                       if (loc_entry.cdte_format == CDROM_LBA) {
-                               loc_entry.cdte_addr.lba = msf_to_log(msf_val);
-                       } else if (loc_entry.cdte_format == CDROM_MSF) {
-                               loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val);
-                               loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1));
-                               loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2));
-                       }
-                       if (copy_to_user(entry, &loc_entry, sizeof *entry))
-                               return -EFAULT;
-               }
-               return 0;
-               break;
-
-       case CDROMPLAYTRKIND:           /* Play a track.  This currently ignores index. */
-               {
-                       struct cdrom_ti ti;
-                       int track_idx;
-
-                       sony_get_toc();
-                       if (!sony_toc_read)
-                               return -EIO;
-
-                       if (copy_from_user(&ti, argp, sizeof ti))
-                               return -EFAULT;
-                       if ((ti.cdti_trk0 < sony_toc->first_track_num)
-                               || (sony_toc->last_track_num < ti.cdti_trk0)
-                               || (ti.cdti_trk1 < ti.cdti_trk0)) {
-                               return -EINVAL;
-                       }
-                       track_idx = find_track(int_to_bcd(ti.cdti_trk0));
-                       if (track_idx < 0)
-                               return -EINVAL;
-                       params[1] = sony_toc->tracks[track_idx].track_start_msf[0];
-                       params[2] = sony_toc->tracks[track_idx].track_start_msf[1];
-                       params[3] = sony_toc->tracks[track_idx].track_start_msf[2];
-                       /*
-                        * If we want to stop after the last track, use the lead-out
-                        * MSF to do that.
-                        */
-                       if (bcd_to_int(sony_toc->last_track_num) <= ti.cdti_trk1) {
-                               log_to_msf(msf_to_log(sony_toc->lead_out_start_msf) - 1,
-                                                  &(params[4]));
-                       } else {
-                               track_idx = find_track(int_to_bcd(ti.cdti_trk1 + 1));
-                               if (track_idx < 0)
-                                       return -EINVAL;
-                               log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf) - 1,
-                                                  &(params[4]));
-                       }
-                       params[0] = 0x03;
-
-                       spin_up_drive(status);
-
-                       set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status);
-
-                       /* Start the drive at the saved position. */
-                       cmd_buff[0] = SONY535_PLAY_AUDIO;
-                       cmd_buff[1] = 0;        /* play back starting at this address */
-                       cmd_buff[2] = params[1];
-                       cmd_buff[3] = params[2];
-                       cmd_buff[4] = params[3];
-                       cmd_buff[5] = SONY535_PLAY_AUDIO;
-                       cmd_buff[6] = 2;        /* set ending address */
-                       cmd_buff[7] = params[4];
-                       cmd_buff[8] = params[5];
-                       cmd_buff[9] = params[6];
-                       if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
-                               (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
-                               printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n",
-                                               status[0]);
-                               printk("... Params: %x %x %x %x %x %x %x\n",
-                                               params[0], params[1], params[2],
-                                               params[3], params[4], params[5], params[6]);
-                               return -EIO;
-                       }
-                       /* Save the final position for pauses and resumes */
-                       final_pos_msf[0] = params[4];
-                       final_pos_msf[1] = params[5];
-                       final_pos_msf[2] = params[6];
-                       sony_audio_status = CDROM_AUDIO_PLAY;
-                       return 0;
-               }
-
-       case CDROMSUBCHNL:                      /* Get subchannel info */
-               return sony_get_subchnl_info(argp);
-
-       case CDROMVOLCTRL:                      /* Volume control.  What volume does this change, anyway? */
-               {
-                       struct cdrom_volctrl volctrl;
-
-                       if (copy_from_user(&volctrl, argp, sizeof volctrl))
-                               return -EFAULT;
-                       cmd_buff[0] = SONY535_SET_VOLUME;
-                       cmd_buff[1] = volctrl.channel0;
-                       cmd_buff[2] = volctrl.channel1;
-                       if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) {
-                               printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n",
-                                               status[0]);
-                               return -EIO;
-                       }
-               }
-               return 0;
-
-       case CDROMEJECT:                        /* Eject the drive */
-               cmd_buff[0] = SONY535_STOP;
-               do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-               cmd_buff[0] = SONY535_SPIN_DOWN;
-               do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-
-               sony_audio_status = CDROM_AUDIO_INVALID;
-               cmd_buff[0] = SONY535_EJECT_CADDY;
-               if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
-                       printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n",
-                                       status[0]);
-                       return -EIO;
-               }
-               return 0;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-}
-
-
-/*
- * Open the drive for operations.  Spin the drive up and read the table of
- * contents if these have not already been done.
- */
-static int
-cdu_open(struct inode *inode,
-                struct file *filp)
-{
-       Byte status[2], cmd_buff[2];
-
-       if (sony_inuse)
-               return -EBUSY;
-       if (check_drive_status() != 0)
-               return -EIO;
-       sony_inuse = 1;
-
-       if (spin_up_drive(status) != 0) {
-               printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n",
-                               status[0]);
-               sony_inuse = 0;
-               return -EIO;
-       }
-       sony_get_toc();
-       if (!sony_toc_read) {
-               cmd_buff[0] = SONY535_SPIN_DOWN;
-               do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-               sony_inuse = 0;
-               return -EIO;
-       }
-       check_disk_change(inode->i_bdev);
-       sony_usage++;
-
-#ifdef LOCK_DOORS
-       /* disable the eject button while mounted */
-       cmd_buff[0] = SONY535_DISABLE_EJECT_BUTTON;
-       do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-#endif
-
-       return 0;
-}
-
-
-/*
- * Close the drive.  Spin it down if no task is using it.  The spin
- * down will fail if playing audio, so audio play is OK.
- */
-static int
-cdu_release(struct inode *inode,
-                       struct file *filp)
-{
-       Byte status[2], cmd_no;
-
-       sony_inuse = 0;
-
-       if (0 < sony_usage) {
-               sony_usage--;
-       }
-       if (sony_usage == 0) {
-               check_drive_status();
-
-               if (sony_audio_status != CDROM_AUDIO_PLAY) {
-                       cmd_no = SONY535_SPIN_DOWN;
-                       do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0);
-               }
-#ifdef LOCK_DOORS
-               /* enable the eject button after umount */
-               cmd_no = SONY535_ENABLE_EJECT_BUTTON;
-               do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0);
-#endif
-       }
-       return 0;
-}
-
-static struct block_device_operations cdu_fops =
-{
-       .owner          = THIS_MODULE,
-       .open           = cdu_open,
-       .release        = cdu_release,
-       .ioctl          = cdu_ioctl,
-       .media_changed  = cdu535_check_media_change,
-};
-
-static struct gendisk *cdu_disk;
-
-/*
- * Initialize the driver.
- */
-static int __init sony535_init(void)
-{
-       struct s535_sony_drive_config drive_config;
-       Byte cmd_buff[3];
-       Byte ret_buff[2];
-       Byte status[2];
-       unsigned long snap;
-       int  got_result = 0;
-       int  tmp_irq;
-       int  i;
-       int err;
-
-       /* Setting the base I/O address to 0 will disable it. */
-       if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0))
-               return 0;
-
-       /* Set up all the register locations */
-       result_reg = sony535_cd_base_io;
-       command_reg = sony535_cd_base_io;
-       data_reg = sony535_cd_base_io + 1;
-       read_status_reg = sony535_cd_base_io + 2;
-       select_unit_reg = sony535_cd_base_io + 3;
-
-#ifndef USE_IRQ
-       sony535_irq_used = 0;   /* polling only until this is ready... */
-#endif
-       /* we need to poll until things get initialized */
-       tmp_irq = sony535_irq_used;
-       sony535_irq_used = 0;
-
-#if DEBUG > 0
-       printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n",
-                       sony535_cd_base_io);
-#endif
-       /* look for the CD-ROM, follows the procedure in the DOS driver */
-       inb(select_unit_reg);
-       /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */
-       schedule_timeout_interruptible((HZ+17)*40/18);
-       inb(result_reg);
-
-       outb(0, read_status_reg);       /* does a reset? */
-       snap = jiffies;
-       while (jiffies-snap < SONY_JIFFIES_TIMEOUT) {
-               select_unit(0);
-               if (inb(result_reg) != 0xff) {
-                       got_result = 1;
-                       break;
-               }
-               sony_sleep();
-       }
-
-       if (!got_result || check_drive_status() == TIME_OUT)
-               goto Enodev;
-
-       /* CD-ROM drive responded --  get the drive configuration */
-       cmd_buff[0] = SONY535_INQUIRY;
-       if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0)
-               goto Enodev;
-
-       /* was able to get the configuration,
-        * set drive mode as rest of init
-        */
-#if DEBUG > 0
-       /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */
-       if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 )
-               printk(CDU535_MESSAGE_NAME
-                               "Inquiry command returned status = 0x%x\n", status[0]);
-#endif
-       /* now ready to use interrupts, if available */
-       sony535_irq_used = tmp_irq;
-
-       /* A negative sony535_irq_used will attempt an autoirq. */
-       if (sony535_irq_used < 0) {
-               unsigned long irq_mask, delay;
-
-               irq_mask = probe_irq_on();
-               enable_interrupts();
-               outb(0, read_status_reg);       /* does a reset? */
-               delay = jiffies + HZ/10;
-               while (time_before(jiffies, delay)) ;
-
-               sony535_irq_used = probe_irq_off(irq_mask);
-               disable_interrupts();
-       }
-       if (sony535_irq_used > 0) {
-           if (request_irq(sony535_irq_used, cdu535_interrupt,
-                                               IRQF_DISABLED, CDU535_HANDLE, NULL)) {
-                       printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME
-                                       " driver; polling instead.\n", sony535_irq_used);
-                       sony535_irq_used = 0;
-               }
-       }
-       cmd_buff[0] = SONY535_SET_DRIVE_MODE;
-       cmd_buff[1] = 0x0;      /* default audio */
-       if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0)
-               goto Enodev_irq;
-
-       /* set the drive mode successful, we are set! */
-       sony_buffer_size = SONY535_BUFFER_SIZE;
-       sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE;
-
-       printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
-                  drive_config.vendor_id,
-                  drive_config.product_id,
-                  drive_config.product_rev_level);
-       printk("  base address %03X, ", sony535_cd_base_io);
-       if (tmp_irq > 0)
-               printk("IRQ%d, ", tmp_irq);
-       printk("using %d byte buffer\n", sony_buffer_size);
-
-       if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) {
-               err = -EIO;
-               goto out1;
-       }
-       sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock);
-       if (!sonycd535_queue) {
-               err = -ENOMEM;
-               goto out1a;
-       }
-
-       blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE);
-       sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL);
-       err = -ENOMEM;
-       if (!sony_toc)
-               goto out2;
-       last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL);
-       if (!last_sony_subcode)
-               goto out3;
-       sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL);
-       if (!sony_buffer)
-               goto out4;
-       for (i = 0; i < sony_buffer_sectors; i++) {
-               sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL);
-               if (!sony_buffer[i]) {
-                       while (--i>=0)
-                               kfree(sony_buffer[i]);
-                       goto out5;
-               }
-       }
-       initialized = 1;
-
-       cdu_disk = alloc_disk(1);
-       if (!cdu_disk)
-               goto out6;
-       cdu_disk->major = MAJOR_NR;
-       cdu_disk->first_minor = 0;
-       cdu_disk->fops = &cdu_fops;
-       sprintf(cdu_disk->disk_name, "cdu");
-
-       if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) {
-               printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n",
-                       sony535_cd_base_io);
-               goto out7;
-       }
-       cdu_disk->queue = sonycd535_queue;
-       add_disk(cdu_disk);
-       return 0;
-
-out7:
-       put_disk(cdu_disk);
-out6:
-       for (i = 0; i < sony_buffer_sectors; i++)
-               kfree(sony_buffer[i]);
-out5:
-       kfree(sony_buffer);
-out4:
-       kfree(last_sony_subcode);
-out3:
-       kfree(sony_toc);
-out2:
-       blk_cleanup_queue(sonycd535_queue);
-out1a:
-       unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
-out1:
-       if (sony535_irq_used)
-               free_irq(sony535_irq_used, NULL);
-       return err;
-Enodev_irq:
-       if (sony535_irq_used)
-               free_irq(sony535_irq_used, NULL);
-Enodev:
-       printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
-       return -EIO;
-}
-
-#ifndef MODULE
-
-/*
- * accept "kernel command line" parameters
- * (added by emoenke@gwdg.de)
- *
- * use: tell LILO:
- *                 sonycd535=0x320
- *
- * the address value has to be the existing CDROM port address.
- */
-static int __init
-sonycd535_setup(char *strings)
-{
-       int ints[3];
-       (void)get_options(strings, ARRAY_SIZE(ints), ints);
-       /* if IRQ change and default io base desired,
-        * then call with io base of 0
-        */
-       if (ints[0] > 0)
-               if (ints[1] != 0)
-                       sony535_cd_base_io = ints[1];
-       if (ints[0] > 1)
-               sony535_irq_used = ints[2];
-       if ((strings != NULL) && (*strings != '\0'))
-               printk(CDU535_MESSAGE_NAME
-                               ": Warning: Unknown interface type: %s\n", strings);
-                               
-       return 1;
-}
-
-__setup("sonycd535=", sonycd535_setup);
-
-#endif /* MODULE */
-
-static void __exit
-sony535_exit(void)
-{
-       int i;
-
-       release_region(sony535_cd_base_io, 4);
-       for (i = 0; i < sony_buffer_sectors; i++)
-               kfree(sony_buffer[i]);
-       kfree(sony_buffer);
-       kfree(last_sony_subcode);
-       kfree(sony_toc);
-       del_gendisk(cdu_disk);
-       put_disk(cdu_disk);
-       blk_cleanup_queue(sonycd535_queue);
-       if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
-               printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
-       else
-               printk(KERN_INFO CDU535_HANDLE " module released\n");
-}
-
-module_init(sony535_init);
-module_exit(sony535_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR);
diff --git a/drivers/cdrom/sonycd535.h b/drivers/cdrom/sonycd535.h
deleted file mode 100644 (file)
index 5dea1ef..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-#ifndef SONYCD535_H
-#define SONYCD535_H
-
-/*
- * define all the commands recognized by the CDU-531/5
- */
-#define SONY535_REQUEST_DRIVE_STATUS_1         (0x80)
-#define SONY535_REQUEST_SENSE                  (0x82)
-#define SONY535_REQUEST_DRIVE_STATUS_2         (0x84)
-#define SONY535_REQUEST_ERROR_STATUS           (0x86)
-#define SONY535_REQUEST_AUDIO_STATUS           (0x88)
-#define SONY535_INQUIRY                                (0x8a)
-
-#define SONY535_SET_INACTIVITY_TIME            (0x90)
-
-#define SONY535_SEEK_AND_READ_N_BLOCKS_1       (0xa0)
-#define SONY535_SEEK_AND_READ_N_BLOCKS_2       (0xa4)
-#define SONY535_PLAY_AUDIO                     (0xa6)
-
-#define SONY535_REQUEST_DISC_CAPACITY          (0xb0)
-#define SONY535_REQUEST_TOC_DATA               (0xb2)
-#define SONY535_REQUEST_SUB_Q_DATA             (0xb4)
-#define SONY535_REQUEST_ISRC                   (0xb6)
-#define SONY535_REQUEST_UPC_EAN                        (0xb8)
-
-#define SONY535_SET_DRIVE_MODE                 (0xc0)
-#define SONY535_REQUEST_DRIVE_MODE             (0xc2)
-#define SONY535_SET_RETRY_COUNT                        (0xc4)
-
-#define SONY535_DIAGNOSTIC_1                   (0xc6)
-#define SONY535_DIAGNOSTIC_4                   (0xcc)
-#define SONY535_DIAGNOSTIC_5                   (0xce)
-
-#define SONY535_EJECT_CADDY                    (0xd0)
-#define SONY535_DISABLE_EJECT_BUTTON           (0xd2)
-#define SONY535_ENABLE_EJECT_BUTTON            (0xd4)
-
-#define SONY535_HOLD                           (0xe0)
-#define SONY535_AUDIO_PAUSE_ON_OFF             (0xe2)
-#define SONY535_SET_VOLUME                     (0xe8)
-
-#define SONY535_STOP                           (0xf0)
-#define SONY535_SPIN_UP                                (0xf2)
-#define SONY535_SPIN_DOWN                      (0xf4)
-
-#define SONY535_CLEAR_PARAMETERS               (0xf6)
-#define SONY535_CLEAR_ENDING_ADDRESS           (0xf8)
-
-/*
- * define some masks
- */
-#define SONY535_DATA_NOT_READY_BIT             (0x1)
-#define SONY535_RESULT_NOT_READY_BIT           (0x2)
-
-/*
- *  drive status 1
- */
-#define SONY535_STATUS1_COMMAND_ERROR          (0x1)
-#define SONY535_STATUS1_DATA_ERROR             (0x2)
-#define SONY535_STATUS1_SEEK_ERROR             (0x4)
-#define SONY535_STATUS1_DISC_TYPE_ERROR                (0x8)
-#define SONY535_STATUS1_NOT_SPINNING           (0x10)
-#define SONY535_STATUS1_EJECT_BUTTON_PRESSED   (0x20)
-#define SONY535_STATUS1_CADDY_NOT_INSERTED     (0x40)
-#define SONY535_STATUS1_BYTE_TWO_FOLLOWS       (0x80)
-
-/*
- * drive status 2
- */
-#define SONY535_CDD_LOADING_ERROR              (0x7)
-#define SONY535_CDD_NO_DISC                    (0x8)
-#define SONY535_CDD_UNLOADING_ERROR            (0x9)
-#define SONY535_CDD_CADDY_NOT_INSERTED         (0xd)
-#define SONY535_ATN_RESET_OCCURRED             (0x2)
-#define SONY535_ATN_DISC_CHANGED               (0x4)
-#define SONY535_ATN_RESET_AND_DISC_CHANGED     (0x6)
-#define SONY535_ATN_EJECT_IN_PROGRESS          (0xe)
-#define SONY535_ATN_BUSY                       (0xf)
-
-/*
- * define some parameters
- */
-#define SONY535_AUDIO_DRIVE_MODE               (0)
-#define SONY535_CDROM_DRIVE_MODE               (0xe0)
-
-#define SONY535_PLAY_OP_PLAYBACK               (0)
-#define SONY535_PLAY_OP_ENTER_HOLD             (1)
-#define SONY535_PLAY_OP_SET_AUDIO_ENDING_ADDR  (2)
-#define SONY535_PLAY_OP_SCAN_FORWARD           (3)
-#define SONY535_PLAY_OP_SCAN_BACKWARD          (4)
-
-/*
- *  convert from msf format to block number 
- */
-#define SONY_BLOCK_NUMBER(m,s,f) (((m)*60L+(s))*75L+(f))
-#define SONY_BLOCK_NUMBER_MSF(x) (((x)[0]*60L+(x)[1])*75L+(x)[2])
-
-/*
- *  error return values from the doSonyCmd() routines
- */
-#define TIME_OUT                       (-1)
-#define NO_CDROM                       (-2)
-#define BAD_STATUS                     (-3)
-#define CD_BUSY                                (-4)
-#define NOT_DATA_CD                    (-5)
-#define NO_ROOM                                (-6)
-
-#define LOG_START_OFFSET        150     /* Offset of first logical sector */
-
-#define SONY_JIFFIES_TIMEOUT   (5*HZ)  /* Maximum time
-                                          the drive will wait/try for an
-                                          operation */
-#define SONY_READY_RETRIES      (50000)  /* How many times to retry a
-                                                  spin waiting for a register
-                                                  to come ready */
-#define SONY535_FAST_POLLS     (10000)   /* how many times recheck 
-                                                  status waiting for a data
-                                                  to become ready */
-
-typedef unsigned char Byte;
-
-/*
- * This is the complete status returned from the drive configuration request
- * command.
- */
-struct s535_sony_drive_config
-{
-   char vendor_id[8];
-   char product_id[16];
-   char product_rev_level[4];
-};
-
-/* The following is returned from the request sub-q data command */
-struct s535_sony_subcode
-{
-   unsigned char address        :4;
-   unsigned char control        :4;
-   unsigned char track_num;
-   unsigned char index_num;
-   unsigned char rel_msf[3];
-   unsigned char abs_msf[3];
-};
-
-struct s535_sony_disc_capacity
-{
-   Byte mFirstTrack, sFirstTrack, fFirstTrack;
-   Byte mLeadOut, sLeadOut, fLeadOut;
-};
-
-/*
- * The following is returned from the request TOC (Table Of Contents) command.
- * (last_track_num-first_track_num+1) values are valid in tracks.
- */
-struct s535_sony_toc
-{
-   unsigned char reserved0      :4;
-   unsigned char control0       :4;
-   unsigned char point0;
-   unsigned char first_track_num;
-   unsigned char reserved0a;
-   unsigned char reserved0b;
-   unsigned char reserved1      :4;
-   unsigned char control1       :4;
-   unsigned char point1;
-   unsigned char last_track_num;
-   unsigned char dummy1;
-   unsigned char dummy2;
-   unsigned char reserved2      :4;
-   unsigned char control2       :4;
-   unsigned char point2;
-   unsigned char lead_out_start_msf[3];
-   struct
-   {
-      unsigned char reserved    :4;
-      unsigned char control     :4;
-      unsigned char track;
-      unsigned char track_start_msf[3];
-   } tracks[100];
-
-   unsigned int lead_out_start_lba;
-};
-
-#endif /* SONYCD535_H */
index 1b094509b1d2fdb5acaebb980a7e157c3b592b2e..90965b4def5cda2e90f6d5def2f3e879bee14035 100644 (file)
@@ -1005,8 +1005,8 @@ static const unsigned short x86_keycodes[256] =
        284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
        367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
        360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
-       103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361,
-       291,108,381,281,290,272,292,305,280, 99,112,257,258,359,113,114,
+       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
+       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
        264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
        377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
        308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
index cc9a9d0df979f5dcf69b4e70d4f7945aae68a490..d2e4cfd79f27daf0001dcff37164bba0a901404c 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/crash_dump.h>
 #include <linux/backing-dev.h>
 #include <linux/bootmem.h>
-#include <linux/pipe_fs_i.h>
+#include <linux/splice.h>
 #include <linux/pfn.h>
 
 #include <asm/uaccess.h>
index 9eb1edacd825d3d4c4e5d345bfb9c869bef98aaa..0aeab3218bb6d6b8c503b2f2386133e611f4a5f7 100644 (file)
@@ -336,8 +336,11 @@ fw_card_bm_work(struct work_struct *work)
        }
 
  pick_me:
-       /* Now figure out what gap count to set. */
-       if (card->topology_type == FW_TOPOLOGY_A &&
+       /*
+        * Pick a gap count from 1394a table E-1.  The table doesn't cover
+        * the typically much larger 1394b beta repeater delays though.
+        */
+       if (!card->beta_repeaters_present &&
            card->root_node->max_hops < ARRAY_SIZE(gap_count_table))
                gap_count = gap_count_table[card->root_node->max_hops];
        else
index dbb76427d52947d64e14f6c11855dac5be698650..75388641a7d34619f1a1ec1c11aa856e5d13fe6f 100644 (file)
@@ -397,7 +397,7 @@ static int ioctl_send_request(struct client *client, void *buffer)
                        request->tcode & 0x1f,
                        device->node->node_id,
                        request->generation,
-                       device->node->max_speed,
+                       device->max_speed,
                        request->offset,
                        response->response.data, request->length,
                        complete_transaction, response);
index c1ce465d97103b3855393cd79bdfd778d531d41b..2b6586341635b9ed57dafc5f6ebb977924177010 100644 (file)
@@ -401,8 +401,7 @@ static int read_rom(struct fw_device *device, int index, u32 * data)
 
        offset = 0xfffff0000400ULL + index * 4;
        fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST,
-                       device->node_id,
-                       device->generation, SCODE_100,
+                       device->node_id, device->generation, device->max_speed,
                        offset, NULL, 4, complete_transaction, &callback_data);
 
        wait_for_completion(&callback_data.done);
@@ -418,6 +417,8 @@ static int read_bus_info_block(struct fw_device *device)
        u32 stack[16], sp, key;
        int i, end, length;
 
+       device->max_speed = SCODE_100;
+
        /* First read the bus info block. */
        for (i = 0; i < 5; i++) {
                if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
@@ -434,6 +435,33 @@ static int read_bus_info_block(struct fw_device *device)
                        return -1;
        }
 
+       device->max_speed = device->node->max_speed;
+
+       /*
+        * Determine the speed of
+        *   - devices with link speed less than PHY speed,
+        *   - devices with 1394b PHY (unless only connected to 1394a PHYs),
+        *   - all devices if there are 1394b repeaters.
+        * Note, we cannot use the bus info block's link_spd as starting point
+        * because some buggy firmwares set it lower than necessary and because
+        * 1394-1995 nodes do not have the field.
+        */
+       if ((rom[2] & 0x7) < device->max_speed ||
+           device->max_speed == SCODE_BETA ||
+           device->card->beta_repeaters_present) {
+               u32 dummy;
+
+               /* for S1600 and S3200 */
+               if (device->max_speed == SCODE_BETA)
+                       device->max_speed = device->card->link_speed;
+
+               while (device->max_speed > SCODE_100) {
+                       if (read_rom(device, 0, &dummy) == RCODE_COMPLETE)
+                               break;
+                       device->max_speed--;
+               }
+       }
+
        /*
         * Now parse the config rom.  The config rom is a recursive
         * directory structure so we parse it using a stack of
@@ -680,8 +708,10 @@ static void fw_device_init(struct work_struct *work)
                    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
                fw_device_shutdown(&device->work.work);
        else
-               fw_notify("created new fw device %s (%d config rom retries)\n",
-                         device->device.bus_id, device->config_rom_retries);
+               fw_notify("created new fw device %s "
+                         "(%d config rom retries, S%d00)\n",
+                         device->device.bus_id, device->config_rom_retries,
+                         1 << device->max_speed);
 
        /*
         * Reschedule the IRM work if we just finished reading the
index af1723eae4ba6d7868d521fd340de08fdd993a9b..d13e6a69707ffe6265a32fbd92efbfb0b31497d1 100644 (file)
@@ -40,6 +40,7 @@ struct fw_device {
        struct fw_node *node;
        int node_id;
        int generation;
+       unsigned max_speed;
        struct fw_card *card;
        struct device device;
        struct list_head link;
index 96c8ac5b86ccceaeed1ce0355b1f8c0c3cd1dda0..41476abc069310ce0989f546de49130d566ea736 100644 (file)
@@ -1934,12 +1934,12 @@ static int pci_suspend(struct pci_dev *pdev, pm_message_t state)
        free_irq(pdev->irq, ohci);
        err = pci_save_state(pdev);
        if (err) {
-               fw_error("pci_save_state failed with %d", err);
+               fw_error("pci_save_state failed\n");
                return err;
        }
        err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
        if (err) {
-               fw_error("pci_set_power_state failed with %d", err);
+               fw_error("pci_set_power_state failed\n");
                return err;
        }
 
@@ -1955,7 +1955,7 @@ static int pci_resume(struct pci_dev *pdev)
        pci_restore_state(pdev);
        err = pci_enable_device(pdev);
        if (err) {
-               fw_error("pci_enable_device failed with %d", err);
+               fw_error("pci_enable_device failed\n");
                return err;
        }
 
index a98d3915e26f33f926d8e0c383842cb5330018db..7c53be0387fbb675b8c26453982d14a6ddf9da0d 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/mod_devicetable.h>
 #include <linux/device.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
+#include <linux/blkdev.h>
+#include <linux/string.h>
 #include <linux/timer.h>
 
 #include <scsi/scsi.h>
 #include "fw-topology.h"
 #include "fw-device.h"
 
+/*
+ * So far only bridges from Oxford Semiconductor are known to support
+ * concurrent logins. Depending on firmware, four or two concurrent logins
+ * are possible on OXFW911 and newer Oxsemi bridges.
+ *
+ * Concurrent logins are useful together with cluster filesystems.
+ */
+static int sbp2_param_exclusive_login = 1;
+module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644);
+MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
+                "(default = Y, use N for concurrent initiators)");
+
 /* I don't know why the SCSI stack doesn't define something like this... */
 typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
 
@@ -154,7 +169,7 @@ struct sbp2_orb {
 #define MANAGEMENT_ORB_LUN(v)                  ((v))
 #define MANAGEMENT_ORB_FUNCTION(v)             ((v) << 16)
 #define MANAGEMENT_ORB_RECONNECT(v)            ((v) << 20)
-#define MANAGEMENT_ORB_EXCLUSIVE               ((1) << 28)
+#define MANAGEMENT_ORB_EXCLUSIVE(v)            ((v) ? 1 << 28 : 0)
 #define MANAGEMENT_ORB_REQUEST_FORMAT(v)       ((v) << 29)
 #define MANAGEMENT_ORB_NOTIFY                  ((1) << 31)
 
@@ -205,9 +220,8 @@ struct sbp2_command_orb {
        scsi_done_fn_t done;
        struct fw_unit *unit;
 
-       struct sbp2_pointer page_table[SG_ALL];
+       struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8)));
        dma_addr_t page_table_bus;
-       dma_addr_t request_buffer_bus;
 };
 
 /*
@@ -347,8 +361,7 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
        spin_unlock_irqrestore(&device->card->lock, flags);
 
        fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
-                       node_id, generation,
-                       device->node->max_speed, offset,
+                       node_id, generation, device->max_speed, offset,
                        &orb->pointer, sizeof(orb->pointer),
                        complete_transaction, orb);
 }
@@ -383,7 +396,7 @@ static void
 complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
 {
        struct sbp2_management_orb *orb =
-           (struct sbp2_management_orb *)base_orb;
+               container_of(base_orb, struct sbp2_management_orb, base);
 
        if (status)
                memcpy(&orb->status, status, sizeof(*status));
@@ -403,21 +416,11 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
        if (orb == NULL)
                return -ENOMEM;
 
-       /*
-        * The sbp2 device is going to send a block read request to
-        * read out the request from host memory, so map it for dma.
-        */
-       orb->base.request_bus =
-               dma_map_single(device->card->device, &orb->request,
-                              sizeof(orb->request), DMA_TO_DEVICE);
-       if (dma_mapping_error(orb->base.request_bus))
-               goto out;
-
        orb->response_bus =
                dma_map_single(device->card->device, &orb->response,
                               sizeof(orb->response), DMA_FROM_DEVICE);
        if (dma_mapping_error(orb->response_bus))
-               goto out;
+               goto fail_mapping_response;
 
        orb->request.response.high    = 0;
        orb->request.response.low     = orb->response_bus;
@@ -432,14 +435,9 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
        orb->request.status_fifo.high = sd->address_handler.offset >> 32;
        orb->request.status_fifo.low  = sd->address_handler.offset;
 
-       /*
-        * FIXME: Yeah, ok this isn't elegant, we hardwire exclusive
-        * login and 1 second reconnect time.  The reconnect setting
-        * is probably fine, but the exclusive login should be an option.
-        */
        if (function == SBP2_LOGIN_REQUEST) {
                orb->request.misc |=
-                       MANAGEMENT_ORB_EXCLUSIVE |
+                       MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login) |
                        MANAGEMENT_ORB_RECONNECT(0);
        }
 
@@ -448,6 +446,12 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
        init_completion(&orb->done);
        orb->base.callback = complete_management_orb;
 
+       orb->base.request_bus =
+               dma_map_single(device->card->device, &orb->request,
+                              sizeof(orb->request), DMA_TO_DEVICE);
+       if (dma_mapping_error(orb->base.request_bus))
+               goto fail_mapping_request;
+
        sbp2_send_orb(&orb->base, unit,
                      node_id, generation, sd->management_agent_address);
 
@@ -479,9 +483,10 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
  out:
        dma_unmap_single(device->card->device, orb->base.request_bus,
                         sizeof(orb->request), DMA_TO_DEVICE);
+ fail_mapping_request:
        dma_unmap_single(device->card->device, orb->response_bus,
                         sizeof(orb->response), DMA_FROM_DEVICE);
-
+ fail_mapping_response:
        if (response)
                fw_memcpy_from_be32(response,
                                    orb->response, sizeof(orb->response));
@@ -511,7 +516,7 @@ static int sbp2_agent_reset(struct fw_unit *unit)
                return -ENOMEM;
 
        fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
-                       sd->node_id, sd->generation, SCODE_400,
+                       sd->node_id, sd->generation, device->max_speed,
                        sd->command_block_agent_address + SBP2_AGENT_RESET,
                        &zero, sizeof(zero), complete_agent_reset_write, t);
 
@@ -521,17 +526,15 @@ static int sbp2_agent_reset(struct fw_unit *unit)
 static void sbp2_reconnect(struct work_struct *work);
 static struct scsi_host_template scsi_driver_template;
 
-static void
-release_sbp2_device(struct kref *kref)
+static void release_sbp2_device(struct kref *kref)
 {
        struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
        struct Scsi_Host *host =
                container_of((void *)sd, struct Scsi_Host, hostdata[0]);
 
+       scsi_remove_host(host);
        sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
                                 SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
-
-       scsi_remove_host(host);
        fw_core_remove_address_handler(&sd->address_handler);
        fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
        put_device(&sd->unit->device);
@@ -833,7 +836,8 @@ sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
 static void
 complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
 {
-       struct sbp2_command_orb *orb = (struct sbp2_command_orb *)base_orb;
+       struct sbp2_command_orb *orb =
+               container_of(base_orb, struct sbp2_command_orb, base);
        struct fw_unit *unit = orb->unit;
        struct fw_device *device = fw_device(unit->device.parent);
        struct scatterlist *sg;
@@ -880,12 +884,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
 
        if (orb->page_table_bus != 0)
                dma_unmap_single(device->card->device, orb->page_table_bus,
-                                sizeof(orb->page_table_bus), DMA_TO_DEVICE);
-
-       if (orb->request_buffer_bus != 0)
-               dma_unmap_single(device->card->device, orb->request_buffer_bus,
-                                sizeof(orb->request_buffer_bus),
-                                DMA_FROM_DEVICE);
+                                sizeof(orb->page_table), DMA_TO_DEVICE);
 
        orb->cmd->result = result;
        orb->done(orb->cmd);
@@ -900,7 +899,6 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
        struct fw_device *device = fw_device(unit->device.parent);
        struct scatterlist *sg;
        int sg_len, l, i, j, count;
-       size_t size;
        dma_addr_t sg_addr;
 
        sg = (struct scatterlist *)orb->cmd->request_buffer;
@@ -935,6 +933,11 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
                sg_len = sg_dma_len(sg + i);
                sg_addr = sg_dma_address(sg + i);
                while (sg_len) {
+                       /* FIXME: This won't get us out of the pinch. */
+                       if (unlikely(j >= ARRAY_SIZE(orb->page_table))) {
+                               fw_error("page table overflow\n");
+                               goto fail_page_table;
+                       }
                        l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH);
                        orb->page_table[j].low = sg_addr;
                        orb->page_table[j].high = (l << 16);
@@ -944,7 +947,13 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
                }
        }
 
-       size = sizeof(orb->page_table[0]) * j;
+       fw_memcpy_to_be32(orb->page_table, orb->page_table,
+                         sizeof(orb->page_table[0]) * j);
+       orb->page_table_bus =
+               dma_map_single(device->card->device, orb->page_table,
+                              sizeof(orb->page_table), DMA_TO_DEVICE);
+       if (dma_mapping_error(orb->page_table_bus))
+               goto fail_page_table;
 
        /*
         * The data_descriptor pointer is the one case where we need
@@ -953,20 +962,12 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
         * initiator (i.e. us), but data_descriptor can refer to data
         * on other nodes so we need to put our ID in descriptor.high.
         */
-
-       orb->page_table_bus =
-               dma_map_single(device->card->device, orb->page_table,
-                              size, DMA_TO_DEVICE);
-       if (dma_mapping_error(orb->page_table_bus))
-               goto fail_page_table;
        orb->request.data_descriptor.high = sd->address_high;
        orb->request.data_descriptor.low  = orb->page_table_bus;
        orb->request.misc |=
                COMMAND_ORB_PAGE_TABLE_PRESENT |
                COMMAND_ORB_DATA_SIZE(j);
 
-       fw_memcpy_to_be32(orb->page_table, orb->page_table, size);
-
        return 0;
 
  fail_page_table:
@@ -991,7 +992,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
         * transfer direction not handled.
         */
        if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) {
-               fw_error("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
+               fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n");
                cmd->result = DID_ERROR << 16;
                done(cmd);
                return 0;
@@ -1005,11 +1006,6 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
 
        /* Initialize rcode to something not RCODE_COMPLETE. */
        orb->base.rcode = -1;
-       orb->base.request_bus =
-               dma_map_single(device->card->device, &orb->request,
-                              sizeof(orb->request), DMA_TO_DEVICE);
-       if (dma_mapping_error(orb->base.request_bus))
-               goto fail_mapping;
 
        orb->unit = unit;
        orb->done = done;
@@ -1024,8 +1020,8 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
         * if we set this to max_speed + 7, we get the right value.
         */
        orb->request.misc =
-               COMMAND_ORB_MAX_PAYLOAD(device->node->max_speed + 7) |
-               COMMAND_ORB_SPEED(device->node->max_speed) |
+               COMMAND_ORB_MAX_PAYLOAD(device->max_speed + 7) |
+               COMMAND_ORB_SPEED(device->max_speed) |
                COMMAND_ORB_NOTIFY;
 
        if (cmd->sc_data_direction == DMA_FROM_DEVICE)
@@ -1036,7 +1032,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
                        COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
 
        if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
-               goto fail_map_payload;
+               goto fail_mapping;
 
        fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
 
@@ -1045,15 +1041,17 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
        memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
 
        orb->base.callback = complete_command_orb;
+       orb->base.request_bus =
+               dma_map_single(device->card->device, &orb->request,
+                              sizeof(orb->request), DMA_TO_DEVICE);
+       if (dma_mapping_error(orb->base.request_bus))
+               goto fail_mapping;
 
        sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
                      sd->command_block_agent_address + SBP2_ORB_POINTER);
 
        return 0;
 
- fail_map_payload:
-       dma_unmap_single(device->card->device, orb->base.request_bus,
-                        sizeof(orb->request), DMA_TO_DEVICE);
  fail_mapping:
        kfree(orb);
  fail_alloc:
@@ -1087,7 +1085,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
                fw_notify("setting fix_capacity for %s\n", unit->device.bus_id);
                sdev->fix_capacity = 1;
        }
-
+       if (sd->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
+               blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
        return 0;
 }
 
index 7aebb8ae0efa0a1723ee473b653df4db977a7eaa..39e5cd12aa526176a70013f958ca6506de9a487c 100644 (file)
@@ -135,17 +135,17 @@ static void update_hop_count(struct fw_node *node)
        int i;
 
        for (i = 0; i < node->port_count; i++) {
-               if (node->ports[i].node == NULL)
+               if (node->ports[i] == NULL)
                        continue;
 
-               if (node->ports[i].node->max_hops > max_child_hops)
-                       max_child_hops = node->ports[i].node->max_hops;
+               if (node->ports[i]->max_hops > max_child_hops)
+                       max_child_hops = node->ports[i]->max_hops;
 
-               if (node->ports[i].node->max_depth > depths[0]) {
+               if (node->ports[i]->max_depth > depths[0]) {
                        depths[1] = depths[0];
-                       depths[0] = node->ports[i].node->max_depth;
-               } else if (node->ports[i].node->max_depth > depths[1])
-                       depths[1] = node->ports[i].node->max_depth;
+                       depths[0] = node->ports[i]->max_depth;
+               } else if (node->ports[i]->max_depth > depths[1])
+                       depths[1] = node->ports[i]->max_depth;
        }
 
        node->max_depth = depths[0] + 1;
@@ -172,7 +172,8 @@ static struct fw_node *build_tree(struct fw_card *card,
        struct list_head stack, *h;
        u32 *next_sid, *end, q;
        int i, port_count, child_port_count, phy_id, parent_count, stack_depth;
-       int gap_count, topology_type;
+       int gap_count;
+       bool beta_repeaters_present;
 
        local_node = NULL;
        node = NULL;
@@ -182,7 +183,7 @@ static struct fw_node *build_tree(struct fw_card *card,
        phy_id = 0;
        irm_node = NULL;
        gap_count = SELF_ID_GAP_COUNT(*sid);
-       topology_type = 0;
+       beta_repeaters_present = false;
 
        while (sid < end) {
                next_sid = count_ports(sid, &port_count, &child_port_count);
@@ -214,7 +215,7 @@ static struct fw_node *build_tree(struct fw_card *card,
 
                node = fw_node_create(q, port_count, card->color);
                if (node == NULL) {
-                       fw_error("Out of memory while building topology.");
+                       fw_error("Out of memory while building topology.\n");
                        return NULL;
                }
 
@@ -224,11 +225,6 @@ static struct fw_node *build_tree(struct fw_card *card,
                if (SELF_ID_CONTENDER(q))
                        irm_node = node;
 
-               if (node->phy_speed == SCODE_BETA)
-                       topology_type |= FW_TOPOLOGY_B;
-               else
-                       topology_type |= FW_TOPOLOGY_A;
-
                parent_count = 0;
 
                for (i = 0; i < port_count; i++) {
@@ -249,12 +245,12 @@ static struct fw_node *build_tree(struct fw_card *card,
                                break;
 
                        case SELFID_PORT_CHILD:
-                               node->ports[i].node = child;
+                               node->ports[i] = child;
                                /*
                                 * Fix up parent reference for this
                                 * child node.
                                 */
-                               child->ports[child->color].node = node;
+                               child->ports[child->color] = node;
                                child->color = card->color;
                                child = fw_node(child->link.next);
                                break;
@@ -278,6 +274,10 @@ static struct fw_node *build_tree(struct fw_card *card,
                list_add_tail(&node->link, &stack);
                stack_depth += 1 - child_port_count;
 
+               if (node->phy_speed == SCODE_BETA &&
+                   parent_count + child_port_count > 1)
+                       beta_repeaters_present = true;
+
                /*
                 * If all PHYs does not report the same gap count
                 * setting, we fall back to 63 which will force a gap
@@ -295,7 +295,7 @@ static struct fw_node *build_tree(struct fw_card *card,
        card->root_node = node;
        card->irm_node = irm_node;
        card->gap_count = gap_count;
-       card->topology_type = topology_type;
+       card->beta_repeaters_present = beta_repeaters_present;
 
        return local_node;
 }
@@ -321,7 +321,7 @@ for_each_fw_node(struct fw_card *card, struct fw_node *root,
                node->color = card->color;
 
                for (i = 0; i < node->port_count; i++) {
-                       child = node->ports[i].node;
+                       child = node->ports[i];
                        if (!child)
                                continue;
                        if (child->color == card->color)
@@ -382,11 +382,11 @@ static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
        struct fw_node *tree;
        int i;
 
-       tree = node1->ports[port].node;
-       node0->ports[port].node = tree;
+       tree = node1->ports[port];
+       node0->ports[port] = tree;
        for (i = 0; i < tree->port_count; i++) {
-               if (tree->ports[i].node == node1) {
-                       tree->ports[i].node = node0;
+               if (tree->ports[i] == node1) {
+                       tree->ports[i] = node0;
                        break;
                }
        }
@@ -437,19 +437,17 @@ update_tree(struct fw_card *card, struct fw_node *root)
                        card->irm_node = node0;
 
                for (i = 0; i < node0->port_count; i++) {
-                       if (node0->ports[i].node && node1->ports[i].node) {
+                       if (node0->ports[i] && node1->ports[i]) {
                                /*
                                 * This port didn't change, queue the
                                 * connected node for further
                                 * investigation.
                                 */
-                               if (node0->ports[i].node->color == card->color)
+                               if (node0->ports[i]->color == card->color)
                                        continue;
-                               list_add_tail(&node0->ports[i].node->link,
-                                             &list0);
-                               list_add_tail(&node1->ports[i].node->link,
-                                             &list1);
-                       } else if (node0->ports[i].node) {
+                               list_add_tail(&node0->ports[i]->link, &list0);
+                               list_add_tail(&node1->ports[i]->link, &list1);
+                       } else if (node0->ports[i]) {
                                /*
                                 * The nodes connected here were
                                 * unplugged; unref the lost nodes and
@@ -457,10 +455,10 @@ update_tree(struct fw_card *card, struct fw_node *root)
                                 * them.
                                 */
 
-                               for_each_fw_node(card, node0->ports[i].node,
+                               for_each_fw_node(card, node0->ports[i],
                                                 report_lost_node);
-                               node0->ports[i].node = NULL;
-                       } else if (node1->ports[i].node) {
+                               node0->ports[i] = NULL;
+                       } else if (node1->ports[i]) {
                                /*
                                 * One or more node were connected to
                                 * this port. Move the new nodes into
@@ -468,7 +466,7 @@ update_tree(struct fw_card *card, struct fw_node *root)
                                 * callbacks for them.
                                 */
                                move_tree(node0, node1, i);
-                               for_each_fw_node(card, node0->ports[i].node,
+                               for_each_fw_node(card, node0->ports[i],
                                                 report_found_node);
                        }
                }
index 363b6cbcd0b335087fba9701cd22b7bc2ea04975..1b56b4ac7fb2c0298830544a31fc5d4b2909d2b7 100644 (file)
 #ifndef __fw_topology_h
 #define __fw_topology_h
 
-enum {
-       FW_TOPOLOGY_A =         0x01,
-       FW_TOPOLOGY_B =         0x02,
-       FW_TOPOLOGY_MIXED =     0x03,
-};
-
 enum {
        FW_NODE_CREATED =   0x00,
        FW_NODE_UPDATED =   0x01,
@@ -33,21 +27,16 @@ enum {
        FW_NODE_LINK_OFF =  0x04,
 };
 
-struct fw_port {
-       struct fw_node *node;
-       unsigned speed : 3; /* S100, S200, ... S3200 */
-};
-
 struct fw_node {
        u16 node_id;
        u8 color;
        u8 port_count;
-       unsigned link_on : 1;
-       unsigned initiated_reset : 1;
-       unsigned b_path : 1;
-       u8 phy_speed : 3; /* As in the self ID packet. */
-       u8 max_speed : 5; /* Minimum of all phy-speeds and port speeds on
-                          * the path from the local node to this node. */
+       u8 link_on : 1;
+       u8 initiated_reset : 1;
+       u8 b_path : 1;
+       u8 phy_speed : 2; /* As in the self ID packet. */
+       u8 max_speed : 2; /* Minimum of all phy-speeds on the path from the
+                          * local node to this node. */
        u8 max_depth : 4; /* Maximum depth to any leaf node */
        u8 max_hops : 4;  /* Max hops in this sub tree */
        atomic_t ref_count;
@@ -58,7 +47,7 @@ struct fw_node {
        /* Upper layer specific data. */
        void *data;
 
-       struct fw_port ports[0];
+       struct fw_node *ports[0];
 };
 
 static inline struct fw_node *
index acdc3be38c613af6ba6a6a4a0eae5921ac1cca3a..5abed193f4a65deb8c6ab3f27355a03a9d3092e8 100644 (file)
@@ -81,7 +81,6 @@
 
 #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
 #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-#define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args)
 
 static inline void
 fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
@@ -246,7 +245,7 @@ struct fw_card {
        struct fw_node *irm_node;
        int color;
        int gap_count;
-       int topology_type;
+       bool beta_repeaters_present;
 
        int index;
 
index 8fbe9fdac128ea232099499729f80693b3aa0acf..3b63b0b7812206e643fb0cc73b1070bc65e84cca 100644 (file)
@@ -1,8 +1,12 @@
 #
 # HID driver configuration
 #
-menu "HID Devices"
+menuconfig HID_SUPPORT
+       bool "HID Devices"
        depends on INPUT
+       default y
+
+if HID_SUPPORT
 
 config HID
        tristate "Generic HID support"
@@ -24,6 +28,7 @@ config HID
 
 config HID_DEBUG
        bool "HID debugging support"
+       default y if !EMBEDDED
        depends on HID
        ---help---
        This option lets the HID layer output diagnostics about its internal
@@ -38,5 +43,4 @@ config HID_DEBUG
 
 source "drivers/hid/usbhid/Kconfig"
 
-endmenu
-
+endif # HID_SUPPORT
index 6ec04e79f6856c0340f20a31f0b08bb9b6afeeb6..317cf8a7b63c11ed03e76772c8c8710a3ec5505c 100644 (file)
 #define DRIVER_DESC "HID core driver"
 #define DRIVER_LICENSE "GPL"
 
+#ifdef CONFIG_HID_DEBUG
+int hid_debug = 0;
+module_param_named(debug, hid_debug, bool, 0600);
+MODULE_PARM_DESC(debug, "Turn HID debugging mode on and off");
+EXPORT_SYMBOL_GPL(hid_debug);
+#endif
+
 /*
  * Register a new report for a device.
  */
@@ -78,7 +85,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
        struct hid_field *field;
 
        if (report->maxfield == HID_MAX_FIELDS) {
-               dbg("too many fields in report");
+               dbg_hid("too many fields in report\n");
                return NULL;
        }
 
@@ -106,7 +113,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
        usage = parser->local.usage[0];
 
        if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
-               dbg("collection stack overflow");
+               dbg_hid("collection stack overflow\n");
                return -1;
        }
 
@@ -114,7 +121,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
                collection = kmalloc(sizeof(struct hid_collection) *
                                parser->device->collection_size * 2, GFP_KERNEL);
                if (collection == NULL) {
-                       dbg("failed to reallocate collection array");
+                       dbg_hid("failed to reallocate collection array\n");
                        return -1;
                }
                memcpy(collection, parser->device->collection,
@@ -150,7 +157,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
 static int close_collection(struct hid_parser *parser)
 {
        if (!parser->collection_stack_ptr) {
-               dbg("collection stack underflow");
+               dbg_hid("collection stack underflow\n");
                return -1;
        }
        parser->collection_stack_ptr--;
@@ -178,7 +185,7 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
 static int hid_add_usage(struct hid_parser *parser, unsigned usage)
 {
        if (parser->local.usage_index >= HID_MAX_USAGES) {
-               dbg("usage index exceeded");
+               dbg_hid("usage index exceeded\n");
                return -1;
        }
        parser->local.usage[parser->local.usage_index] = usage;
@@ -202,12 +209,12 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
        int i;
 
        if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
-               dbg("hid_register_report failed");
+               dbg_hid("hid_register_report failed\n");
                return -1;
        }
 
        if (parser->global.logical_maximum < parser->global.logical_minimum) {
-               dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+               dbg_hid("logical range invalid %d %d\n", parser->global.logical_minimum, parser->global.logical_maximum);
                return -1;
        }
 
@@ -287,7 +294,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
                case HID_GLOBAL_ITEM_TAG_PUSH:
 
                        if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
-                               dbg("global enviroment stack overflow");
+                               dbg_hid("global enviroment stack overflow\n");
                                return -1;
                        }
 
@@ -298,7 +305,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
                case HID_GLOBAL_ITEM_TAG_POP:
 
                        if (!parser->global_stack_ptr) {
-                               dbg("global enviroment stack underflow");
+                               dbg_hid("global enviroment stack underflow\n");
                                return -1;
                        }
 
@@ -342,27 +349,27 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 
                case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
                        if ((parser->global.report_size = item_udata(item)) > 32) {
-                               dbg("invalid report_size %d", parser->global.report_size);
+                               dbg_hid("invalid report_size %d\n", parser->global.report_size);
                                return -1;
                        }
                        return 0;
 
                case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
                        if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-                               dbg("invalid report_count %d", parser->global.report_count);
+                               dbg_hid("invalid report_count %d\n", parser->global.report_count);
                                return -1;
                        }
                        return 0;
 
                case HID_GLOBAL_ITEM_TAG_REPORT_ID:
                        if ((parser->global.report_id = item_udata(item)) == 0) {
-                               dbg("report_id 0 is invalid");
+                               dbg_hid("report_id 0 is invalid\n");
                                return -1;
                        }
                        return 0;
 
                default:
-                       dbg("unknown global tag 0x%x", item->tag);
+                       dbg_hid("unknown global tag 0x%x\n", item->tag);
                        return -1;
        }
 }
@@ -377,7 +384,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
        unsigned n;
 
        if (item->size == 0) {
-               dbg("item data expected for local item");
+               dbg_hid("item data expected for local item\n");
                return -1;
        }
 
@@ -395,14 +402,14 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                                 * items and the first delimiter set.
                                 */
                                if (parser->local.delimiter_depth != 0) {
-                                       dbg("nested delimiters");
+                                       dbg_hid("nested delimiters\n");
                                        return -1;
                                }
                                parser->local.delimiter_depth++;
                                parser->local.delimiter_branch++;
                        } else {
                                if (parser->local.delimiter_depth < 1) {
-                                       dbg("bogus close delimiter");
+                                       dbg_hid("bogus close delimiter\n");
                                        return -1;
                                }
                                parser->local.delimiter_depth--;
@@ -412,7 +419,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                case HID_LOCAL_ITEM_TAG_USAGE:
 
                        if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
+                               dbg_hid("alternative usage ignored\n");
                                return 0;
                        }
 
@@ -424,7 +431,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
 
                        if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
+                               dbg_hid("alternative usage ignored\n");
                                return 0;
                        }
 
@@ -437,7 +444,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
 
                        if (parser->local.delimiter_branch > 1) {
-                               dbg("alternative usage ignored");
+                               dbg_hid("alternative usage ignored\n");
                                return 0;
                        }
 
@@ -446,14 +453,14 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
 
                        for (n = parser->local.usage_minimum; n <= data; n++)
                                if (hid_add_usage(parser, n)) {
-                                       dbg("hid_add_usage failed\n");
+                                       dbg_hid("hid_add_usage failed\n");
                                        return -1;
                                }
                        return 0;
 
                default:
 
-                       dbg("unknown local item tag 0x%x", item->tag);
+                       dbg_hid("unknown local item tag 0x%x\n", item->tag);
                        return 0;
        }
        return 0;
@@ -487,7 +494,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
                        ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
                        break;
                default:
-                       dbg("unknown main item tag 0x%x", item->tag);
+                       dbg_hid("unknown main item tag 0x%x\n", item->tag);
                        ret = 0;
        }
 
@@ -502,7 +509,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
 
 static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
 {
-       dbg("reserved item type, tag 0x%x", item->tag);
+       dbg_hid("reserved item type, tag 0x%x\n", item->tag);
        return 0;
 }
 
@@ -667,14 +674,14 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
        while ((start = fetch_item(start, end, &item)) != NULL) {
 
                if (item.format != HID_ITEM_FORMAT_SHORT) {
-                       dbg("unexpected long global item");
+                       dbg_hid("unexpected long global item\n");
                        hid_free_device(device);
                        vfree(parser);
                        return NULL;
                }
 
                if (dispatch_type[item.type](parser, &item)) {
-                       dbg("item %u %u %u %u parsing failed\n",
+                       dbg_hid("item %u %u %u %u parsing failed\n",
                                item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
                        hid_free_device(device);
                        vfree(parser);
@@ -683,13 +690,13 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 
                if (start == end) {
                        if (parser->collection_stack_ptr) {
-                               dbg("unbalanced collection at end of report description");
+                               dbg_hid("unbalanced collection at end of report description\n");
                                hid_free_device(device);
                                vfree(parser);
                                return NULL;
                        }
                        if (parser->local.delimiter_depth) {
-                               dbg("unbalanced delimiter at end of report description");
+                               dbg_hid("unbalanced delimiter at end of report description\n");
                                hid_free_device(device);
                                vfree(parser);
                                return NULL;
@@ -699,7 +706,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
                }
        }
 
-       dbg("item fetching failed at offset %d\n", (int)(end - start));
+       dbg_hid("item fetching failed at offset %d\n", (int)(end - start));
        hid_free_device(device);
        vfree(parser);
        return NULL;
@@ -915,13 +922,13 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
        hid_dump_input(field->usage + offset, value);
 
        if (offset >= field->report_count) {
-               dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
+               dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count);
                hid_dump_field(field, 8);
                return -1;
        }
        if (field->logical_minimum < 0) {
                if (value != snto32(s32ton(value, size), size)) {
-                       dbg("value %d is out of range", value);
+                       dbg_hid("value %d is out of range\n", value);
                        return -1;
                }
        }
@@ -934,19 +941,17 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 {
        struct hid_report_enum *report_enum = hid->report_enum + type;
        struct hid_report *report;
-       int n, rsize;
+       int n, rsize, i;
 
        if (!hid)
                return -ENODEV;
 
        if (!size) {
-               dbg("empty report");
+               dbg_hid("empty report\n");
                return -1;
        }
 
-#ifdef CONFIG_HID_DEBUG
-       printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
-#endif
+       dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
 
        n = 0;                          /* Normally report number is 0 */
        if (report_enum->numbered) {    /* Device uses numbered reports, data[0] is report number */
@@ -954,25 +959,21 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
                size--;
        }
 
-#ifdef CONFIG_HID_DEBUG
-       {
-               int i;
-               printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
-               for (i = 0; i < size; i++)
-                       printk(" %02x", data[i]);
-               printk("\n");
-       }
-#endif
+       /* dump the report descriptor */
+       dbg_hid("report %d (size %u) = ", n, size);
+       for (i = 0; i < size; i++)
+               dbg_hid_line(" %02x", data[i]);
+       dbg_hid_line("\n");
 
        if (!(report = report_enum->report_id_hash[n])) {
-               dbg("undefined report_id %d received", n);
+               dbg_hid("undefined report_id %d received\n", n);
                return -1;
        }
 
        rsize = ((report->size - 1) >> 3) + 1;
 
        if (size < rsize) {
-               dbg("report %d is too short, (%d < %d)", report->id, size, rsize);
+               dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize);
                memset(data + size, 0, rsize - size);
        }
 
index 83c4126b37c333f59b575a40dce9f6fd1d2b675b..a13757b7898028986f98739eecfb3649be96bdfd 100644 (file)
@@ -347,6 +347,9 @@ static void resolv_usage_page(unsigned page) {
 void hid_resolv_usage(unsigned usage) {
        const struct hid_usage_entry *p;
 
+       if (!hid_debug)
+               return;
+
        resolv_usage_page(usage >> 16);
        printk(".");
        for (p = hid_usage_table; p->description; p++)
@@ -369,6 +372,9 @@ __inline__ static void tab(int n) {
 void hid_dump_field(struct hid_field *field, int n) {
        int j;
 
+       if (!hid_debug)
+               return;
+
        if (field->physical) {
                tab(n);
                printk("Physical(");
@@ -466,6 +472,9 @@ void hid_dump_device(struct hid_device *device) {
        unsigned i,k;
        static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
 
+       if (!hid_debug)
+               return;
+
        for (i = 0; i < HID_REPORT_TYPES; i++) {
                report_enum = device->report_enum + i;
                list = report_enum->report_list.next;
@@ -489,6 +498,9 @@ void hid_dump_device(struct hid_device *device) {
 EXPORT_SYMBOL_GPL(hid_dump_device);
 
 void hid_dump_input(struct hid_usage *usage, __s32 value) {
+       if (!hid_debug)
+               return;
+
        printk("hid-debug: input ");
        hid_resolv_usage(usage->hid);
        printk(" = %d\n", value);
@@ -758,6 +770,9 @@ static char **names[EV_MAX + 1] = {
 
 void hid_resolv_event(__u8 type, __u16 code) {
 
+       if (!hid_debug)
+               return;
+
        printk("%s.%s", events[type] ? events[type] : "?",
                names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
 }
index 7f817897b178063059be2cfde16e19caa8b6d3df..8edbd30cf7955bcb54e80d2ce42fe6f2f545b8e2 100644 (file)
@@ -60,6 +60,19 @@ static const unsigned char hid_keyboard[256] = {
        150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
 };
 
+/* extended mapping for certain Logitech hardware (Logitech cordless desktop LX500) */
+#define LOGITECH_EXPANDED_KEYMAP_SIZE 80
+static int logitech_expanded_keymap[LOGITECH_EXPANDED_KEYMAP_SIZE] = {
+         0,216,  0,213,175,156,  0,  0,  0,  0,
+       144,  0,  0,  0,  0,  0,  0,  0,  0,212,
+       174,167,152,161,112,  0,  0,  0,154,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,183,184,185,186,187,
+       188,189,190,191,192,193,194,  0,  0,  0
+};
+
 static const struct {
        __s32 x;
        __s32 y;
@@ -308,9 +321,7 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
                
                clear_bit(old_keycode, dev->keybit);
                set_bit(usage->code, dev->keybit);
-#ifdef CONFIG_HID_DEBUG
-               printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
-#endif
+               dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
                /* Set the keybit for the old keycode if the old keycode is used
                 * by another key */
                if (hidinput_find_key (hid, 0, old_keycode))
@@ -333,11 +344,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
        field->hidinput = hidinput;
 
-#ifdef CONFIG_HID_DEBUG
-       printk(KERN_DEBUG "Mapping: ");
+       dbg_hid("Mapping: ");
        hid_resolv_usage(usage->hid);
-       printk(" ---> ");
-#endif
+       dbg_hid_line(" ---> ");
 
        if (field->flags & HID_MAIN_ITEM_CONSTANT)
                goto ignore;
@@ -378,6 +387,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                        }
                        }
 
+                       /* Special handling for Logitech Cordless Desktop */
+                       if (field->application != HID_GD_MOUSE) {
+                               if (device->quirks & HID_QUIRK_LOGITECH_EXPANDED_KEYMAP) {
+                                       int hid = usage->hid & HID_USAGE;
+                                       if (hid < LOGITECH_EXPANDED_KEYMAP_SIZE && logitech_expanded_keymap[hid] != 0)
+                                               code = logitech_expanded_keymap[hid];
+                               }
+                       } else {
+                               if (device->quirks & HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL) {
+                                       int hid = usage->hid & HID_USAGE;
+                                       if (hid == 7 || hid == 8)
+                                               goto ignore;
+                               }
+                       }
+
                        map_key(code);
                        break;
 
@@ -566,6 +590,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x0e5: map_key_clear(KEY_BASSBOOST);       break;
                                case 0x0e9: map_key_clear(KEY_VOLUMEUP);        break;
                                case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);      break;
+
+                               /* reserved in HUT 1.12. Reported on Petalynx remote */
+                               case 0x0f6: map_key_clear(KEY_NEXT);            break;
+                               case 0x0fa: map_key_clear(KEY_BACK);            break;
+
                                case 0x183: map_key_clear(KEY_CONFIG);          break;
                                case 0x184: map_key_clear(KEY_WORDPROCESSOR);   break;
                                case 0x185: map_key_clear(KEY_EDITOR);          break;
@@ -598,7 +627,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x21b: map_key_clear(KEY_COPY);            break;
                                case 0x21c: map_key_clear(KEY_CUT);             break;
                                case 0x21d: map_key_clear(KEY_PASTE);           break;
-                               case 0x221: map_key_clear(KEY_FIND);            break;
+                               case 0x21f: map_key_clear(KEY_FIND);            break;
+                               case 0x221: map_key_clear(KEY_SEARCH);          break;
+                               case 0x222: map_key_clear(KEY_GOTO);            break;
                                case 0x223: map_key_clear(KEY_HOMEPAGE);        break;
                                case 0x224: map_key_clear(KEY_BACK);            break;
                                case 0x225: map_key_clear(KEY_FORWARD);         break;
@@ -688,7 +719,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        break;
 
                case HID_UP_MSVENDOR:
-                       goto ignore;
+
+                       /* special case - Chicony Chicony KU-0418 tactical pad */
+                       if (device->vendor == 0x04f2 && device->product == 0x0418) {
+                               set_bit(EV_REP, input->evbit);
+                               switch(usage->hid & HID_USAGE) {
+                                       case 0xff01: map_key_clear(BTN_1);              break;
+                                       case 0xff02: map_key_clear(BTN_2);              break;
+                                       case 0xff03: map_key_clear(BTN_3);              break;
+                                       case 0xff04: map_key_clear(BTN_4);              break;
+                                       case 0xff05: map_key_clear(BTN_5);              break;
+                                       case 0xff06: map_key_clear(BTN_6);              break;
+                                       case 0xff07: map_key_clear(BTN_7);              break;
+                                       case 0xff08: map_key_clear(BTN_8);              break;
+                                       case 0xff09: map_key_clear(BTN_9);              break;
+                                       case 0xff0a: map_key_clear(BTN_A);              break;
+                                       case 0xff0b: map_key_clear(BTN_B);              break;
+                                       default:    goto ignore;
+                               }
+                       } else {
+                               goto ignore;
+                       }
+                       break;
 
                case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
 
@@ -704,10 +756,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        }
                        break;
 
-               case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
-
+               case HID_UP_LOGIVENDOR:
                        set_bit(EV_REP, input->evbit);
                        switch(usage->hid & HID_USAGE) {
+                               /* Reported on Logitech Ultra X Media Remote */
                                case 0x004: map_key_clear(KEY_AGAIN);           break;
                                case 0x00d: map_key_clear(KEY_HOME);            break;
                                case 0x024: map_key_clear(KEY_SHUFFLE);         break;
@@ -725,6 +777,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x04d: map_key_clear(KEY_SUBTITLE);        break;
                                case 0x051: map_key_clear(KEY_RED);             break;
                                case 0x052: map_key_clear(KEY_CLOSE);           break;
+
+                               /* Reported on Petalynx Maxter remote */
+                               case 0x05a: map_key_clear(KEY_TEXT);            break;
+                               case 0x05b: map_key_clear(KEY_RED);             break;
+                               case 0x05c: map_key_clear(KEY_GREEN);           break;
+                               case 0x05d: map_key_clear(KEY_YELLOW);          break;
+                               case 0x05e: map_key_clear(KEY_BLUE);            break;
+
                                default:    goto ignore;
                        }
                        break;
@@ -818,16 +878,24 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        field->dpad = usage->code;
        }
 
+       /* for those devices which produce Consumer volume usage as relative,
+        * we emulate pressing volumeup/volumedown appropriate number of times
+        * in hidinput_hid_event()
+        */
+       if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
+                       (usage->code == ABS_VOLUME)) {
+               set_bit(KEY_VOLUMEUP, input->keybit);
+               set_bit(KEY_VOLUMEDOWN, input->keybit);
+       }
+
        hid_resolv_event(usage->type, usage->code);
-#ifdef CONFIG_HID_DEBUG
-       printk("\n");
-#endif
+
+       dbg_hid_line("\n");
+
        return;
 
 ignore:
-#ifdef CONFIG_HID_DEBUG
-       printk("IGNORED\n");
-#endif
+       dbg_hid_line("IGNORED\n");
        return;
 }
 
@@ -896,18 +964,33 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
        }
 
        if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
-               dbg("Maximum Effects - %d",value);
+               dbg_hid("Maximum Effects - %d\n",value);
                return;
        }
 
        if (usage->hid == (HID_UP_PID | 0x7fUL)) {
-               dbg("PID Pool Report\n");
+               dbg_hid("PID Pool Report\n");
                return;
        }
 
        if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
                return;
 
+       if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
+                       (usage->code == ABS_VOLUME)) {
+               int count = abs(value);
+               int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
+               int i;
+
+               for (i = 0; i < count; i++) {
+                       input_event(input, EV_KEY, direction, 1);
+                       input_sync(input);
+                       input_event(input, EV_KEY, direction, 0);
+                       input_sync(input);
+               }
+               return;
+       }
+
        input_event(input, usage->type, usage->code, value);
 
        if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
@@ -976,7 +1059,7 @@ int hidinput_connect(struct hid_device *hid)
                        if (IS_INPUT_APPLICATION(hid->collection[i].usage))
                                break;
 
-       if (i == hid->maxcollection)
+       if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
                return -1;
 
        if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
@@ -994,7 +1077,7 @@ int hidinput_connect(struct hid_device *hid)
                                if (!hidinput || !input_dev) {
                                        kfree(hidinput);
                                        input_free_device(input_dev);
-                                       err("Out of memory during hid input probe");
+                                       err_hid("Out of memory during hid input probe");
                                        return -1;
                                }
 
index d91b9dac6dff67843b2a8faeff47a9807f6eac45..3afa4a5035b7128b6e84fdc835637bdb9c690b74 100644 (file)
@@ -60,6 +60,12 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
                " quirks=vendorID:productID:quirks"
                " where vendorID, productID, and quirks are all in"
                " 0x-prefixed hex");
+static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
+module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444);
+MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying "
+               " rdesc_quirks=vendorID:productID:rdesc_quirks"
+               " where vendorID, productID, and rdesc_quirks are all in"
+               " 0x-prefixed hex");
 /*
  * Input submission and I/O error handler.
  */
@@ -127,7 +133,7 @@ static void hid_reset(struct work_struct *work)
                        hid_io_error(hid);
                break;
        default:
-               err("can't reset device, %s-%s/input%d, status %d",
+               err_hid("can't reset device, %s-%s/input%d, status %d",
                                hid_to_usb_dev(hid)->bus->bus_name,
                                hid_to_usb_dev(hid)->devpath,
                                usbhid->ifnum, rc);
@@ -220,7 +226,7 @@ static void hid_irq_in(struct urb *urb)
        if (status) {
                clear_bit(HID_IN_RUNNING, &usbhid->iofl);
                if (status != -EPERM) {
-                       err("can't resubmit intr, %s-%s/input%d, status %d",
+                       err_hid("can't resubmit intr, %s-%s/input%d, status %d",
                                        hid_to_usb_dev(hid)->bus->bus_name,
                                        hid_to_usb_dev(hid)->devpath,
                                        usbhid->ifnum, status);
@@ -240,10 +246,10 @@ static int hid_submit_out(struct hid_device *hid)
        usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
        usbhid->urbout->dev = hid_to_usb_dev(hid);
 
-       dbg("submitting out urb");
+       dbg_hid("submitting out urb\n");
 
        if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
-               err("usb_submit_urb(out) failed");
+               err_hid("usb_submit_urb(out) failed");
                return -1;
        }
 
@@ -287,12 +293,12 @@ static int hid_submit_ctrl(struct hid_device *hid)
        usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
        usbhid->cr->wLength = cpu_to_le16(len);
 
-       dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
+       dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
                usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
                usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
 
        if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
-               err("usb_submit_urb(ctrl) failed");
+               err_hid("usb_submit_urb(ctrl) failed");
                return -1;
        }
 
@@ -474,7 +480,7 @@ int usbhid_wait_io(struct hid_device *hid)
        if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
                                        !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
                                        10*HZ)) {
-               dbg("timeout waiting for ctrl or out queue to clear");
+               dbg_hid("timeout waiting for ctrl or out queue to clear\n");
                return -1;
        }
 
@@ -632,20 +638,6 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
        usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
-/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-
-static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
-       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
-               info("Fixing up Cherry Cymotion report descriptor");
-               rdesc[11] = rdesc[16] = 0xff;
-               rdesc[12] = rdesc[17] = 0x03;
-       }
-}
-
 /*
  * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
  * to "operational".  Without this, the ps3 controller will not report any
@@ -667,51 +659,11 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
                                 USB_CTRL_GET_TIMEOUT);
 
        if (result < 0)
-               err("%s failed: %d\n", __func__, result);
+               err_hid("%s failed: %d\n", __func__, result);
 
        kfree(buf);
 }
 
-/*
- * Certain Logitech keyboards send in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 90 && rdesc[83] == 0x26
-                       && rdesc[84] == 0x8c
-                       && rdesc[85] == 0x02) {
-               info("Fixing up Logitech keyboard report descriptor");
-               rdesc[84] = rdesc[89] = 0x4d;
-               rdesc[85] = rdesc[90] = 0x10;
-       }
-}
-
-/*
- * Some USB barcode readers from cypress have usage min and usage max in
- * the wrong order
- */
-static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
-{
-       short fixed = 0;
-       int i;
-
-       for (i = 0; i < rsize - 4; i++) {
-               if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
-                       unsigned char tmp;
-
-                       rdesc[i] = 0x19; rdesc[i+2] = 0x29;
-                       tmp = rdesc[i+3];
-                       rdesc[i+3] = rdesc[i+1];
-                       rdesc[i+1] = tmp;
-               }
-       }
-
-       if (fixed)
-               info("Fixing up Cypress report descriptor");
-}
-
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -746,7 +698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
            (!interface->desc.bNumEndpoints ||
             usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
-               dbg("class descriptor not present\n");
+               dbg_hid("class descriptor not present\n");
                return NULL;
        }
 
@@ -755,41 +707,34 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                        rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
 
        if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
-               dbg("weird size of report descriptor (%u)", rsize);
+               dbg_hid("weird size of report descriptor (%u)\n", rsize);
                return NULL;
        }
 
        if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
-               dbg("couldn't allocate rdesc memory");
+               dbg_hid("couldn't allocate rdesc memory\n");
                return NULL;
        }
 
        hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
 
        if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
-               dbg("reading report descriptor failed");
+               dbg_hid("reading report descriptor failed\n");
                kfree(rdesc);
                return NULL;
        }
 
-       if ((quirks & HID_QUIRK_CYMOTION))
-               hid_fixup_cymotion_descriptor(rdesc, rsize);
+       usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
+                       le16_to_cpu(dev->descriptor.idProduct), rdesc,
+                       rsize, rdesc_quirks_param);
 
-       if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
-               hid_fixup_logitech_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
-               hid_fixup_cypress_descriptor(rdesc, rsize);
-
-#ifdef CONFIG_HID_DEBUG
-       printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+       dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
        for (n = 0; n < rsize; n++)
-               printk(" %02x", (unsigned char) rdesc[n]);
-       printk("\n");
-#endif
+               dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
+       dbg_hid_line("\n");
 
        if (!(hid = hid_parse_report(rdesc, n))) {
-               dbg("parsing report descriptor failed");
+               dbg_hid("parsing report descriptor failed\n");
                kfree(rdesc);
                return NULL;
        }
@@ -861,7 +806,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        }
 
        if (!usbhid->urbin) {
-               err("couldn't find an input interrupt endpoint");
+               err_hid("couldn't find an input interrupt endpoint");
                goto fail;
        }
 
@@ -956,7 +901,7 @@ static void hid_disconnect(struct usb_interface *intf)
        usb_kill_urb(usbhid->urbctrl);
 
        del_timer_sync(&usbhid->io_retry);
-       flush_scheduled_work();
+       cancel_work_sync(&usbhid->reset_work);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_disconnect(hid);
@@ -978,7 +923,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
        int i;
        char *c;
 
-       dbg("HID probe called for ifnum %d",
+       dbg_hid("HID probe called for ifnum %d\n",
                        intf->altsetting->desc.bInterfaceNumber);
 
        if (!(hid = usb_hid_configure(intf)))
index c5cd4107d6aff59f833c4ec9bc79b956522fd135..4b7ab6a46d93b9d2e539820382a33b8edd76ee71 100644 (file)
@@ -78,7 +78,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
                report->field[0]->value[1] = 0x08;
                report->field[0]->value[2] = x;
                report->field[0]->value[3] = y;
-               dbg("(x, y)=(%04x, %04x)", x, y);
+               dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
                usbhid_submit_report(hid, report, USB_DIR_OUT);
                break;
 
@@ -93,7 +93,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
                report->field[0]->value[1] = 0x00;
                report->field[0]->value[2] = left;
                report->field[0]->value[3] = right;
-               dbg("(left, right)=(%04x, %04x)", left, right);
+               dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
                usbhid_submit_report(hid, report, USB_DIR_OUT);
                break;
        }
@@ -113,20 +113,20 @@ int hid_lgff_init(struct hid_device* hid)
 
        /* Find the report to use */
        if (list_empty(report_list)) {
-               err("No output report found");
+               err_hid("No output report found");
                return -1;
        }
 
        /* Check that the report looks ok */
        report = list_entry(report_list->next, struct hid_report, list);
        if (!report) {
-               err("NULL output report");
+               err_hid("NULL output report");
                return -1;
        }
 
        field = report->field[0];
        if (!field) {
-               err("NULL field");
+               err_hid("NULL field");
                return -1;
        }
 
index f5a90e950e6b54cfcd48381f89d8b38e141b1aea..011326178c0670c5b5e680a47d741661101a45aa 100644 (file)
@@ -738,6 +738,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
        pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
        pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
        pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
+       pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
        pidff->set_effect[PID_START_DELAY].value[0] = 0;
 
        usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
index f6c4145dc20253a885ead58fabd0665c8497f273..775b9f3b8ce3e37cce8cc2e45166c1035107d59f 100644 (file)
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
+#define USB_VENDOR_ID_GAMERON          0x0810
+#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
+
 #define USB_VENDOR_ID_GLAB             0x06c2
 #define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
 #define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_WHEEL   0xc294
+#define USB_DEVICE_ID_LOGITECH_KBD     0xc311
 #define USB_DEVICE_ID_S510_RECEIVER    0xc50c
 #define USB_DEVICE_ID_S510_RECEIVER_2  0xc517
+#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500  0xc512
 #define USB_DEVICE_ID_MX3000_RECEIVER  0xc513
 #define USB_DEVICE_ID_DINOVO_EDGE      0xc714
 
 #define USB_DEVICE_ID_MGE_UPS          0xffff
 #define USB_DEVICE_ID_MGE_UPS1         0x0001
 
+#define USB_VENDOR_ID_MICROSOFT                0x045e
+#define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
+
+#define USB_VENDOR_ID_NCR              0x0404
+#define USB_DEVICE_ID_NCR_FIRST                0x0300
+#define USB_DEVICE_ID_NCR_LAST         0x03ff
+
 #define USB_VENDOR_ID_NEC              0x073e
 #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
 
 #define USB_VENDOR_ID_PANTHERLORD      0x0810
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
 
+#define USB_VENDOR_ID_PETALYNX         0x18b1
+#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE   0x0037
+
 #define USB_VENDOR_ID_PLAYDOTCOM       0x0b43
 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII     0x0003
 
@@ -278,6 +293,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -285,11 +301,10 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
        
-       { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
-
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
 
        { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
 
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
@@ -409,9 +424,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
 
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_LOGITECH_DESCRIPTOR },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
 
        { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
 
@@ -426,6 +439,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -448,9 +462,28 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
 
        { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
 
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX },
+       { 0, 0 }
+};
+
+/* Quirks for devices which require report descriptor fixup go here */
+static const struct hid_rdesc_blacklist {
+       __u16 idVendor;
+       __u16 idProduct;
+       __u32 quirks;
+} hid_rdesc_blacklist[] = {
+
+       { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION },
+
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
+
+       { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
+
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
 
        { 0, 0 }
 };
@@ -493,7 +526,7 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
        }
 
        if (bl_entry != NULL)
-               dbg("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
+               dbg_hid("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
                                bl_entry->quirks, bl_entry->idVendor,
                                bl_entry->idProduct);
 
@@ -521,13 +554,13 @@ int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
        int list_edited = 0;
 
        if (!idVendor) {
-               dbg("Cannot add a quirk with idVendor = 0");
+               dbg_hid("Cannot add a quirk with idVendor = 0\n");
                return -EINVAL;
        }
 
        q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);
        if (!q_new) {
-               dbg("Could not allocate quirks_list_struct");
+               dbg_hid("Could not allocate quirks_list_struct\n");
                return -ENOMEM;
        }
 
@@ -559,7 +592,6 @@ int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
        return 0;
 }
 
-
 /**
  * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory
  *
@@ -643,7 +675,7 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
                        bl_entry = &hid_blacklist[n];
 
        if (bl_entry != NULL)
-               dbg("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
+               dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
                                bl_entry->quirks, bl_entry->idVendor, 
                                bl_entry->idProduct);
        return bl_entry;
@@ -675,6 +707,12 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
                                idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
                        return HID_QUIRK_IGNORE;
 
+       /* NCR devices must not be queried for reports */
+       if (idVendor == USB_VENDOR_ID_NCR &&
+                       idProduct >= USB_DEVICE_ID_NCR_FIRST &&
+                       idProduct <= USB_DEVICE_ID_NCR_LAST)
+                       return HID_QUIRK_NOGET;
+
        down_read(&dquirks_rwsem);
        bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
        if (!bl_entry)
@@ -686,3 +724,126 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
        return quirks;
 }
 
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize)
+{
+       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+               printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n");
+               rdesc[11] = rdesc[16] = 0xff;
+               rdesc[12] = rdesc[17] = 0x03;
+       }
+}
+
+
+/*
+ * Certain Logitech keyboards send in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 90 && rdesc[83] == 0x26
+                       && rdesc[84] == 0x8c
+                       && rdesc[85] == 0x02) {
+               printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n");
+               rdesc[84] = rdesc[89] = 0x4d;
+               rdesc[85] = rdesc[90] = 0x10;
+       }
+}
+
+/* Petalynx Maxter Remote has maximum for consumer page set too low */
+static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 60 && rdesc[39] == 0x2a
+                       && rdesc[40] == 0xf5
+                       && rdesc[41] == 0x00
+                       && rdesc[59] == 0x26
+                       && rdesc[60] == 0xf9
+                       && rdesc[61] == 0x00) {
+               printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n");
+               rdesc[60] = 0xfa;
+               rdesc[40] = 0xfa;
+       }
+}
+
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
+{
+       short fixed = 0;
+       int i;
+
+       for (i = 0; i < rsize - 4; i++) {
+               if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
+                       unsigned char tmp;
+
+                       rdesc[i] = 0x19; rdesc[i+2] = 0x29;
+                       tmp = rdesc[i+3];
+                       rdesc[i+3] = rdesc[i+1];
+                       rdesc[i+1] = tmp;
+               }
+       }
+
+       if (fixed)
+               printk(KERN_INFO "Fixing up Cypress report descriptor\n");
+}
+
+
+static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
+{
+       if ((quirks & HID_QUIRK_RDESC_CYMOTION))
+               usbhid_fixup_cymotion_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_RDESC_LOGITECH)
+               usbhid_fixup_logitech_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX)
+               usbhid_fixup_cypress_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_RDESC_PETALYNX)
+               usbhid_fixup_petalynx_descriptor(rdesc, rsize);
+}
+
+/**
+ * usbhid_fixup_report_descriptor: check if report descriptor needs fixup
+ *
+ * Description:
+ *     Walks the hid_rdesc_blacklist[] array and checks whether the device
+ *     is known to have broken report descriptor that needs to be fixed up
+ *     prior to entering the HID parser
+ *
+ * Returns: nothing
+ */
+void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
+                                   char *rdesc, unsigned rsize, char **quirks_param)
+{
+       int n, m;
+       u16 paramVendor, paramProduct;
+       u32 quirks;
+
+       /* static rdesc quirk entries */
+       for (n = 0; hid_rdesc_blacklist[n].idVendor; n++)
+               if (hid_rdesc_blacklist[n].idVendor == idVendor &&
+                               hid_rdesc_blacklist[n].idProduct == idProduct)
+                       __usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks,
+                                       rdesc, rsize);
+
+       /* runtime rdesc quirk entries handling */
+       for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
+               m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
+                               &paramVendor, &paramProduct, &quirks);
+
+               if (m != 3)
+                       printk(KERN_WARNING
+                               "Could not parse HID quirk module param %s\n",
+                               quirks_param[n]);
+               else if (paramVendor == idVendor && paramProduct == idProduct)
+                       __usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
+       }
+
+}
index ab5ba6ef891cb756fd531119baeabef7211c6dcd..555bb48b4295d0d7ea167702ea125bcb4cbd1088 100644 (file)
@@ -70,7 +70,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
 
        tmff->rumble->value[0] = left;
        tmff->rumble->value[1] = right;
-       dbg("(left,right)=(%08x, %08x)", left, right);
+       dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
        usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
 
        return 0;
index a7fbffcdaf363e4398155b774da7bf32156b9db3..5a688274f6a3331d2264d10de5fff780de473b9c 100644 (file)
  */
 
 
-/* #define DEBUG */
-
-#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg)
-
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
@@ -49,14 +45,14 @@ static int hid_zpff_play(struct input_dev *dev, void *data,
 
        left = effect->u.rumble.strong_magnitude;
        right = effect->u.rumble.weak_magnitude;
-       debug("called with 0x%04x 0x%04x", left, right);
+       dbg_hid("called with 0x%04x 0x%04x\n", left, right);
 
        left = left * 0x7f / 0xffff;
        right = right * 0x7f / 0xffff;
 
        zpff->report->field[2]->value[0] = left;
        zpff->report->field[3]->value[0] = right;
-       debug("running with 0x%02x 0x%02x", left, right);
+       dbg_hid("running with 0x%02x 0x%02x\n", left, right);
        usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
 
        return 0;
index 488d61bdbf2c1960d4d84e4cd3347f56916fcd1d..e793127f971eae29903298b7cb6d3ec64a156325 100644 (file)
@@ -779,7 +779,7 @@ int hiddev_connect(struct hid_device *hid)
 
        retval = usb_register_dev(usbhid->intf, &hiddev_class);
        if (retval) {
-               err("Not able to get a minor for this device.");
+               err_hid("Not able to get a minor for this device.");
                kfree(hiddev);
                return -1;
        }
index 1309787807130cfa2e2121ae856ccde721da92ff..b76b02f7b52de04a11e17d2a17e0e80b850d9922 100644 (file)
@@ -125,7 +125,7 @@ static void usb_kbd_irq(struct urb *urb)
 resubmit:
        i = usb_submit_urb (urb, GFP_ATOMIC);
        if (i)
-               err ("can't resubmit intr, %s-%s/input0, status %d",
+               err_hid ("can't resubmit intr, %s-%s/input0, status %d",
                                kbd->usbdev->bus->bus_name,
                                kbd->usbdev->devpath, i);
 }
@@ -151,7 +151,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
        *(kbd->leds) = kbd->newleds;
        kbd->led->dev = kbd->usbdev;
        if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-               err("usb_submit_urb(leds) failed");
+               err_hid("usb_submit_urb(leds) failed");
 
        return 0;
 }
@@ -169,7 +169,7 @@ static void usb_kbd_led(struct urb *urb)
        *(kbd->leds) = kbd->newleds;
        kbd->led->dev = kbd->usbdev;
        if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-               err("usb_submit_urb(leds) failed");
+               err_hid("usb_submit_urb(leds) failed");
 }
 
 static int usb_kbd_open(struct input_dev *dev)
index 66f826252aee4d6c66fa606a2348c25f4d3a4dad..444a0b84f5bdeddbff12fcfb40265c5f6f4b224e 100644 (file)
@@ -448,23 +448,21 @@ static int icside_dma_test_irq(ide_drive_t *drive)
                        ICS_ARCIN_V6_INTRSTAT_1)) & 1;
 }
 
-static int icside_dma_timeout(ide_drive_t *drive)
+static void icside_dma_timeout(ide_drive_t *drive)
 {
        printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
 
        if (icside_dma_test_irq(drive))
-               return 0;
+               return;
 
-       ide_dump_status(drive, "DMA timeout",
-               HWIF(drive)->INB(IDE_STATUS_REG));
+       ide_dump_status(drive, "DMA timeout", HWIF(drive)->INB(IDE_STATUS_REG));
 
-       return icside_dma_end(drive);
+       icside_dma_end(drive);
 }
 
-static int icside_dma_lostirq(ide_drive_t *drive)
+static void icside_dma_lost_irq(ide_drive_t *drive)
 {
        printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-       return 1;
 }
 
 static void icside_dma_init(ide_hwif_t *hwif)
@@ -490,8 +488,8 @@ static void icside_dma_init(ide_hwif_t *hwif)
        hwif->dma_start         = icside_dma_start;
        hwif->ide_dma_end       = icside_dma_end;
        hwif->ide_dma_test_irq  = icside_dma_test_irq;
-       hwif->ide_dma_timeout   = icside_dma_timeout;
-       hwif->ide_dma_lostirq   = icside_dma_lostirq;
+       hwif->dma_timeout       = icside_dma_timeout;
+       hwif->dma_lost_irq      = icside_dma_lost_irq;
 
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
index ca0341c05e556bf8828cc32349c7cfc07da29ebd..886091bc7db01e1028804b136a635f53f7c6cc3f 100644 (file)
@@ -819,7 +819,7 @@ init_e100_ide (void)
                hwif->dma_host_off = &cris_dma_off;
                hwif->dma_host_on = &cris_dma_on;
                hwif->dma_off_quietly = &cris_dma_off;
-               hwif->udma_four = 0;
+               hwif->cbl = ATA_CBL_PATA40;
                hwif->ultra_mask = cris_ultra_mask;
                hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
                hwif->autodma = 1;
index 252ab8295edfd9fef5fc0fb029e0ed33c898e9f0..1486eb212ccc7b2952ebe0d9fba53edd2e5324c2 100644 (file)
@@ -481,7 +481,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                else
                        printk("  Unknown Error Type: ");
 
-               if (sense->sense_key < ARY_LEN(sense_key_texts))
+               if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
                        s = sense_key_texts[sense->sense_key];
 
                printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
@@ -491,7 +491,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                                 sense->ascq);
                        s = buf;
                } else {
-                       int lo = 0, mid, hi = ARY_LEN(sense_data_texts);
+                       int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
                        unsigned long key = (sense->sense_key << 16);
                        key |= (sense->asc << 8);
                        if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
@@ -524,7 +524,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
 
                if (failed_command != NULL) {
 
-                       int lo=0, mid, hi= ARY_LEN (packet_command_texts);
+                       int lo=0, mid, hi= ARRAY_SIZE(packet_command_texts);
                        s = NULL;
 
                        while (hi > lo) {
index ad1f2ed14a3723cbcec3081341487e7d784c494c..228b29c5d2e4d0684d6f2490ed6aa7c5a6bfa098 100644 (file)
@@ -498,8 +498,6 @@ struct cdrom_info {
  * Descriptions of ATAPI error codes.
  */
 
-#define ARY_LEN(a) ((sizeof(a) / sizeof(a[0])))
-
 /* This stuff should be in cdrom.h, since it is now generic... */
 
 /* ATAPI sense keys (from table 140 of ATAPI 2.6) */
index dc2175c81f5efe5c955729efd5b23b22c612d48e..b1304a7f3e0acfea5bb2ab900a0f0f1ab75e0169 100644 (file)
@@ -1190,11 +1190,11 @@ static int idedisk_ioctl(struct inode *inode, struct file *file,
        return generic_ide_ioctl(drive, file, bdev, cmd, arg);
 
 read_val:
-       down(&ide_setting_sem);
+       mutex_lock(&ide_setting_mtx);
        spin_lock_irqsave(&ide_lock, flags);
        err = *val;
        spin_unlock_irqrestore(&ide_lock, flags);
-       up(&ide_setting_sem);
+       mutex_unlock(&ide_setting_mtx);
        return err >= 0 ? put_user(err, (long __user *)arg) : err;
 
 set_val:
@@ -1204,9 +1204,9 @@ set_val:
                if (!capable(CAP_SYS_ADMIN))
                        err = -EACCES;
                else {
-                       down(&ide_setting_sem);
+                       mutex_lock(&ide_setting_mtx);
                        err = setfunc(drive, arg);
-                       up(&ide_setting_sem);
+                       mutex_unlock(&ide_setting_mtx);
                }
        }
        return err;
index ead141e2db9e2d12213daaa5d746fe178a05724d..5fe1d72ab4514e97a5dbcc5c3c1ea6183cd46324 100644 (file)
 
 static const struct drive_list_entry drive_whitelist [] = {
 
-       { "Micropolis 2112A"    ,       "ALL"           },
-       { "CONNER CTMA 4000"    ,       "ALL"           },
-       { "CONNER CTT8000-A"    ,       "ALL"           },
-       { "ST34342A"            ,       "ALL"           },
+       { "Micropolis 2112A"    ,       NULL            },
+       { "CONNER CTMA 4000"    ,       NULL            },
+       { "CONNER CTT8000-A"    ,       NULL            },
+       { "ST34342A"            ,       NULL            },
        { NULL                  ,       NULL            }
 };
 
 static const struct drive_list_entry drive_blacklist [] = {
 
-       { "WDC AC11000H"        ,       "ALL"           },
-       { "WDC AC22100H"        ,       "ALL"           },
-       { "WDC AC32500H"        ,       "ALL"           },
-       { "WDC AC33100H"        ,       "ALL"           },
-       { "WDC AC31600H"        ,       "ALL"           },
+       { "WDC AC11000H"        ,       NULL            },
+       { "WDC AC22100H"        ,       NULL            },
+       { "WDC AC32500H"        ,       NULL            },
+       { "WDC AC33100H"        ,       NULL            },
+       { "WDC AC31600H"        ,       NULL            },
        { "WDC AC32100H"        ,       "24.09P07"      },
        { "WDC AC23200L"        ,       "21.10N21"      },
-       { "Compaq CRD-8241B"    ,       "ALL"           },
-       { "CRD-8400B"           ,       "ALL"           },
-       { "CRD-8480B",                  "ALL"           },
-       { "CRD-8482B",                  "ALL"           },
-       { "CRD-84"              ,       "ALL"           },
-       { "SanDisk SDP3B"       ,       "ALL"           },
-       { "SanDisk SDP3B-64"    ,       "ALL"           },
-       { "SANYO CD-ROM CRD"    ,       "ALL"           },
-       { "HITACHI CDR-8"       ,       "ALL"           },
-       { "HITACHI CDR-8335"    ,       "ALL"           },
-       { "HITACHI CDR-8435"    ,       "ALL"           },
-       { "Toshiba CD-ROM XM-6202B"     ,       "ALL"           },
-       { "TOSHIBA CD-ROM XM-1702BC",   "ALL"           },
-       { "CD-532E-A"           ,       "ALL"           },
-       { "E-IDE CD-ROM CR-840",        "ALL"           },
-       { "CD-ROM Drive/F5A",   "ALL"           },
-       { "WPI CDD-820",                "ALL"           },
-       { "SAMSUNG CD-ROM SC-148C",     "ALL"           },
-       { "SAMSUNG CD-ROM SC",  "ALL"           },
-       { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     "ALL"           },
-       { "_NEC DV5800A",               "ALL"           },  
+       { "Compaq CRD-8241B"    ,       NULL            },
+       { "CRD-8400B"           ,       NULL            },
+       { "CRD-8480B",                  NULL            },
+       { "CRD-8482B",                  NULL            },
+       { "CRD-84"              ,       NULL            },
+       { "SanDisk SDP3B"       ,       NULL            },
+       { "SanDisk SDP3B-64"    ,       NULL            },
+       { "SANYO CD-ROM CRD"    ,       NULL            },
+       { "HITACHI CDR-8"       ,       NULL            },
+       { "HITACHI CDR-8335"    ,       NULL            },
+       { "HITACHI CDR-8435"    ,       NULL            },
+       { "Toshiba CD-ROM XM-6202B"     ,       NULL            },
+       { "TOSHIBA CD-ROM XM-1702BC",   NULL            },
+       { "CD-532E-A"           ,       NULL            },
+       { "E-IDE CD-ROM CR-840",        NULL            },
+       { "CD-ROM Drive/F5A",   NULL            },
+       { "WPI CDD-820",                NULL            },
+       { "SAMSUNG CD-ROM SC-148C",     NULL            },
+       { "SAMSUNG CD-ROM SC",  NULL            },
+       { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     NULL            },
+       { "_NEC DV5800A",               NULL            },
        { "SAMSUNG CD-ROM SN-124",      "N001" },
-       { "Seagate STT20000A",          "ALL" },
+       { "Seagate STT20000A",          NULL  },
        { NULL                  ,       NULL            }
 
 };
@@ -147,8 +147,8 @@ int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *driv
 {
        for ( ; drive_table->id_model ; drive_table++)
                if ((!strcmp(drive_table->id_model, id->model)) &&
-                   ((strstr(id->fw_rev, drive_table->id_firmware)) ||
-                    (!strcmp(drive_table->id_firmware, "ALL"))))
+                   (!drive_table->id_firmware ||
+                    strstr(id->fw_rev, drive_table->id_firmware)))
                        return 1;
        return 0;
 }
@@ -702,8 +702,22 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
                        mask = id->dma_mword & hwif->mwdma_mask;
                break;
        case XFER_SW_DMA_0:
-               if (id->field_valid & 2)
+               if (id->field_valid & 2) {
                        mask = id->dma_1word & hwif->swdma_mask;
+               } else if (id->tDMA) {
+                       /*
+                        * ide_fix_driveid() doesn't convert ->tDMA to the
+                        * CPU endianness so we need to do it here
+                        */
+                       u8 mode = le16_to_cpu(id->tDMA);
+
+                       /*
+                        * if the mode is valid convert it to the mask
+                        * (the maximum allowed mode is XFER_SW_DMA_2)
+                        */
+                       if (mode <= 2)
+                               mask = ((2 << mode) - 1) & hwif->swdma_mask;
+               }
                break;
        default:
                BUG();
@@ -847,27 +861,27 @@ int ide_set_dma(ide_drive_t *drive)
        return rc;
 }
 
-EXPORT_SYMBOL_GPL(ide_set_dma);
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-int __ide_dma_lostirq (ide_drive_t *drive)
+void ide_dma_lost_irq (ide_drive_t *drive)
 {
        printk("%s: DMA interrupt recovery\n", drive->name);
-       return 1;
 }
 
-EXPORT_SYMBOL(__ide_dma_lostirq);
+EXPORT_SYMBOL(ide_dma_lost_irq);
 
-int __ide_dma_timeout (ide_drive_t *drive)
+void ide_dma_timeout (ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = HWIF(drive);
+
        printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
-       if (HWIF(drive)->ide_dma_test_irq(drive))
-               return 0;
 
-       return HWIF(drive)->ide_dma_end(drive);
+       if (hwif->ide_dma_test_irq(drive))
+               return;
+
+       hwif->ide_dma_end(drive);
 }
 
-EXPORT_SYMBOL(__ide_dma_timeout);
+EXPORT_SYMBOL(ide_dma_timeout);
 
 /*
  * Needed for allowing full modular support of ide-driver
@@ -1018,10 +1032,10 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
                hwif->ide_dma_end = &__ide_dma_end;
        if (!hwif->ide_dma_test_irq)
                hwif->ide_dma_test_irq = &__ide_dma_test_irq;
-       if (!hwif->ide_dma_timeout)
-               hwif->ide_dma_timeout = &__ide_dma_timeout;
-       if (!hwif->ide_dma_lostirq)
-               hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+       if (!hwif->dma_timeout)
+               hwif->dma_timeout = &ide_dma_timeout;
+       if (!hwif->dma_lost_irq)
+               hwif->dma_lost_irq = &ide_dma_lost_irq;
 
        if (hwif->chipset != ide_trm290) {
                u8 dma_stat = hwif->INB(hwif->dma_status);
index bfe8f1b712bad1cfc3356fdc204b2553a2f0583b..c5b5011da56e37a568c19e06dd27383a834fa358 100644 (file)
@@ -1350,7 +1350,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
                                                hwif->INB(IDE_STATUS_REG));
        } else {
                printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
-               (void) hwif->ide_dma_timeout(drive);
+               hwif->dma_timeout(drive);
        }
 
        /*
@@ -1466,7 +1466,7 @@ void ide_timer_expiry (unsigned long data)
                                startstop = handler(drive);
                        } else if (drive_is_ready(drive)) {
                                if (drive->waiting_for_dma)
-                                       (void) hwgroup->hwif->ide_dma_lostirq(drive);
+                                       hwgroup->hwif->dma_lost_irq(drive);
                                (void)ide_ack_intr(hwif);
                                printk(KERN_WARNING "%s: lost interrupt\n", drive->name);
                                startstop = handler(drive);
index f0be5f665a0e0ae21af516609c0a82c556b4e0cd..92578b6832e9fbb2e31dd0287f1664ae979ab082 100644 (file)
@@ -574,7 +574,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        struct hd_driveid *id = drive->id;
 
-       if (hwif->udma_four == 0)
+       if (hwif->cbl == ATA_CBL_PATA40_SHORT)
+               return 1;
+
+       if (hwif->cbl != ATA_CBL_PATA80)
                goto no_80w;
 
        /* Check for SATA but only if we are ATA5 or higher */
@@ -600,7 +603,8 @@ no_80w:
 
        printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
                            "limiting max speed to UDMA33\n",
-                           drive->name, hwif->udma_four ? "drive" : "host");
+                           drive->name,
+                           hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host");
 
        drive->udma33_warned = 1;
 
index f5ce22c38f827eceec594021ad68d1c5811aeacf..cc5801399467360bbd1097a5aa36801a487a6a36 100644 (file)
@@ -144,7 +144,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
        local_irq_enable();
        ide_fix_driveid(id);
 
-#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
+#if defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
        /*
         * EATA SCSI controllers do a hardware ATA emulation:
         * Ignore them if there is a driver for them available.
@@ -154,7 +154,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
                printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
                goto err_misc;
        }
-#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
+#endif /* CONFIG_SCSI_EATA || CONFIG_SCSI_EATA_PIO */
 
        /*
         *  WIN_IDENTIFY returns little-endian info,
@@ -1025,7 +1025,7 @@ static int init_irq (ide_hwif_t *hwif)
        BUG_ON(irqs_disabled());        
        BUG_ON(hwif == NULL);
 
-       down(&ide_cfg_sem);
+       mutex_lock(&ide_cfg_mtx);
        hwif->hwgroup = NULL;
 #if MAX_HWIFS > 1
        /*
@@ -1154,7 +1154,7 @@ static int init_irq (ide_hwif_t *hwif)
                printk(" (%sed with %s)",
                        hwif->sharing_irq ? "shar" : "serializ", match->name);
        printk("\n");
-       up(&ide_cfg_sem);
+       mutex_unlock(&ide_cfg_mtx);
        return 0;
 out_unlink:
        spin_lock_irq(&ide_lock);
@@ -1177,7 +1177,7 @@ out_unlink:
        }
        spin_unlock_irq(&ide_lock);
 out_up:
-       up(&ide_cfg_sem);
+       mutex_unlock(&ide_cfg_mtx);
        return 1;
 }
 
index ea94c9aa1220754b8cad352bff4cb8102e08075f..fc1d8ae6a80381d08937faf4dc5d2fd687d33c7c 100644 (file)
@@ -156,7 +156,7 @@ static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int d
 {
        ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 
-       down(&ide_setting_sem);
+       mutex_lock(&ide_setting_mtx);
        while ((*p) && strcmp((*p)->name, name) < 0)
                p = &((*p)->next);
        if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
@@ -177,10 +177,10 @@ static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int d
        if (auto_remove)
                setting->auto_remove = 1;
        *p = setting;
-       up(&ide_setting_sem);
+       mutex_unlock(&ide_setting_mtx);
        return 0;
 abort:
-       up(&ide_setting_sem);
+       mutex_unlock(&ide_setting_mtx);
        kfree(setting);
        return -1;
 }
@@ -224,7 +224,7 @@ static void __ide_remove_setting (ide_drive_t *drive, char *name)
  *
  *     Automatically remove all the driver specific settings for this
  *     drive. This function may not be called from IRQ context. The
- *     caller must hold ide_setting_sem.
+ *     caller must hold ide_setting_mtx.
  */
 
 static void auto_remove_settings (ide_drive_t *drive)
@@ -269,7 +269,7 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
  *     @setting: drive setting
  *
  *     Read a drive setting and return the value. The caller
- *     must hold the ide_setting_sem when making this call.
+ *     must hold the ide_setting_mtx when making this call.
  *
  *     BUGS: the data return and error are the same return value
  *     so an error -EINVAL and true return of the same value cannot
@@ -306,7 +306,7 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
  *     @val: value
  *
  *     Write a drive setting if it is possible. The caller
- *     must hold the ide_setting_sem when making this call.
+ *     must hold the ide_setting_mtx when making this call.
  *
  *     BUGS: the data return and error are the same return value
  *     so an error -EINVAL and true return of the same value cannot
@@ -367,7 +367,7 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
  *     @drive: drive being configured
  *
  *     Add the generic parts of the system settings to the /proc files.
- *     The caller must not be holding the ide_setting_sem.
+ *     The caller must not be holding the ide_setting_mtx.
  */
 
 void ide_add_generic_settings (ide_drive_t *drive)
@@ -408,7 +408,7 @@ static int proc_ide_read_settings
 
        proc_ide_settings_warn();
 
-       down(&ide_setting_sem);
+       mutex_lock(&ide_setting_mtx);
        out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
        out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
        while(setting) {
@@ -428,7 +428,7 @@ static int proc_ide_read_settings
                setting = setting->next;
        }
        len = out - page;
-       up(&ide_setting_sem);
+       mutex_unlock(&ide_setting_mtx);
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -508,16 +508,16 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
                                ++p;
                        }
 
-                       down(&ide_setting_sem);
+                       mutex_lock(&ide_setting_mtx);
                        setting = ide_find_setting_by_name(drive, name);
                        if (!setting)
                        {
-                               up(&ide_setting_sem);
+                               mutex_unlock(&ide_setting_mtx);
                                goto parse_error;
                        }
                        if (for_real)
                                ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
-                       up(&ide_setting_sem);
+                       mutex_unlock(&ide_setting_mtx);
                }
        } while (!for_real++);
        free_page((unsigned long)buf);
@@ -705,7 +705,7 @@ EXPORT_SYMBOL(ide_proc_register_driver);
  *     Clean up the driver specific /proc files and IDE settings
  *     for a given drive.
  *
- *     Takes ide_setting_sem and ide_lock.
+ *     Takes ide_setting_mtx and ide_lock.
  *     Caller must hold none of the locks.
  */
 
@@ -715,10 +715,10 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
 
        ide_remove_proc_entries(drive->proc, driver->proc);
 
-       down(&ide_setting_sem);
+       mutex_lock(&ide_setting_mtx);
        spin_lock_irqsave(&ide_lock, flags);
        /*
-        * ide_setting_sem protects the settings list
+        * ide_setting_mtx protects the settings list
         * ide_lock protects the use of settings
         *
         * so we need to hold both, ide_settings_sem because we want to
@@ -726,11 +726,11 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
         * a setting out that is being used.
         *
         * OTOH both ide_{read,write}_setting are only ever used under
-        * ide_setting_sem.
+        * ide_setting_mtx.
         */
        auto_remove_settings(drive);
        spin_unlock_irqrestore(&ide_lock, flags);
-       up(&ide_setting_sem);
+       mutex_unlock(&ide_setting_mtx);
 }
 
 EXPORT_SYMBOL(ide_proc_unregister_driver);
index c0864b1e92285ed514fe5982a79383fdd9efbc3b..e6cb8593b5ba8382ce4e481e524bdcf6b1de3ca7 100644 (file)
@@ -102,66 +102,16 @@ static struct ide_timing ide_timing[] = {
 #define EZ(v,unit)             ((v)?ENOUGH(v,unit):0)
 
 #define XFER_MODE      0xf0
-#define XFER_UDMA_133  0x48
-#define XFER_UDMA_100  0x44
-#define XFER_UDMA_66   0x42
-#define XFER_UDMA      0x40
 #define XFER_MWDMA     0x20
-#define XFER_SWDMA     0x10
 #define XFER_EPIO      0x01
 #define XFER_PIO       0x00
 
-static short ide_find_best_mode(ide_drive_t *drive, int map)
+static short ide_find_best_pio_mode(ide_drive_t *drive)
 {
        struct hd_driveid *id = drive->id;
        short best = 0;
 
-       if (!id)
-               return XFER_PIO_SLOW;
-
-       if ((map & XFER_UDMA) && (id->field_valid & 4)) {       /* Want UDMA and UDMA bitmap valid */
-
-               if ((map & XFER_UDMA_133) == XFER_UDMA_133)
-                       if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
-
-               if ((map & XFER_UDMA_100) == XFER_UDMA_100)
-                       if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
-
-               if ((map & XFER_UDMA_66) == XFER_UDMA_66)
-                       if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 :
-                                   (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
-
-                if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 :
-                           (id->dma_ultra & 0x0002) ? XFER_UDMA_1 :
-                           (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best;
-       }
-
-       if ((map & XFER_MWDMA) && (id->field_valid & 2)) {      /* Want MWDMA and drive has EIDE fields */
-
-               if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 :
-                           (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 :
-                           (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0)) return best;
-       }
-
-       if (map & XFER_SWDMA) {                                 /* Want SWDMA */
-
-               if (id->field_valid & 2) {                      /* EIDE SWDMA */
-
-                       if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 :
-                                   (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 :
-                                   (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0)) return best;
-               }
-
-               if (id->capability & 1) {                       /* Pre-EIDE style SWDMA */
-
-                       if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 :
-                                   (id->tDMA == 1) ? XFER_SW_DMA_1 :
-                                   (id->tDMA == 0) ? XFER_SW_DMA_0 : 0)) return best;
-               }
-       }
-
-
-       if ((map & XFER_EPIO) && (id->field_valid & 2)) {       /* EIDE PIO modes */
+       if (id->field_valid & 2) {      /* EIDE PIO modes */
 
                if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
                            (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
@@ -262,7 +212,7 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
  */
 
        if ((speed & XFER_MODE) != XFER_PIO) {
-               ide_timing_compute(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT);
+               ide_timing_compute(drive, ide_find_best_pio_mode(drive), &p, T, UT);
                ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
        }
 
index 0cd76bf66833aa1afedc47715fc9271d5a85145d..c948a5c17a5d8c1e1cb5afe9682afa1f51e95442 100644 (file)
@@ -169,7 +169,7 @@ static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
 static int idebus_parameter;   /* holds the "idebus=" parameter */
 static int system_bus_speed;   /* holds what we think is VESA/PCI bus speed */
 
-DECLARE_MUTEX(ide_cfg_sem);
+DEFINE_MUTEX(ide_cfg_mtx);
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
@@ -460,6 +460,8 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->mwdma_mask                = tmp_hwif->mwdma_mask;
        hwif->swdma_mask                = tmp_hwif->swdma_mask;
 
+       hwif->cbl                       = tmp_hwif->cbl;
+
        hwif->chipset                   = tmp_hwif->chipset;
        hwif->hold                      = tmp_hwif->hold;
 
@@ -496,8 +498,8 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->ide_dma_clear_irq         = tmp_hwif->ide_dma_clear_irq;
        hwif->dma_host_on               = tmp_hwif->dma_host_on;
        hwif->dma_host_off              = tmp_hwif->dma_host_off;
-       hwif->ide_dma_lostirq           = tmp_hwif->ide_dma_lostirq;
-       hwif->ide_dma_timeout           = tmp_hwif->ide_dma_timeout;
+       hwif->dma_lost_irq              = tmp_hwif->dma_lost_irq;
+       hwif->dma_timeout               = tmp_hwif->dma_timeout;
 
        hwif->OUTB                      = tmp_hwif->OUTB;
        hwif->OUTBSYNC                  = tmp_hwif->OUTBSYNC;
@@ -533,7 +535,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->extra_base                = tmp_hwif->extra_base;
        hwif->extra_ports               = tmp_hwif->extra_ports;
        hwif->autodma                   = tmp_hwif->autodma;
-       hwif->udma_four                 = tmp_hwif->udma_four;
 
        hwif->hwif_data                 = tmp_hwif->hwif_data;
 }
@@ -564,7 +565,7 @@ void ide_unregister(unsigned int index)
 {
        ide_drive_t *drive;
        ide_hwif_t *hwif, *g;
-       static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
+       static ide_hwif_t tmp_hwif; /* protected by ide_cfg_mtx */
        ide_hwgroup_t *hwgroup;
        int irq_count = 0, unit;
 
@@ -572,7 +573,7 @@ void ide_unregister(unsigned int index)
 
        BUG_ON(in_interrupt());
        BUG_ON(irqs_disabled());
-       down(&ide_cfg_sem);
+       mutex_lock(&ide_cfg_mtx);
        spin_lock_irq(&ide_lock);
        hwif = &ide_hwifs[index];
        if (!hwif->present)
@@ -679,7 +680,7 @@ void ide_unregister(unsigned int index)
 
 abort:
        spin_unlock_irq(&ide_lock);
-       up(&ide_cfg_sem);
+       mutex_unlock(&ide_cfg_mtx);
 }
 
 EXPORT_SYMBOL(ide_unregister);
@@ -817,9 +818,9 @@ EXPORT_SYMBOL(ide_register_hw);
  *     Locks for IDE setting functionality
  */
 
-DECLARE_MUTEX(ide_setting_sem);
+DEFINE_MUTEX(ide_setting_mtx);
 
-EXPORT_SYMBOL_GPL(ide_setting_sem);
+EXPORT_SYMBOL_GPL(ide_setting_mtx);
 
 /**
  *     ide_spin_wait_hwgroup   -       wait for group
@@ -1192,11 +1193,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
        }
 
 read_val:
-       down(&ide_setting_sem);
+       mutex_lock(&ide_setting_mtx);
        spin_lock_irqsave(&ide_lock, flags);
        err = *val;
        spin_unlock_irqrestore(&ide_lock, flags);
-       up(&ide_setting_sem);
+       mutex_unlock(&ide_setting_mtx);
        return err >= 0 ? put_user(err, (long __user *)arg) : err;
 
 set_val:
@@ -1206,9 +1207,9 @@ set_val:
                if (!capable(CAP_SYS_ADMIN))
                        err = -EACCES;
                else {
-                       down(&ide_setting_sem);
+                       mutex_lock(&ide_setting_mtx);
                        err = setfunc(drive, arg);
-                       up(&ide_setting_sem);
+                       mutex_unlock(&ide_setting_mtx);
                }
        }
        return err;
@@ -1548,7 +1549,11 @@ static int __init ide_setup(char *s)
                                goto bad_option;
                        case -7: /* ata66 */
 #ifdef CONFIG_BLK_DEV_IDEPCI
-                               hwif->udma_four = 1;
+                               /*
+                                * Use ATA_CBL_PATA40_SHORT so drive side
+                                * cable detection is also overriden.
+                                */
+                               hwif->cbl = ATA_CBL_PATA40_SHORT;
                                goto obsolete_option;
 #else
                                goto bad_hwif;
index 45ed03591cd88df752caeb58bea03379f6367cd8..7f4c0a5050a1393e27e0c2ec3c9e7117d0546935 100644 (file)
@@ -130,7 +130,7 @@ struct hd_i_struct {
        
 #ifdef HD_TYPE
 static struct hd_i_struct hd_info[] = { HD_TYPE };
-static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+static int NR_HD = ARRAY_SIZE(hd_info);
 #else
 static struct hd_i_struct hd_info[MAX_HD];
 static int NR_HD;
@@ -623,7 +623,8 @@ repeat:
        cyl   = track / disk->head;
 #ifdef DEBUG
        printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n",
-               req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ",
+               req->rq_disk->disk_name,
+               req_data_dir(req) == READ ? "read" : "writ",
                cyl, head, sec, nsect, req->buffer);
 #endif
        if (blk_fs_request(req)) {
index c211fc78345d16b0c3f9da4ef96b8a1ff6c79bbd..b557c45a5a9dc614e7aa556e07554f5b3623457a 100644 (file)
@@ -77,15 +77,6 @@ int macide_ack_intr(ide_hwif_t* hwif)
        return 0;
 }
 
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-static void macide_mediabay_interrupt(int irq, void *dev_id)
-{
-       int state = baboon->mb_status & 0x04;
-
-       printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion");
-}
-#endif
-
 /*
  * Probe for a Macintosh IDE interface
  */
@@ -128,11 +119,6 @@ void macide_init(void)
                        ide_drive_t *drive = &ide_hwifs[index].drives[0];
                        drive->capacity64 = drive->cyl*drive->head*drive->sect;
 
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-                       request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
-                                       IRQ_FLG_FAST, "mediabay",
-                                       macide_mediabay_interrupt);
-#endif
                }
                break;
 
index ca95e990862ebdf36df33f936e47709b8d1ace6a..2e7013a2a7f635073eefef53498a54698e095fe5 100644 (file)
@@ -381,9 +381,7 @@ static int auide_dma_setup(ide_drive_t *drive)
 
 static int auide_dma_check(ide_drive_t *drive)
 {
-       u8 speed;
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+       u8 speed = ide_max_dma_mode(drive);
 
        if( dbdma_init_done == 0 ){
                auide_hwif.white_list = ide_in_drive_list(drive->id,
@@ -394,7 +392,6 @@ static int auide_dma_check(ide_drive_t *drive)
                auide_ddma_init(&auide_hwif);
                dbdma_init_done = 1;
        }
-#endif
 
        /* Is the drive in our DMA black list? */
 
@@ -409,8 +406,6 @@ static int auide_dma_check(ide_drive_t *drive)
        else
                drive->using_dma = 1;
 
-       speed = ide_find_best_mode(drive, XFER_PIO | XFER_MWDMA);
-       
        if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
                return 0;
 
@@ -456,10 +451,9 @@ static void auide_dma_off_quietly(ide_drive_t *drive)
        drive->using_dma = 0;
 }
 
-static int auide_dma_lostirq(ide_drive_t *drive)
+static void auide_dma_lost_irq(ide_drive_t *drive)
 {
        printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-       return 0;
 }
 
 static void auide_ddma_tx_callback(int irq, void *param)
@@ -489,16 +483,16 @@ static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 de
   
 #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
 
-static int auide_dma_timeout(ide_drive_t *drive)
+static void auide_dma_timeout(ide_drive_t *drive)
 {
-//      printk("%s\n", __FUNCTION__);
+       ide_hwif_t *hwif = HWIF(drive);
 
        printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
 
-       if (HWIF(drive)->ide_dma_test_irq(drive))
-               return 0;
+       if (hwif->ide_dma_test_irq(drive))
+               return;
 
-       return HWIF(drive)->ide_dma_end(drive);
+       hwif->ide_dma_end(drive);
 }
                                        
 
@@ -721,7 +715,7 @@ static int au_ide_probe(struct device *dev)
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
        hwif->dma_off_quietly           = &auide_dma_off_quietly;
-       hwif->ide_dma_timeout           = &auide_dma_timeout;
+       hwif->dma_timeout               = &auide_dma_timeout;
 
        hwif->ide_dma_check             = &auide_dma_check;
        hwif->dma_exec_cmd              = &auide_dma_exec_cmd;
@@ -731,7 +725,7 @@ static int au_ide_probe(struct device *dev)
        hwif->ide_dma_test_irq          = &auide_dma_test_irq;
        hwif->dma_host_off              = &auide_dma_host_off;
        hwif->dma_host_on               = &auide_dma_host_on;
-       hwif->ide_dma_lostirq           = &auide_dma_lostirq;
+       hwif->dma_lost_irq              = &auide_dma_lost_irq;
        hwif->ide_dma_on                = &auide_dma_on;
 
        hwif->autodma                   = 1;
index b173bc66ce1e19ae25efef18e8361864c850a877..e5d09367627ee19e99217af29dd2bae68fc50286 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/aec62xx.c             Version 0.21    Apr 21, 2007
+ * linux/drivers/ide/pci/aec62xx.c             Version 0.24    May 24, 2007
  *
  * Copyright (C) 1999-2002     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2007          MontaVista Software, Inc. <source@mvista.com>
@@ -140,25 +140,10 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        return(ide_config_drive_speed(drive, speed));
 }
 
-static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
-{
-       switch (HWIF(drive)->pci_dev->device) {
-               case PCI_DEVICE_ID_ARTOP_ATP865:
-               case PCI_DEVICE_ID_ARTOP_ATP865R:
-               case PCI_DEVICE_ID_ARTOP_ATP860:
-               case PCI_DEVICE_ID_ARTOP_ATP860R:
-                       return ((int) aec6260_tune_chipset(drive, speed));
-               case PCI_DEVICE_ID_ARTOP_ATP850UF:
-                       return ((int) aec6210_tune_chipset(drive, speed));
-               default:
-                       return -1;
-       }
-}
-
 static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
 {
        pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-       (void) aec62xx_tune_chipset(drive, pio + XFER_PIO_0);
+       (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
 }
 
 static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
@@ -172,12 +157,9 @@ static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
        return -1;
 }
 
-static int aec62xx_irq_timeout (ide_drive_t *drive)
+static void aec62xx_dma_lost_irq (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
-
-       switch(dev->device) {
+       switch (HWIF(drive)->pci_dev->device) {
                case PCI_DEVICE_ID_ARTOP_ATP860:
                case PCI_DEVICE_ID_ARTOP_ATP860R:
                case PCI_DEVICE_ID_ARTOP_ATP865:
@@ -186,7 +168,6 @@ static int aec62xx_irq_timeout (ide_drive_t *drive)
                default:
                        break;
        }
-       return 0;
 }
 
 static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const char *name)
@@ -224,64 +205,46 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
 
 static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev     = hwif->pci_dev;
+       u8 reg54 = 0,  mask     = hwif->channel ? 0xf0 : 0x0f;
+       unsigned long flags;
 
-       hwif->autodma = 0;
        hwif->tuneproc = &aec62xx_tune_drive;
-       hwif->speedproc = &aec62xx_tune_chipset;
 
-       if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
-               hwif->serialized = hwif->channel;
-
-       if (hwif->mate)
-               hwif->mate->serialized = hwif->serialized;
+       if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+               if(hwif->mate)
+                       hwif->mate->serialized = hwif->serialized = 1;
+               hwif->speedproc = &aec6210_tune_chipset;
+       } else
+               hwif->speedproc = &aec6260_tune_chipset;
 
        if (!hwif->dma_base) {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
+               hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
                return;
        }
 
        hwif->ultra_mask = hwif->cds->udma_mask;
-
-       /* atp865 and atp865r */
-       if (hwif->ultra_mask == 0x3f) {
-               /* check bit 0x10 of DMA status register */
-               if (inb(pci_resource_start(dev, 4) + 2) & 0x10)
-                       hwif->ultra_mask = 0x7f; /* udma0-6 */
-       }
-
        hwif->mwdma_mask = 0x07;
 
        hwif->ide_dma_check     = &aec62xx_config_drive_xfer_rate;
-       hwif->ide_dma_lostirq   = &aec62xx_irq_timeout;
-
-       if (!noautodma)
-               hwif->autodma = 1;
-       hwif->drives[0].autodma = hwif->autodma;
-       hwif->drives[1].autodma = hwif->autodma;
-}
-
-static void __devinit init_dma_aec62xx(ide_hwif_t *hwif, unsigned long dmabase)
-{
-       struct pci_dev *dev     = hwif->pci_dev;
+       hwif->dma_lost_irq      = &aec62xx_dma_lost_irq;
 
        if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-               u8 reg54h = 0;
-               unsigned long flags;
-
                spin_lock_irqsave(&ide_lock, flags);
-               pci_read_config_byte(dev, 0x54, &reg54h);
-               pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+               pci_read_config_byte (dev, 0x54, &reg54);
+               pci_write_config_byte(dev, 0x54, (reg54 & ~mask));
                spin_unlock_irqrestore(&ide_lock, flags);
-       } else {
-               u8 ata66        = 0;
+       } else if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
+               u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
+
                pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
-               if (!(hwif->udma_four))
-                       hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1;
+
+               hwif->cbl = (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
        }
 
-       ide_setup_dma(hwif, dmabase, 8);
+       if (!noautodma)
+               hwif->autodma = 1;
+       hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
 }
 
 static int __devinit init_setup_aec62xx(struct pci_dev *dev, ide_pci_device_t *d)
@@ -291,16 +254,12 @@ static int __devinit init_setup_aec62xx(struct pci_dev *dev, ide_pci_device_t *d
 
 static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d)
 {
-       unsigned long bar4reg = pci_resource_start(dev, 4);
-
-       if (inb(bar4reg+2) & 0x10) {
-               strcpy(d->name, "AEC6880");
-               if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
-                       strcpy(d->name, "AEC6880R");
-       } else {
-               strcpy(d->name, "AEC6280");
-               if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
-                       strcpy(d->name, "AEC6280R");
+       unsigned long dma_base = pci_resource_start(dev, 4);
+
+       if (inb(dma_base + 2) & 0x10) {
+               d->name = (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) ?
+                         "AEC6880R" : "AEC6880";
+               d->udma_mask = 0x7f; /* udma0-6 */
        }
 
        return ide_setup_pci_device(dev, d);
@@ -312,7 +271,6 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .init_setup     = init_setup_aec62xx,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .init_dma       = init_dma_aec62xx,
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
@@ -323,7 +281,6 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .init_setup     = init_setup_aec62xx,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .init_dma       = init_dma_aec62xx,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = OFF_BOARD,
@@ -333,28 +290,25 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .init_setup     = init_setup_aec62xx,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .init_dma       = init_dma_aec62xx,
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = NEVER_BOARD,
                .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
-               .name           = "AEC6X80",
+               .name           = "AEC6280",
                .init_setup     = init_setup_aec6x80,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .init_dma       = init_dma_aec62xx,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 4 */
-               .name           = "AEC6X80R",
+               .name           = "AEC6280R",
                .init_setup     = init_setup_aec6x80,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .init_dma       = init_dma_aec62xx,
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
@@ -370,13 +324,16 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
  *
  *     Called when the PCI registration layer (or the IDE initialization)
  *     finds a device matching our IDE device tables.
+ *
+ *     NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
+ *     chips, pass a local copy of 'struct pci_device_id' down the call chain.
  */
  
 static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data];
+       ide_pci_device_t d = aec62xx_chipsets[id->driver_data];
 
-       return d->init_setup(dev, d);
+       return d.init_setup(dev, &d);
 }
 
 static struct pci_device_id aec62xx_pci_tbl[] = {
index 27525ec2e19a68a566a2c53bfba05d4c4263117d..8a6b27b3bcc3fb67de4ebfdeb7305453a6ecf8de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/alim15x3.c            Version 0.21    2007/02/03
+ * linux/drivers/ide/pci/alim15x3.c            Version 0.25    Jun 9 2007
  *
  *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
  *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -10,6 +10,7 @@
  *  Copyright (C) 2002 Alan Cox <alan@redhat.com>
  *  ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
  *  Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ *  Copyright (C) 2007 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
  *
  *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
  *
@@ -36,6 +37,7 @@
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
+#include <linux/dmi.h>
 
 #include <asm/io.h>
 
@@ -583,6 +585,35 @@ out:
        return 0;
 }
 
+/*
+ *     Cable special cases
+ */
+
+static struct dmi_system_id cable_dmi_table[] = {
+       {
+               .ident = "HP Pavilion N5430",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+               },
+       },
+       { }
+};
+
+static int ali_cable_override(struct pci_dev *pdev)
+{
+       /* Fujitsu P2000 */
+       if (pdev->subsystem_vendor == 0x10CF &&
+           pdev->subsystem_device == 0x10AF)
+               return 1;
+
+       /* Systems by DMI */
+       if (dmi_check_system(cable_dmi_table))
+               return 1;
+
+       return 0;
+}
+
 /**
  *     ata66_ali15x3   -       check for UDMA 66 support
  *     @hwif: IDE interface
@@ -594,37 +625,31 @@ out:
  *     FIXME: frobs bits that are not defined on newer ALi devicea
  */
 
-static unsigned int __devinit ata66_ali15x3 (ide_hwif_t *hwif)
+static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
 {
        struct pci_dev *dev     = hwif->pci_dev;
-       unsigned int ata66      = 0;
-       u8 cable_80_pin[2]      = { 0, 0 };
-
        unsigned long flags;
-       u8 tmpbyte;
+       u8 cbl = ATA_CBL_PATA40, tmpbyte;
 
        local_irq_save(flags);
 
        if (m5229_revision >= 0xC2) {
                /*
-                * Ultra66 cable detection (from Host View)
-                * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
-                */
-               pci_read_config_byte(dev, 0x4a, &tmpbyte);
-               /*
-                * 0x4a, bit0 is 0 => primary channel
-                * has 80-pin (from host view)
-                */
-               if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
-               /*
-                * 0x4a, bit1 is 0 => secondary channel
-                * has 80-pin (from host view)
-                */
-               if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
-               /*
-                * Allow ata66 if cable of current channel has 80 pins
+                * m5229 80-pin cable detection (from Host View)
+                *
+                * 0x4a bit0 is 0 => primary channel has 80-pin
+                * 0x4a bit1 is 0 => secondary channel has 80-pin
+                *
+                * Certain laptops use short but suitable cables
+                * and don't implement the detect logic.
                 */
-               ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+               if (ali_cable_override(dev))
+                       cbl = ATA_CBL_PATA40_SHORT;
+               else {
+                       pci_read_config_byte(dev, 0x4a, &tmpbyte);
+                       if ((tmpbyte & (1 << hwif->channel)) == 0)
+                               cbl = ATA_CBL_PATA80;
+               }
        } else {
                /*
                 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
@@ -657,7 +682,7 @@ static unsigned int __devinit ata66_ali15x3 (ide_hwif_t *hwif)
 
        local_irq_restore(flags);
 
-       return(ata66);
+       return cbl;
 }
 
 /**
@@ -708,8 +733,9 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
                hwif->dma_setup = &ali15x3_dma_setup;
                if (!noautodma)
                        hwif->autodma = 1;
-               if (!(hwif->udma_four))
-                       hwif->udma_four = ata66_ali15x3(hwif);
+
+               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+                       hwif->cbl = ata66_ali15x3(hwif);
        }
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
index a2be65fcf89c6f45aed44cfbccd83471a543b814..84ed30cdb324de5d4928700807f8db1198140228 100644 (file)
@@ -1,10 +1,11 @@
 /*
- * Version 2.16
+ * Version 2.20
  *
  * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
  * IDE driver for Linux.
  *
  * Copyright (c) 2000-2002 Vojtech Pavlik
+ * Copyright (c) 2007 Bartlomiej Zolnierkiewicz
  *
  * Based on the work of:
  *      Andre Hedrick
 #define AMD_ADDRESS_SETUP      (0x0c + amd_config->base)
 #define AMD_UDMA_TIMING                (0x10 + amd_config->base)
 
-#define AMD_UDMA               0x07
-#define AMD_UDMA_33            0x01
-#define AMD_UDMA_66            0x02
-#define AMD_UDMA_100           0x03
-#define AMD_UDMA_133           0x04
 #define AMD_CHECK_SWDMA                0x08
 #define AMD_BAD_SWDMA          0x10
 #define AMD_BAD_FIFO           0x20
 
 static struct amd_ide_chip {
        unsigned short id;
-       unsigned long base;
-       unsigned char flags;
+       u8 base;
+       u8 udma_mask;
+       u8 flags;
 } amd_ide_chips[] = {
-       { PCI_DEVICE_ID_AMD_COBRA_7401,         0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },
-       { PCI_DEVICE_ID_AMD_VIPER_7409,         0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA },
-       { PCI_DEVICE_ID_AMD_VIPER_7411,         0x40, AMD_UDMA_100 | AMD_BAD_FIFO },
-       { PCI_DEVICE_ID_AMD_OPUS_7441,          0x40, AMD_UDMA_100 },
-       { PCI_DEVICE_ID_AMD_8111_IDE,           0x40, AMD_UDMA_133 | AMD_CHECK_SERENADE },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,      0x50, AMD_UDMA_100 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,     0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,    0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,   0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,     0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,    0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,   0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,  0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE,        0x50, AMD_UDMA_133 },
-       { PCI_DEVICE_ID_AMD_CS5536_IDE,                 0x40, AMD_UDMA_100 },
+       { PCI_DEVICE_ID_AMD_COBRA_7401,          0x40, ATA_UDMA2, AMD_BAD_SWDMA },
+       { PCI_DEVICE_ID_AMD_VIPER_7409,          0x40, ATA_UDMA4, AMD_CHECK_SWDMA },
+       { PCI_DEVICE_ID_AMD_VIPER_7411,          0x40, ATA_UDMA5, AMD_BAD_FIFO },
+       { PCI_DEVICE_ID_AMD_OPUS_7441,           0x40, ATA_UDMA5, },
+       { PCI_DEVICE_ID_AMD_8111_IDE,            0x40, ATA_UDMA6, AMD_CHECK_SERENADE },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,       0x50, ATA_UDMA5, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,      0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,     0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,    0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,      0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,     0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,    0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,   0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE, 0x50, ATA_UDMA6, },
+       { PCI_DEVICE_ID_AMD_CS5536_IDE,          0x40, ATA_UDMA5, },
        { 0 }
 };
 
@@ -87,7 +84,7 @@ static ide_pci_device_t *amd_chipset;
 static unsigned int amd_80w;
 static unsigned int amd_clock;
 
-static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
 static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
 
 /*
@@ -128,7 +125,7 @@ static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
 
        pci_read_config_byte(dev, PCI_REVISION_ID, &t);
        amd_print("Revision:                           IDE %#x", t);
-       amd_print("Highest DMA rate:                   %s", amd_dma[amd_config->flags & AMD_UDMA]);
+       amd_print("Highest DMA rate:                   UDMA%s", amd_dma[fls(amd_config->udma_mask) - 1]);
 
        amd_print("BM-DMA base:                        %#lx", amd_base);
        amd_print("PCI clock:                          %d.%dMHz", amd_clock / 1000, amd_clock / 100 % 10);
@@ -221,12 +218,12 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
        pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
                ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
 
-       switch (amd_config->flags & AMD_UDMA) {
-               case AMD_UDMA_33:  t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-               case AMD_UDMA_66:  t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
-               case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
-               case AMD_UDMA_133: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 15)]) : 0x03; break;
-               default: return;
+       switch (amd_config->udma_mask) {
+       case ATA_UDMA2: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+       case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
+       case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
+       case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 15)]) : 0x03; break;
+       default: return;
        }
 
        pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
@@ -248,7 +245,7 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
                ide_config_drive_speed(drive, speed);
 
        T = 1000000000 / amd_clock;
-       UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2);
+       UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2);
 
        ide_timing_compute(drive, speed, &t, T, UT);
 
@@ -277,29 +274,19 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
 static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
        if (pio == 255) {
-               amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+               amd_set_drive(drive, ide_find_best_pio_mode(drive));
                return;
        }
 
        amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
 }
 
-/*
- * amd74xx_dmaproc() is a callback from upper layers that can do
- * a lot, but we use it for DMA/PIO tuning only, delegating everything
- * else to the default ide_dmaproc().
- */
-
 static int amd74xx_ide_dma_check(ide_drive_t *drive)
 {
-       int w80 = HWIF(drive)->udma_four;
+       u8 speed = ide_max_dma_mode(drive);
 
-       u8 speed = ide_find_best_mode(drive,
-               XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
-               ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
-               (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
-               (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0) |
-               (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_133 ? XFER_UDMA_133 : 0));
+       if (speed == 0)
+               speed = ide_find_best_pio_mode(drive);
 
        amd_set_drive(drive, speed);
 
@@ -334,10 +321,10 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
  * Check 80-wire cable presence.
  */
 
-       switch (amd_config->flags & AMD_UDMA) {
+       switch (amd_config->udma_mask) {
 
-               case AMD_UDMA_133:
-               case AMD_UDMA_100:
+               case ATA_UDMA6:
+               case ATA_UDMA5:
                        pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
                        pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
                        amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
@@ -349,7 +336,7 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
                                }
                        break;
 
-               case AMD_UDMA_66:
+               case ATA_UDMA4:
                        /* no host side cable detection */
                        amd_80w = 0x03;
                        break;
@@ -370,7 +357,7 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
        if ((amd_config->flags & AMD_CHECK_SERENADE) &&
                dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
                dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
-                       amd_config->flags = AMD_UDMA_100;
+                       amd_config->udma_mask = ATA_UDMA5;
 
 /*
  * Determine the system bus clock.
@@ -395,8 +382,9 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
  */
 
        pci_read_config_byte(dev, PCI_REVISION_ID, &t);
-       printk(KERN_INFO "%s: %s (rev %02x) %s controller\n",
-               amd_chipset->name, pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA]);
+       printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
+               amd_chipset->name, pci_name(dev), t,
+               amd_dma[fls(amd_config->udma_mask) - 1]);
 
 /*
  * Register /proc/ide/amd74xx entry
@@ -437,12 +425,19 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                return;
 
         hwif->atapi_dma = 1;
-        hwif->ultra_mask = 0x7f;
-        hwif->mwdma_mask = 0x07;
-        hwif->swdma_mask = 0x07;
 
-       if (!hwif->udma_four)
-               hwif->udma_four = (amd_80w >> hwif->channel) & 1;
+       hwif->ultra_mask = amd_config->udma_mask;
+       hwif->mwdma_mask = 0x07;
+       if ((amd_config->flags & AMD_BAD_SWDMA) == 0)
+               hwif->swdma_mask = 0x07;
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
+               if ((amd_80w >> hwif->channel) & 1)
+                       hwif->cbl = ATA_CBL_PATA80;
+               else
+                       hwif->cbl = ATA_CBL_PATA40;
+       }
+
         hwif->ide_dma_check = &amd74xx_ide_dma_check;
         if (!noautodma)
                 hwif->autodma = 1;
index 8ab33faf6f76776d860d1b2db3ce72834937f369..2761510309b381a17de6dd8078262d104191de33 100644 (file)
@@ -264,10 +264,11 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
        hwif->swdma_mask = 0x04;
 
        pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
+
        if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
-               hwif->udma_four = 1;
+               hwif->cbl = ATA_CBL_PATA80;
        else
-               hwif->udma_four = 0;
+               hwif->cbl = ATA_CBL_PATA40;
 
        hwif->dma_host_on = &atiixp_dma_host_on;
        hwif->dma_host_off = &atiixp_dma_host_off;
index 7c57dc696f5206d9b4d4f26e0d185e874f2fd1a3..8631b6c8aa15bbae16f1f1b6ad817eb76d353840 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cmd64x.c              Version 1.47    Mar 19, 2007
+ * linux/drivers/ide/pci/cmd64x.c              Version 1.50    May 10, 2007
  *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Due to massive hardware bugs, UltraDMA is only supported
@@ -52,9 +52,6 @@
 #define   ARTTIM23_DIS_RA2     0x04
 #define   ARTTIM23_DIS_RA3     0x08
 #define   ARTTIM23_INTR_CH1    0x10
-#define ARTTIM2                0x57
-#define ARTTIM3                0x57
-#define DRWTIM23       0x58
 #define DRWTIM2                0x58
 #define BRST           0x59
 #define DRWTIM3                0x5b
@@ -469,71 +466,43 @@ static int cmd646_1_ide_dma_end (ide_drive_t *drive)
 
 static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const char *name)
 {
-       u32 class_rev = 0;
        u8 mrdmode = 0;
 
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xff;
+       if (dev->device == PCI_DEVICE_ID_CMD_646) {
+               u8 rev = 0;
 
-       switch(dev->device) {
-               case PCI_DEVICE_ID_CMD_643:
-                       break;
-               case PCI_DEVICE_ID_CMD_646:
-                       printk(KERN_INFO "%s: chipset revision 0x%02X, ", name, class_rev);
-                       switch(class_rev) {
-                               case 0x07:
-                               case 0x05:
-                                       printk("UltraDMA Capable");
-                                       break;
-                               case 0x03:
-                                       printk("MultiWord DMA Force Limited");
-                                       break;
-                               case 0x01:
-                               default:
-                                       printk("MultiWord DMA Limited, IRQ workaround enabled");
-                                       break;
-                               }
-                       printk("\n");
-                        break;
-               case PCI_DEVICE_ID_CMD_648:
-               case PCI_DEVICE_ID_CMD_649:
+               pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+               switch (rev) {
+               case 0x07:
+               case 0x05:
+                       printk("%s: UltraDMA capable", name);
                        break;
+               case 0x03:
                default:
+                       printk("%s: MultiWord DMA force limited", name);
+                       break;
+               case 0x01:
+                       printk("%s: MultiWord DMA limited, "
+                              "IRQ workaround enabled\n", name);
                        break;
+               }
        }
 
        /* Set a good latency timer and cache line size value. */
        (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
        /* FIXME: pci_set_master() to ensure a good latency timer value */
 
-       /* Setup interrupts. */
-       (void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
-       mrdmode &= ~(0x30);
-       (void) pci_write_config_byte(dev, MRDMODE, mrdmode);
-
-       /* Use MEMORY READ LINE for reads.
-        * NOTE: Although not mentioned in the PCI0646U specs,
-        *       these bits are write only and won't be read
-        *       back as set or not.  The PCI0646U2 specs clarify
-        *       this point.
+       /*
+        * Enable interrupts, select MEMORY READ LINE for reads.
+        *
+        * NOTE: although not mentioned in the PCI0646U specs,
+        * bits 0-1 are write only and won't be read back as
+        * set or not -- PCI0646U2 specs clarify this point.
         */
-       (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-
-       /* Set reasonable active/recovery/address-setup values. */
-       (void) pci_write_config_byte(dev, ARTTIM0,  0x40);
-       (void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
-       (void) pci_write_config_byte(dev, ARTTIM1,  0x40);
-       (void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
-#ifdef __i386__
-       (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#else
-       (void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
-#endif
-       (void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
-       (void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
-#ifdef CONFIG_PPC
-       (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
-#endif /* CONFIG_PPC */
+       (void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
+       mrdmode &= ~0x30;
+       (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
 
 #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 
@@ -548,29 +517,27 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
        return 0;
 }
 
-static unsigned int __devinit ata66_cmd64x(ide_hwif_t *hwif)
+static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
 {
-       u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01;
+       struct pci_dev  *dev    = hwif->pci_dev;
+       u8 bmidecsr = 0, mask   = hwif->channel ? 0x02 : 0x01;
 
-       switch(hwif->pci_dev->device) {
-               case PCI_DEVICE_ID_CMD_643:
-               case PCI_DEVICE_ID_CMD_646:
-                       return ata66;
-               default:
-                       break;
+       switch (dev->device) {
+       case PCI_DEVICE_ID_CMD_648:
+       case PCI_DEVICE_ID_CMD_649:
+               pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
+               return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+       default:
+               return ATA_CBL_PATA40;
        }
-       pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
-       return (ata66 & mask) ? 1 : 0;
 }
 
 static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
 {
        struct pci_dev *dev     = hwif->pci_dev;
-       unsigned int class_rev;
+       u8 rev                  = 0;
 
-       hwif->autodma = 0;
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xff;
+       pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
        hwif->tuneproc  = &cmd64x_tune_drive;
        hwif->speedproc = &cmd64x_tune_chipset;
@@ -580,8 +547,8 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
        if (!hwif->dma_base)
                return;
 
-       hwif->atapi_dma = 1;
-
+       hwif->atapi_dma  = 1;
+       hwif->mwdma_mask = 0x07;
        hwif->ultra_mask = hwif->cds->udma_mask;
 
        /*
@@ -596,16 +563,15 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
         *
         * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
         */
-       if (dev->device == PCI_DEVICE_ID_CMD_646 && class_rev < 5)
+       if (dev->device == PCI_DEVICE_ID_CMD_646 && rev < 5)
                hwif->ultra_mask = 0x00;
 
-       hwif->mwdma_mask = 0x07;
-
        hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66_cmd64x(hwif);
 
-       switch(dev->device) {
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_cmd64x(hwif);
+
+       switch (dev->device) {
        case PCI_DEVICE_ID_CMD_648:
        case PCI_DEVICE_ID_CMD_649:
        alt_irq_bits:
@@ -614,10 +580,10 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
                break;
        case PCI_DEVICE_ID_CMD_646:
                hwif->chipset = ide_cmd646;
-               if (class_rev == 0x01) {
+               if (rev == 0x01) {
                        hwif->ide_dma_end = &cmd646_1_ide_dma_end;
                        break;
-               } else if (class_rev >= 0x03)
+               } else if (rev >= 0x03)
                        goto alt_irq_bits;
                /* fall thru */
        default:
@@ -626,11 +592,9 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
                break;
        }
 
-
        if (!noautodma)
                hwif->autodma = 1;
-       hwif->drives[0].autodma = hwif->autodma;
-       hwif->drives[1].autodma = hwif->autodma;
+       hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
 }
 
 static int __devinit init_setup_cmd64x(struct pci_dev *dev, ide_pci_device_t *d)
index 41925c47ef05968d484107b34b7c22b1e53373c4..10f61f38243cbc6242ee1b33c2634b1cdca6a8e1 100644 (file)
@@ -187,7 +187,8 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
 
        /* if a 80 wire cable was detected */
        pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
-       return (bit & 1);
+
+       return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 }
 
 /****
@@ -212,8 +213,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
        hwif->ultra_mask = 0x1F;
        hwif->mwdma_mask = 0x07;
 
-
-       hwif->udma_four = cs5535_cable_detect(hwif->pci_dev);
+       hwif->cbl = cs5535_cable_detect(hwif->pci_dev);
 
        if (!noautodma)
                hwif->autodma = 1;
index c33d0b0f11c91896eb498bb1a5f030ad7ce6b51b..4b6bae8eee82822b875bd40f4ccba0cb72894c9b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c              Version 1.06    Jun 27, 2007
+ * linux/drivers/ide/pci/hpt366.c              Version 1.10    Jun 29, 2007
  *
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
@@ -77,7 +77,7 @@
  *   since they may tamper with its fields
  * - prefix the driver startup messages with the real chip name
  * - claim the extra 240 bytes of I/O space for all chips
- * - optimize the rate masking/filtering and the drive list lookup code
+ * - optimize the UltraDMA filtering and the drive list lookup code
  * - use pci_get_slot() to get to the function 1 of HPT36x/374
  * - cache offset of the channel's misc. control registers (MCRs) being used
  *   throughout the driver
@@ -99,9 +99,9 @@
  *   stop duplicating it for each channel by storing the pointer in the pci_dev
  *   structure: first, at the init_setup stage, point it to a static "template"
  *   with only the chip type and its specific base DPLL frequency, the highest
- *   supported DMA mode, and the chip settings table pointer filled, then, at
- *   the init_chipset stage, allocate per-chip instance  and fill it with the
- *   rest of the necessary information
+ *   UltraDMA mode, and the chip settings table pointer filled,  then, at the
+ *   init_chipset stage, allocate per-chip instance  and fill it with the rest
+ *   of the necessary information
  * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
  *   switch  to calculating  PCI clock frequency based on the chip's base DPLL
  *   frequency
  *   also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
  *   unify HPT36x/37x timing setup code and the speedproc handlers by joining
  *   the register setting lists into the table indexed by the clock selected
+ * - set the correct hwif->ultra_mask for each individual chip
  *     Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
  */
 
@@ -391,7 +392,7 @@ enum ata_clock {
 
 struct hpt_info {
        u8 chip_type;           /* Chip type */
-       u8 max_mode;            /* Speeds allowed */
+       u8 max_ultra;           /* Max. UltraDMA mode allowed */
        u8 dpll_clk;            /* DPLL clock in MHz */
        u8 pci_clk;             /* PCI  clock in MHz */
        u32 **settings;         /* Chipset settings table */
@@ -430,77 +431,77 @@ static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
 
 static struct hpt_info hpt36x __devinitdata = {
        .chip_type      = HPT36x,
-       .max_mode       = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+       .max_ultra      = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? 4 : 3) : 2,
        .dpll_clk       = 0,    /* no DPLL */
        .settings       = hpt36x_settings
 };
 
 static struct hpt_info hpt370 __devinitdata = {
        .chip_type      = HPT370,
-       .max_mode       = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+       .max_ultra      = HPT370_ALLOW_ATA100_5 ? 5 : 4,
        .dpll_clk       = 48,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt370a __devinitdata = {
        .chip_type      = HPT370A,
-       .max_mode       = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+       .max_ultra      = HPT370_ALLOW_ATA100_5 ? 5 : 4,
        .dpll_clk       = 48,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt374 __devinitdata = {
        .chip_type      = HPT374,
-       .max_mode       = 3,
+       .max_ultra      = 5,
        .dpll_clk       = 48,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt372 __devinitdata = {
        .chip_type      = HPT372,
-       .max_mode       = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT372_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 55,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt372a __devinitdata = {
        .chip_type      = HPT372A,
-       .max_mode       = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT372_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 66,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt302 __devinitdata = {
        .chip_type      = HPT302,
-       .max_mode       = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT372_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 66,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt371 __devinitdata = {
        .chip_type      = HPT371,
-       .max_mode       = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT371_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 66,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt372n __devinitdata = {
        .chip_type      = HPT372N,
-       .max_mode       = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT372_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 77,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt302n __devinitdata = {
        .chip_type      = HPT302N,
-       .max_mode       = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT302_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 77,
        .settings       = hpt37x_settings
 };
 
 static struct hpt_info hpt371n __devinitdata = {
        .chip_type      = HPT371N,
-       .max_mode       = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+       .max_ultra      = HPT371_ALLOW_ATA133_6 ? 6 : 5,
        .dpll_clk       = 77,
        .settings       = hpt37x_settings
 };
@@ -523,53 +524,38 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
 static u8 hpt3xx_udma_filter(ide_drive_t *drive)
 {
        struct hpt_info *info   = pci_get_drvdata(HWIF(drive)->pci_dev);
-       u8 chip_type            = info->chip_type;
-       u8 mode                 = info->max_mode;
        u8 mask;
 
-       switch (mode) {
-               case 0x04:
-                       mask = 0x7f;
-                       break;
-               case 0x03:
+       switch (info->chip_type) {
+       case HPT370A:
+               if (!HPT370_ALLOW_ATA100_5 ||
+                   check_in_drive_list(drive, bad_ata100_5))
+                       return 0x1f;
+               else
+                       return 0x3f;
+       case HPT370:
+               if (!HPT370_ALLOW_ATA100_5 ||
+                   check_in_drive_list(drive, bad_ata100_5))
+                       mask = 0x1f;
+               else
                        mask = 0x3f;
-                       if (chip_type >= HPT374)
-                               break;
-                       if (!check_in_drive_list(drive, bad_ata100_5))
-                               goto check_bad_ata33;
-                       /* fall thru */
-               case 0x02:
+               break;
+       case HPT36x:
+               if (!HPT366_ALLOW_ATA66_4 ||
+                   check_in_drive_list(drive, bad_ata66_4))
+                       mask = 0x0f;
+               else
                        mask = 0x1f;
 
-                       /*
-                        * CHECK ME, Does this need to be changed to HPT374 ??
-                        */
-                       if (chip_type >= HPT370)
-                               goto check_bad_ata33;
-                       if (HPT366_ALLOW_ATA66_4 &&
-                           !check_in_drive_list(drive, bad_ata66_4))
-                               goto check_bad_ata33;
-
-                       mask = 0x0f;
-                       if (HPT366_ALLOW_ATA66_3 &&
-                           !check_in_drive_list(drive, bad_ata66_3))
-                               goto check_bad_ata33;
-                       /* fall thru */
-               case 0x01:
+               if (!HPT366_ALLOW_ATA66_3 ||
+                   check_in_drive_list(drive, bad_ata66_3))
                        mask = 0x07;
-
-               check_bad_ata33:
-                       if (chip_type >= HPT370A)
-                               break;
-                       if (!check_in_drive_list(drive, bad_ata33))
-                               break;
-                       /* fall thru */
-               case 0x00:
-               default:
-                       mask = 0x00;
-                       break;
+               break;
+       default:
+               return 0x7f;
        }
-       return mask;
+
+       return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
 }
 
 static u32 get_speed_setting(u8 speed, struct hpt_info *info)
@@ -737,7 +723,7 @@ static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
  * This is specific to the HPT366 UDMA chipset
  * by HighPoint|Triones Technologies, Inc.
  */
-static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
+static void hpt366_dma_lost_irq(ide_drive_t *drive)
 {
        struct pci_dev *dev = HWIF(drive)->pci_dev;
        u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
@@ -749,7 +735,7 @@ static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
                drive->name, __FUNCTION__, mcr1, mcr3, scr1);
        if (scr1 & 0x10)
                pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
-       return __ide_dma_lostirq(drive);
+       ide_dma_lost_irq(drive);
 }
 
 static void hpt370_clear_engine(ide_drive_t *drive)
@@ -799,10 +785,10 @@ static int hpt370_ide_dma_end(ide_drive_t *drive)
        return __ide_dma_end(drive);
 }
 
-static int hpt370_ide_dma_timeout(ide_drive_t *drive)
+static void hpt370_dma_timeout(ide_drive_t *drive)
 {
        hpt370_irq_timeout(drive);
-       return __ide_dma_timeout(drive);
+       ide_dma_timeout(drive);
 }
 
 /* returns 1 if DMA IRQ issued, 0 otherwise */
@@ -1150,7 +1136,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
                  * Select 66 MHz DPLL clock only if UltraATA/133 mode is
                  * supported/enabled, use 50 MHz DPLL clock otherwise...
                  */
-               if (info->max_mode == 0x04) {
+               if (info->max_ultra == 6) {
                        dpll_clk = 66;
                        clock = ATA_CLOCK_66MHZ;
                } else if (dpll_clk) {  /* HPT36x chips don't have DPLL */
@@ -1243,7 +1229,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        struct pci_dev  *dev            = hwif->pci_dev;
        struct hpt_info *info           = pci_get_drvdata(dev);
        int serialize                   = HPT_SERIALIZE_IO;
-       u8  scr1 = 0, ata66             = (hwif->channel) ? 0x01 : 0x02;
+       u8  scr1 = 0, ata66             = hwif->channel ? 0x01 : 0x02;
        u8  chip_type                   = info->chip_type;
        u8  new_mcr, old_mcr            = 0;
 
@@ -1256,7 +1242,9 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        hwif->intrproc                  = &hpt3xx_intrproc;
        hwif->maskproc                  = &hpt3xx_maskproc;
        hwif->busproc                   = &hpt3xx_busproc;
-       hwif->udma_filter               = &hpt3xx_udma_filter;
+
+       if (chip_type <= HPT370A)
+               hwif->udma_filter       = &hpt3xx_udma_filter;
 
        /*
         * HPT3xxN chips have some complications:
@@ -1305,7 +1293,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                return;
        }
 
-       hwif->ultra_mask = 0x7f;
+       hwif->ultra_mask = hwif->cds->udma_mask;
        hwif->mwdma_mask = 0x07;
 
        /*
@@ -1342,8 +1330,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        } else
                pci_read_config_byte (dev, 0x5a, &scr1);
 
-       if (!hwif->udma_four)
-               hwif->udma_four = (scr1 & ata66) ? 0 : 1;
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 
        hwif->ide_dma_check             = &hpt366_config_drive_xfer_rate;
 
@@ -1353,9 +1341,9 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        } else if (chip_type >= HPT370) {
                hwif->dma_start         = &hpt370_ide_dma_start;
                hwif->ide_dma_end       = &hpt370_ide_dma_end;
-               hwif->ide_dma_timeout   = &hpt370_ide_dma_timeout;
+               hwif->dma_timeout       = &hpt370_dma_timeout;
        } else
-               hwif->ide_dma_lostirq   = &hpt366_ide_dma_lostirq;
+               hwif->dma_lost_irq      = &hpt366_dma_lost_irq;
 
        if (!noautodma)
                hwif->autodma = 1;
@@ -1503,9 +1491,35 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
 
        pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
-       if (rev > 6)
+       switch (rev) {
+       case 0:
+       case 1:
+       case 2:
+               /*
+                * HPT36x chips have one channel per function and have
+                * both channel enable bits located differently and visible
+                * to both functions -- really stupid design decision... :-(
+                * Bit 4 is for the primary channel, bit 5 for the secondary.
+                */
+               d->channels = 1;
+               d->enablebits[0].mask = d->enablebits[0].val = 0x10;
+
+               d->udma_mask = HPT366_ALLOW_ATA66_3 ?
+                             (HPT366_ALLOW_ATA66_4 ? 0x1f : 0x0f) : 0x07;
+               break;
+       case 3:
+       case 4:
+               d->udma_mask = HPT370_ALLOW_ATA100_5 ? 0x3f : 0x1f;
+               break;
+       default:
                rev = 6;
-               
+               /* fall thru */
+       case 5:
+       case 6:
+               d->udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f;
+               break;
+       }
+
        d->name = chipset_names[rev];
 
        pci_set_drvdata(dev, info[rev]);
@@ -1513,15 +1527,6 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
        if (rev > 2)
                goto init_single;
 
-       /*
-        * HPT36x chips have one channel per function and have
-        * both channel enable bits located differently and visible
-        * to both functions -- really stupid design decision... :-(
-        * Bit 4 is for the primary channel, bit 5 for the secondary.
-        */
-       d->channels = 1;
-       d->enablebits[0].mask = d->enablebits[0].val = 0x10;
-
        if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
                u8  mcr1 = 0, pin1 = 0, pin2 = 0;
                int ret;
@@ -1573,6 +1578,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+               .udma_mask      = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
                .extra          = 240
        },{     /* 2 */
@@ -1584,6 +1590,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+               .udma_mask      = HPT302_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
                .extra          = 240
        },{     /* 3 */
@@ -1595,6 +1602,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+               .udma_mask      = HPT371_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
                .extra          = 240
        },{     /* 4 */
@@ -1606,6 +1614,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .channels       = 2,    /* 4 */
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+               .udma_mask      = 0x3f,
                .bootable       = OFF_BOARD,
                .extra          = 240
        },{     /* 5 */
@@ -1617,6 +1626,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .channels       = 2,    /* 4 */
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+               .udma_mask      = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
                .extra          = 240
        }
index c04a02687b95ec91c3687761c6f3e4e318b380c5..ff48c23e571ea03ad6506437b3ece40f3afedd47 100644 (file)
@@ -231,7 +231,7 @@ static int it8213_config_drive_for_dma (ide_drive_t *drive)
 
 static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
 {
-       u8 reg42h = 0, ata66 = 0;
+       u8 reg42h = 0;
 
        hwif->speedproc = &it8213_tune_chipset;
        hwif->tuneproc  = &it8213_tuneproc;
@@ -250,11 +250,11 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
        hwif->swdma_mask = 0x04;
 
        pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
-       ata66 = (reg42h & 0x02) ? 0 : 1;
 
        hwif->ide_dma_check = &it8213_config_drive_for_dma;
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66;
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 
        /*
         *      The BIOS often doesn't set up DMA on this controller
index 3aeb7f1b79168f9790f3faafda531c653b7195c4..8197b653ba1ed8cbb67e450ed6d5af628a21dd40 100644 (file)
@@ -491,10 +491,10 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive)
  *     the needed logic onboard.
  */
 
-static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif)
+static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
 {
        /* The reference driver also only does disk side */
-       return 1;
+       return ATA_CBL_PATA80;
 }
 
 /**
@@ -662,8 +662,9 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
 
        hwif->ide_dma_check = &it821x_config_drive_for_dma;
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66_it821x(hwif);
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_it821x(hwif);
 
        /*
         *      The BIOS often doesn't set up DMA on this controller
index 76ed251472298682a516c0b6699dc0c07a7618d4..a6008f63e71ef677721411e7d2f36cb1696e9141 100644 (file)
@@ -25,10 +25,10 @@ typedef enum {
  *     ata66_jmicron           -       Cable check
  *     @hwif: IDE port
  *
- *     Return 1 if the cable is 80pin
+ *     Returns the cable type.
  */
 
-static int __devinit ata66_jmicron(ide_hwif_t *hwif)
+static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
 {
        struct pci_dev *pdev = hwif->pci_dev;
 
@@ -70,16 +70,17 @@ static int __devinit ata66_jmicron(ide_hwif_t *hwif)
        {
        case PORT_PATA0:
                if (control & (1 << 3)) /* 40/80 pin primary */
-                       return 0;
-               return 1;
+                       return ATA_CBL_PATA40;
+               return ATA_CBL_PATA80;
        case PORT_PATA1:
                if (control5 & (1 << 19))       /* 40/80 pin secondary */
-                       return 0;
-               return 1;
+                       return ATA_CBL_PATA40;
+               return ATA_CBL_PATA80;
        case PORT_SATA:
                break;
        }
-       return 1; /* Avoid bogus "control reaches end of non-void function" */
+       /* Avoid bogus "control reaches end of non-void function" */
+       return ATA_CBL_PATA80;
 }
 
 static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
@@ -159,8 +160,9 @@ static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
 
        hwif->ide_dma_check = &jmicron_config_drive_for_dma;
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66_jmicron(hwif);
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_jmicron(hwif);
 
        hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->autodma;
index 0765dce6948eb1f91cc39ce878bac44750776a11..ee5020df005d7515eaf7822c18515a34fb119fff 100644 (file)
@@ -225,7 +225,10 @@ static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 
 static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
 {
-       return get_indexed_reg(hwif, 0x0b) & 0x04;
+       if (get_indexed_reg(hwif, 0x0b) & 0x04)
+               return ATA_CBL_PATA40;
+       else
+               return ATA_CBL_PATA80;
 }
 
 static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
@@ -509,8 +512,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
 
        hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
 
-       if (!hwif->udma_four)
-               hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = pdcnew_cable_detect(hwif);
 
        if (!noautodma)
                hwif->autodma = 1;
index 23844687deea90a8d8a33efcb5486d7fabcb74df..41ac4a94959fb2c6fd1e4032cf599fe9370d84b4 100644 (file)
@@ -152,8 +152,10 @@ static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
 static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
 {
        u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+
        pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-       return (CIS & mask) ? 1 : 0;
+
+       return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 }
 
 /*
@@ -267,18 +269,24 @@ somebody_else:
        return (dma_stat & 4) == 4;     /* return 1 if INTR asserted */
 }
 
-static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
 {
-       if (HWIF(drive)->resetproc != NULL)
-               HWIF(drive)->resetproc(drive);
-       return __ide_dma_lostirq(drive);
+       ide_hwif_t *hwif = HWIF(drive);
+
+       if (hwif->resetproc != NULL)
+               hwif->resetproc(drive);
+
+       ide_dma_lost_irq(drive);
 }
 
-static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+static void pdc202xx_dma_timeout(ide_drive_t *drive)
 {
-       if (HWIF(drive)->resetproc != NULL)
-               HWIF(drive)->resetproc(drive);
-       return __ide_dma_timeout(drive);
+       ide_hwif_t *hwif = HWIF(drive);
+
+       if (hwif->resetproc != NULL)
+               hwif->resetproc(drive);
+
+       ide_dma_timeout(drive);
 }
 
 static void pdc202xx_reset_host (ide_hwif_t *hwif)
@@ -347,12 +355,13 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
        hwif->err_stops_fifo = 1;
 
        hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
-       hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
-       hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+       hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
+       hwif->dma_timeout = &pdc202xx_dma_timeout;
 
        if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
-               if (!(hwif->udma_four))
-                       hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+                       hwif->cbl = pdc202xx_old_cable_detect(hwif);
+
                hwif->dma_start = &pdc202xx_old_ide_dma_start;
                hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
        } 
index 8b219dd630241f4285512e61a9b417872c5147e8..2e0b29ef596a9a15039d43b04fb50566ba2a40ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/piix.c       Version 0.47    February 8, 2007
+ *  linux/drivers/ide/pci/piix.c       Version 0.50    Jun 10, 2007
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -394,14 +394,45 @@ static void piix_dma_clear_irq(ide_drive_t *drive)
        hwif->OUTB(dma_stat, hwif->dma_status);
 }
 
-static int __devinit piix_cable_detect(ide_hwif_t *hwif)
+struct ich_laptop {
+       u16 device;
+       u16 subvendor;
+       u16 subdevice;
+};
+
+/*
+ *     List of laptops that use short cables rather than 80 wire
+ */
+
+static const struct ich_laptop ich_laptop[] = {
+       /* devid, subvendor, subdev */
+       { 0x27DF, 0x0005, 0x0280 },     /* ICH7 on Acer 5602WLMi */
+       { 0x27DF, 0x1025, 0x0110 },     /* ICH7 on Acer 3682WLMi */
+       { 0x27DF, 0x1043, 0x1267 },     /* ICH7 on Asus W5F */
+       { 0x24CA, 0x1025, 0x0061 },     /* ICH4 on Acer Aspire 2023WLMi */
+       /* end marker */
+       { 0, }
+};
+
+static u8 __devinit piix_cable_detect(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *pdev = hwif->pci_dev;
+       const struct ich_laptop *lap = &ich_laptop[0];
        u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
 
-       pci_read_config_byte(dev, 0x54, &reg54h);
+       /* check for specials */
+       while (lap->device) {
+               if (lap->device == pdev->device &&
+                   lap->subvendor == pdev->subsystem_vendor &&
+                   lap->subdevice == pdev->subsystem_device) {
+                       return ATA_CBL_PATA40_SHORT;
+               }
+               lap++;
+       }
+
+       pci_read_config_byte(pdev, 0x54, &reg54h);
 
-       return (reg54h & mask) ? 1 : 0;
+       return (reg54h & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 }
 
 /**
@@ -444,8 +475,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
        hwif->swdma_mask = 0x04;
 
        if (hwif->ultra_mask & 0x78) {
-               if (!hwif->udma_four)
-                       hwif->udma_four = piix_cable_detect(hwif);
+               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+                       hwif->cbl = piix_cable_detect(hwif);
        }
 
        if (no_piix_dma)
index 55bc0a32e34f9d1b8781bef98a34461cce96ade8..7b87488e3daa831fee54fba1e4dc9f8d59c43b94 100644 (file)
@@ -716,7 +716,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
        hwif->atapi_dma = 1;
 
        /* we support 80c cable only. */
-       hwif->udma_four = 1;
+       hwif->cbl = ATA_CBL_PATA80;
 
        hwif->autodma = 0;
        if (!noautodma)
index d9c4fd1ae9969784144f10d073c7d078b490bbc6..1371b5bf6bf04b5537a7449fdcab0a0731465529 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/serverworks.c         Version 0.11    Jun 2 2007
+ * linux/drivers/ide/pci/serverworks.c         Version 0.20    Jun 3 2007
  *
  * Copyright (C) 1998-2000 Michel Aubry
  * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -151,84 +151,11 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&
                drive->media == ide_disk && speed >= XFER_UDMA_0)
                        BUG();
-                       
-       pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
-       pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
+
        pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
        pci_read_config_word(dev, 0x4A, &csb5_pio);
        pci_read_config_byte(dev, 0x54, &ultra_enable);
 
-       /* If we are in RAID mode (eg AMI MegaIDE) then we can't it
-          turns out trust the firmware configuration */
-
-       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               goto oem_setup_failed;
-
-       /* Per Specified Design by OEM, and ASIC Architect */
-       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
-           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
-               if (!drive->init_speed) {
-                       u8 dma_stat = inb(hwif->dma_status);
-
-                       if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
-                           ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
-                               drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
-                               return 0;
-                       } else if ((dma_timing) &&
-                                  ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
-                               u8 dmaspeed;
-
-                               switch (dma_timing & 0x77) {
-                               case 0x20:
-                                       dmaspeed = XFER_MW_DMA_2;
-                                       break;
-                               case 0x21:
-                                       dmaspeed = XFER_MW_DMA_1;
-                                       break;
-                               case 0x77:
-                                       dmaspeed = XFER_MW_DMA_0;
-                                       break;
-                               default:
-                                       goto dma_pio;
-                               }
-
-                               drive->current_speed = drive->init_speed = dmaspeed;
-                               return 0;
-                       }
-dma_pio:
-                       if (pio_timing) {
-                               u8 piospeed;
-
-                               switch (pio_timing & 0x7f) {
-                               case 0x20:
-                                       piospeed = XFER_PIO_4;
-                                       break;
-                               case 0x22:
-                                       piospeed = XFER_PIO_3;
-                                       break;
-                               case 0x34:
-                                       piospeed = XFER_PIO_2;
-                                       break;
-                               case 0x47:
-                                       piospeed = XFER_PIO_1;
-                                       break;
-                               case 0x5d:
-                                       piospeed = XFER_PIO_0;
-                                       break;
-                               default:
-                                       goto oem_setup_failed;
-                               }
-
-                               drive->current_speed = drive->init_speed = piospeed;
-                               return 0;
-                       }
-               }
-       }
-
-oem_setup_failed:
-
-       pio_timing      = 0;
-       dma_timing      = 0;
        ultra_timing    &= ~(0x0F << (4*unit));
        ultra_enable    &= ~(0x01 << drive->dn);
        csb5_pio        &= ~(0x0F << (4*drive->dn));
@@ -402,9 +329,9 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
        return dev->irq;
 }
 
-static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
+static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif)
 {
-       return 1;
+       return ATA_CBL_PATA80;
 }
 
 /* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
@@ -414,7 +341,7 @@ static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
+static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
@@ -422,8 +349,8 @@ static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
            (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
             dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
                return ((1 << (hwif->channel + 14)) &
-                       dev->subsystem_device) ? 1 : 0;
-       return 0;
+                       dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+       return ATA_CBL_PATA40;
 }
 
 /* Sun Cobalt Alpine hardware avoids the 80-pin cable
@@ -432,18 +359,18 @@ static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
  *
  * WARNING: this only works on Alpine hardware!
  */
-static unsigned int __devinit ata66_svwks_cobalt (ide_hwif_t *hwif)
+static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
            dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
            dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
                return ((1 << (hwif->channel + 14)) &
-                       dev->subsystem_device) ? 1 : 0;
-       return 0;
+                       dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+       return ATA_CBL_PATA40;
 }
 
-static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
+static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
 
@@ -462,9 +389,9 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
        /* Per Specified Design by OEM, and ASIC Architect */
        if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
            (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
-               return 1;
+               return ATA_CBL_PATA80;
 
-       return 0;
+       return ATA_CBL_PATA40;
 }
 
 static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
@@ -495,8 +422,8 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 
        hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
        if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-               if (!hwif->udma_four)
-                       hwif->udma_four = ata66_svwks(hwif);
+               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+                       hwif->cbl = ata66_svwks(hwif);
        }
        if (!noautodma)
                hwif->autodma = 1;
index d3185e29a38eef3c6763c68ef390e4b3aaa0ec69..d396b2929ed87791564600b85675d72eda7af774 100644 (file)
@@ -316,14 +316,6 @@ static void sgiioc4_dma_host_off(ide_drive_t * drive)
        sgiioc4_clearirq(drive);
 }
 
-static int
-sgiioc4_ide_dma_lostirq(ide_drive_t * drive)
-{
-       HWIF(drive)->resetproc(drive);
-
-       return __ide_dma_lostirq(drive);
-}
-
 static void
 sgiioc4_resetproc(ide_drive_t * drive)
 {
@@ -331,6 +323,14 @@ sgiioc4_resetproc(ide_drive_t * drive)
        sgiioc4_clearirq(drive);
 }
 
+static void
+sgiioc4_dma_lost_irq(ide_drive_t * drive)
+{
+       sgiioc4_resetproc(drive);
+
+       ide_dma_lost_irq(drive);
+}
+
 static u8
 sgiioc4_INB(unsigned long port)
 {
@@ -607,8 +607,8 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
        hwif->dma_host_on = &sgiioc4_dma_host_on;
        hwif->dma_host_off = &sgiioc4_dma_host_off;
-       hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
-       hwif->ide_dma_timeout = &__ide_dma_timeout;
+       hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
+       hwif->dma_timeout = &ide_dma_timeout;
 
        hwif->INB = &sgiioc4_INB;
 }
index 1a4444e7226aa840093e39779bc192eaed8d728f..1c3e354878934dd923116fe7a6723524057c8026 100644 (file)
@@ -933,16 +933,17 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif)
  *     interface.
  */
 
-static unsigned int __devinit ata66_siimage(ide_hwif_t *hwif)
+static u8 __devinit ata66_siimage(ide_hwif_t *hwif)
 {
        unsigned long addr = siimage_selreg(hwif, 0);
-       if (pci_get_drvdata(hwif->pci_dev) == NULL) {
-               u8 ata66 = 0;
+       u8 ata66 = 0;
+
+       if (pci_get_drvdata(hwif->pci_dev) == NULL)
                pci_read_config_byte(hwif->pci_dev, addr, &ata66);
-               return (ata66 & 0x01) ? 1 : 0;
-       }
+       else
+               ata66 = hwif->INB(addr);
 
-       return (hwif->INB(addr) & 0x01) ? 1 : 0;
+       return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 }
 
 /**
@@ -988,8 +989,9 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
                hwif->atapi_dma = 1;
 
        hwif->ide_dma_check = &siimage_config_drive_for_dma;
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66_siimage(hwif);
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_siimage(hwif);
 
        if (hwif->mmio) {
                hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
index ec0adad9ef6132928094a5774c06daedd52525d7..f875183ac8d9bfef0b338c06f6e567852e856d79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/sis5513.c     Version 0.20    Mar 4, 2007
+ * linux/drivers/ide/pci/sis5513.c     Version 0.25    Jun 10, 2007
  *
  * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2002          Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
@@ -796,10 +796,33 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
        return 0;
 }
 
-static unsigned int __devinit ata66_sis5513 (ide_hwif_t *hwif)
+struct sis_laptop {
+       u16 device;
+       u16 subvendor;
+       u16 subdevice;
+};
+
+static const struct sis_laptop sis_laptop[] = {
+       /* devid, subvendor, subdev */
+       { 0x5513, 0x1043, 0x1107 },     /* ASUS A6K */
+       /* end marker */
+       { 0, }
+};
+
+static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
 {
+       struct pci_dev *pdev = hwif->pci_dev;
+       const struct sis_laptop *lap = &sis_laptop[0];
        u8 ata66 = 0;
 
+       while (lap->device) {
+               if (lap->device == pdev->device &&
+                   lap->subvendor == pdev->subsystem_vendor &&
+                   lap->subdevice == pdev->subsystem_device)
+                       return ATA_CBL_PATA40_SHORT;
+               lap++;
+       }
+
        if (chipset_family >= ATA_133) {
                u16 regw = 0;
                u16 reg_addr = hwif->channel ? 0x52: 0x50;
@@ -811,7 +834,8 @@ static unsigned int __devinit ata66_sis5513 (ide_hwif_t *hwif)
                pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
                ata66 = (reg48h & mask) ? 0 : 1;
        }
-        return ata66;
+
+       return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 }
 
 static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
@@ -841,8 +865,8 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
        if (!chipset_family)
                return;
 
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66_sis5513(hwif);
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_sis5513(hwif);
 
        if (chipset_family > ATA_16) {
                hwif->ide_dma_check = &sis5513_config_xfer_rate;
index 7c383d9cc4727344a2a28d627e016c09fba7841b..487879842af495959cbfcb92900c6bbe81f8f6e1 100644 (file)
@@ -195,7 +195,7 @@ static inline void sl82c105_reset_host(struct pci_dev *dev)
  * This function is called when the IDE timer expires, the drive
  * indicates that it is READY, and we were waiting for DMA to complete.
  */
-static int sl82c105_ide_dma_lostirq(ide_drive_t *drive)
+static void sl82c105_dma_lost_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -222,9 +222,6 @@ static int sl82c105_ide_dma_lostirq(ide_drive_t *drive)
        }
 
        sl82c105_reset_host(dev);
-
-       /* __ide_dma_lostirq would return 1, so we do as well */
-       return 1;
 }
 
 /*
@@ -244,15 +241,12 @@ static void sl82c105_dma_start(ide_drive_t *drive)
        ide_dma_start(drive);
 }
 
-static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
+static void sl82c105_dma_timeout(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name));
 
-       DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name));
-
-       sl82c105_reset_host(dev);
-       return __ide_dma_timeout(drive);
+       sl82c105_reset_host(HWIF(drive)->pci_dev);
+       ide_dma_timeout(drive);
 }
 
 static int sl82c105_ide_dma_on(ide_drive_t *drive)
@@ -441,9 +435,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
        hwif->ide_dma_check             = &sl82c105_ide_dma_check;
        hwif->ide_dma_on                = &sl82c105_ide_dma_on;
        hwif->dma_off_quietly           = &sl82c105_dma_off_quietly;
-       hwif->ide_dma_lostirq           = &sl82c105_ide_dma_lostirq;
+       hwif->dma_lost_irq              = &sl82c105_dma_lost_irq;
        hwif->dma_start                 = &sl82c105_dma_start;
-       hwif->ide_dma_timeout           = &sl82c105_ide_dma_timeout;
+       hwif->dma_timeout               = &sl82c105_dma_timeout;
 
        if (!noautodma)
                hwif->autodma = 1;
index c40f291f91e04c62cce013882abcc67ef53ad05d..575dbbd8b482edb345960fc5e56ecbf87ed39693 100644 (file)
@@ -199,10 +199,9 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x06;
        hwif->swdma_mask = 0x04;
 
-       if (!hwif->udma_four) {
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
                /* bit[0(1)]: 0:80, 1:40 */
-               hwif->udma_four = (reg47 & mask) ? 0 : 1;
-       }
+               hwif->cbl = (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 
        hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
 
index cee619bb2eaf8a7713ccc7582acb48b22f4c10e8..8de1f8e224946b589fb173df6d572499598eecb2 100644 (file)
@@ -220,13 +220,13 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
        hwif->ide_dma_check     = &tc86c001_config_drive_xfer_rate;
        hwif->dma_start         = &tc86c001_dma_start;
 
-       if (!hwif->udma_four) {
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
                /*
                 * System Control  1 Register bit 13 (PDIAGN):
                 * 0=80-pin cable, 1=40-pin cable
                 */
                scr1 = hwif->INW(sc_base + 0x00);
-               hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+               hwif->cbl = (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
        }
 
        if (!noautodma)
index a508550c4095cecb0a43ffb474ca4d94b531d30b..d21dd2e7eeb3cbba63970a0bfc61768ed906207e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * Version 3.38
+ * Version 3.45
  *
  * VIA IDE driver for Linux. Supported southbridges:
  *
@@ -9,6 +9,7 @@
  *   vt8235, vt8237, vt8237a
  *
  * Copyright (c) 2000-2002 Vojtech Pavlik
+ * Copyright (c) 2007 Bartlomiej Zolnierkiewicz
  *
  * Based on the work of:
  *     Michel Aubry
@@ -33,6 +34,8 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/dmi.h>
+
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_CHRP
@@ -41,8 +44,6 @@
 
 #include "ide-timing.h"
 
-#define DISPLAY_VIA_TIMINGS
-
 #define VIA_IDE_ENABLE         0x40
 #define VIA_IDE_CONFIG         0x41
 #define VIA_FIFO_CONFIG                0x43
 #define VIA_ADDRESS_SETUP      0x4c
 #define VIA_UDMA_TIMING                0x50
 
-#define VIA_UDMA               0x007
-#define VIA_UDMA_NONE          0x000
-#define VIA_UDMA_33            0x001
-#define VIA_UDMA_66            0x002
-#define VIA_UDMA_100           0x003
-#define VIA_UDMA_133           0x004
-#define VIA_BAD_PREQ           0x010   /* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66          0x020   /* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO           0x040   /* Needs to have FIFO split set */
-#define VIA_NO_UNMASK          0x080   /* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID             0x100   /* Has wrong vendor ID (0x1107) */
-#define VIA_BAD_AST            0x200   /* Don't touch Address Setup Timing */
+#define VIA_BAD_PREQ           0x01 /* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66          0x02 /* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO           0x04 /* Needs to have FIFO split set */
+#define VIA_NO_UNMASK          0x08 /* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID             0x10 /* Has wrong vendor ID (0x1107) */
+#define VIA_BAD_AST            0x20 /* Don't touch Address Setup Timing */
 
 /*
  * VIA SouthBridge chips.
@@ -76,36 +71,37 @@ static struct via_isa_bridge {
        u16 id;
        u8 rev_min;
        u8 rev_max;
-       u16 flags;
+       u8 udma_mask;
+       u8 flags;
 } via_isa_bridges[] = {
-       { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8233a",    PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
-       { "vt8233c",    PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
-       { "vt8233",     PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-       { "vt8231",     PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
-       { "vt82c686b",  PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
-       { "vt82c686a",  PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
-       { "vt82c686",   PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-       { "vt82c596b",  PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
-       { "vt82c596a",  PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
-       { "vt82c586a",  PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
-       { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
-       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+       { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8233a",    PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+       { "vt8233c",    PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, ATA_UDMA5, },
+       { "vt8233",     PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, ATA_UDMA5, },
+       { "vt8231",     PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, ATA_UDMA5, },
+       { "vt82c686b",  PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, ATA_UDMA5, },
+       { "vt82c686a",  PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, ATA_UDMA4, },
+       { "vt82c686",   PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+       { "vt82c596b",  PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, ATA_UDMA4, },
+       { "vt82c596a",  PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
+       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
+       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
+       { "vt82c586a",  PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
+       { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f,      0x00, VIA_SET_FIFO },
+       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f,      0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
+       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f,      0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
        { NULL }
 };
 
 static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+static char *via_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
 
 struct via82cxxx_dev
 {
@@ -140,12 +136,12 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
        pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
                ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
 
-       switch (vdev->via_config->flags & VIA_UDMA) {
-               case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-               case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
-               case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-               case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-               default: return;
+       switch (vdev->via_config->udma_mask) {
+       case ATA_UDMA2: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+       case ATA_UDMA4: t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+       case ATA_UDMA5: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+       case ATA_UDMA6: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+       default: return;
        }
 
        pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
@@ -173,12 +169,12 @@ static int via_set_drive(ide_drive_t *drive, u8 speed)
 
        T = 1000000000 / via_clock;
 
-       switch (vdev->via_config->flags & VIA_UDMA) {
-               case VIA_UDMA_33:   UT = T;   break;
-               case VIA_UDMA_66:   UT = T/2; break;
-               case VIA_UDMA_100:  UT = T/3; break;
-               case VIA_UDMA_133:  UT = T/4; break;
-               default: UT = T;
+       switch (vdev->via_config->udma_mask) {
+       case ATA_UDMA2: UT = T;   break;
+       case ATA_UDMA4: UT = T/2; break;
+       case ATA_UDMA5: UT = T/3; break;
+       case ATA_UDMA6: UT = T/4; break;
+       default:        UT = T;
        }
 
        ide_timing_compute(drive, speed, &t, T, UT);
@@ -208,8 +204,7 @@ static int via_set_drive(ide_drive_t *drive, u8 speed)
 static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
 {
        if (pio == 255) {
-               via_set_drive(drive,
-                       ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+               via_set_drive(drive, ide_find_best_pio_mode(drive));
                return;
        }
 
@@ -226,16 +221,10 @@ static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
  
 static int via82cxxx_ide_dma_check (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
-       u16 w80 = hwif->udma_four;
+       u8 speed = ide_max_dma_mode(drive);
 
-       u16 speed = ide_find_best_mode(drive,
-               XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-               (vdev->via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-               (w80 && (vdev->via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-               (w80 && (vdev->via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-               (w80 && (vdev->via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+       if (speed == 0)
+               speed = ide_find_best_pio_mode(drive);
 
        via_set_drive(drive, speed);
 
@@ -272,8 +261,8 @@ static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
 {
        int i;
 
-       switch (vdev->via_config->flags & VIA_UDMA) {
-               case VIA_UDMA_66:
+       switch (vdev->via_config->udma_mask) {
+               case ATA_UDMA4:
                        for (i = 24; i >= 0; i -= 8)
                                if (((u >> (i & 16)) & 8) &&
                                    ((u >> i) & 0x20) &&
@@ -286,7 +275,7 @@ static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
                                }
                        break;
 
-               case VIA_UDMA_100:
+               case ATA_UDMA5:
                        for (i = 24; i >= 0; i -= 8)
                                if (((u >> i) & 0x10) ||
                                    (((u >> i) & 0x20) &&
@@ -298,7 +287,7 @@ static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
                                }
                        break;
 
-               case VIA_UDMA_133:
+               case ATA_UDMA6:
                        for (i = 24; i >= 0; i -= 8)
                                if (((u >> i) & 0x10) ||
                                    (((u >> i) & 0x20) &&
@@ -353,7 +342,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
 
        via_cable_detect(vdev, u);
 
-       if ((via_config->flags & VIA_UDMA) == VIA_UDMA_66) {
+       if (via_config->udma_mask == ATA_UDMA4) {
                /* Enable Clk66 */
                pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
        } else if (via_config->flags & VIA_BAD_CLK66) {
@@ -416,16 +405,54 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
         */
 
        pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-       printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s "
+       printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %sDMA%s "
                "controller on pci%s\n",
                via_config->name, t,
-               via_dma[via_config->flags & VIA_UDMA],
+               via_config->udma_mask ? "U" : "MW",
+               via_dma[via_config->udma_mask ?
+                       (fls(via_config->udma_mask) - 1) : 0],
                pci_name(dev));
 
        pci_dev_put(isa);
        return 0;
 }
 
+/*
+ *     Cable special cases
+ */
+
+static struct dmi_system_id cable_dmi_table[] = {
+       {
+               .ident = "Acer Ferrari 3400",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"),
+               },
+       },
+       { }
+};
+
+static int via_cable_override(void)
+{
+       /* Systems by DMI */
+       if (dmi_check_system(cable_dmi_table))
+               return 1;
+       return 0;
+}
+
+static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
+{
+       struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
+
+       if (via_cable_override())
+               return ATA_CBL_PATA40_SHORT;
+
+       if ((vdev->via_80w >> hwif->channel) & 1)
+               return ATA_CBL_PATA80;
+       else
+               return ATA_CBL_PATA40;
+}
+
 static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
 {
        struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
@@ -454,12 +481,14 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
                return;
 
        hwif->atapi_dma = 1;
-       hwif->ultra_mask = 0x7f;
+
+       hwif->ultra_mask = vdev->via_config->udma_mask;
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
-       if (!hwif->udma_four)
-               hwif->udma_four = (vdev->via_80w >> hwif->channel) & 1;
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = via82cxxx_cable_detect(hwif);
+
        hwif->ide_dma_check = &via82cxxx_ide_dma_check;
        if (!noautodma)
                hwif->autodma = 1;
index 45fc36f0f219feaba9649978c69d697966e2ba57..e46f47206542bfec313086e5feab745b62131562 100644 (file)
@@ -942,8 +942,8 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
                                return 1;
                case XFER_UDMA_4:
                case XFER_UDMA_3:
-                       if (HWIF(drive)->udma_four == 0)
-                               return 1;               
+                       if (drive->hwif->cbl != ATA_CBL_PATA80)
+                               return 1;
                case XFER_UDMA_2:
                case XFER_UDMA_1:
                case XFER_UDMA_0:
@@ -1244,7 +1244,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        hwif->chipset = ide_pmac;
        hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
        hwif->hold = pmif->mediabay;
-       hwif->udma_four = pmif->cable_80;
+       hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
        hwif->drives[0].unmask = 1;
        hwif->drives[1].unmask = 1;
        hwif->tuneproc = pmac_ide_tuneproc;
@@ -1821,28 +1821,11 @@ pmac_ide_dma_check(ide_drive_t *drive)
                enable = 0;
 
        if (enable) {
-               short mode;
-               
-               map = XFER_MWDMA;
-               if (pmif->kind == controller_kl_ata4
-                   || pmif->kind == controller_un_ata6
-                   || pmif->kind == controller_k2_ata6
-                   || pmif->kind == controller_sh_ata6) {
-                       map |= XFER_UDMA;
-                       if (pmif->cable_80) {
-                               map |= XFER_UDMA_66;
-                               if (pmif->kind == controller_un_ata6 ||
-                                   pmif->kind == controller_k2_ata6 ||
-                                   pmif->kind == controller_sh_ata6)
-                                       map |= XFER_UDMA_100;
-                               if (pmif->kind == controller_sh_ata6)
-                                       map |= XFER_UDMA_133;
-                       }
-               }
-               mode = ide_find_best_mode(drive, map);
-               if (mode & XFER_UDMA)
+               u8 mode = ide_max_dma_mode(drive);
+
+               if (mode >= XFER_UDMA_0)
                        drive->using_dma = pmac_ide_udma_enable(drive, mode);
-               else if (mode & XFER_MWDMA)
+               else if (mode >= XFER_MW_DMA_0)
                        drive->using_dma = pmac_ide_mdma_enable(drive, mode);
                hwif->OUTB(0, IDE_CONTROL_REG);
                /* Apply settings to controller */
@@ -2004,20 +1987,19 @@ static void pmac_ide_dma_host_on(ide_drive_t *drive)
 {
 }
 
-static int
-pmac_ide_dma_lostirq (ide_drive_t *drive)
+static void
+pmac_ide_dma_lost_irq (ide_drive_t *drive)
 {
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
        volatile struct dbdma_regs __iomem *dma;
        unsigned long status;
 
        if (pmif == NULL)
-               return 0;
+               return;
        dma = pmif->dma_regs;
 
        status = readl(&dma->status);
        printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
-       return 0;
 }
 
 /*
@@ -2057,8 +2039,8 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
        hwif->dma_host_off = &pmac_ide_dma_host_off;
        hwif->dma_host_on = &pmac_ide_dma_host_on;
-       hwif->ide_dma_timeout = &__ide_dma_timeout;
-       hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq;
+       hwif->dma_timeout = &ide_dma_timeout;
+       hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
 
        hwif->atapi_dma = 1;
        switch(pmif->kind) {
index 20814137761220e5ebbf00dd86e2ee0e21421a3e..65722117ab6e449b7cf2445a286d1e63131fcb4f 100644 (file)
@@ -2280,7 +2280,7 @@ static void dv1394_remove_host(struct hpsb_host *host)
        } while (video);
 
        if (found_ohci_card)
-               class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+               device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
                           IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
 }
 
@@ -2295,9 +2295,9 @@ static void dv1394_add_host(struct hpsb_host *host)
 
        ohci = (struct ti_ohci *)host->hostdata;
 
-       class_device_create(hpsb_protocol_class, NULL, MKDEV(
-               IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), 
-               NULL, "dv1394-%d", id);
+       device_create(hpsb_protocol_class, NULL, MKDEV(
+               IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
+               "dv1394-%d", id);
 
        dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
        dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
index 7c13fb3c167b02b541834283d272d1a5a17f5860..93362eed94eda0be345958ab069f0f78935c6443 100644 (file)
@@ -599,9 +599,7 @@ static void ether1394_add_host(struct hpsb_host *host)
        }
 
        SET_MODULE_OWNER(dev);
-
-       /* This used to be &host->device in Linux 2.6.20 and before. */
-       SET_NETDEV_DEV(dev, host->device.parent);
+       SET_NETDEV_DEV(dev, &host->device);
 
        priv = netdev_priv(dev);
        INIT_LIST_HEAD(&priv->ip_node_list);
index 83a49331275188e265346f2ed70e753c2f52a010..b6425469b6ee455ef0690f1bb5dc7653a15e37d6 100644 (file)
@@ -483,37 +483,6 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
        return retval;
 }
 
-/**
- * hpsb_listen_channel - enable receving a certain isochronous channel
- *
- * Reception is handled through the @hl's iso_receive op.
- */
-int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                       unsigned int channel)
-{
-       if (channel > 63) {
-               HPSB_ERR("%s called with invalid channel", __FUNCTION__);
-               return -EINVAL;
-       }
-       if (host->iso_listen_count[channel]++ == 0)
-               return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
-       return 0;
-}
-
-/**
- * hpsb_unlisten_channel - disable receving a certain isochronous channel
- */
-void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                          unsigned int channel)
-{
-       if (channel > 63) {
-               HPSB_ERR("%s called with invalid channel", __FUNCTION__);
-               return;
-       }
-       if (--host->iso_listen_count[channel] == 0)
-               host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
-}
-
 static void init_hpsb_highlevel(struct hpsb_host *host)
 {
        INIT_LIST_HEAD(&dummy_zero_addr.host_list);
@@ -570,20 +539,6 @@ void highlevel_host_reset(struct hpsb_host *host)
        read_unlock_irqrestore(&hl_irqs_lock, flags);
 }
 
-void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length)
-{
-       unsigned long flags;
-       struct hpsb_highlevel *hl;
-       int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
-
-       read_lock_irqsave(&hl_irqs_lock, flags);
-       list_for_each_entry(hl, &hl_irqs, irq_list) {
-               if (hl->iso_receive)
-                       hl->iso_receive(host, channel, data, length);
-       }
-       read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
                           void *data, size_t length)
 {
index 63474f7ee69d5ac48bf1a6d8670e7450fcb53cc7..eb9fe321e09a37507c6527df82c7abd352db0b2a 100644 (file)
@@ -26,9 +26,7 @@ struct hpsb_address_serve {
 struct hpsb_highlevel {
        const char *name;
 
-       /* Any of the following pointers can legally be NULL, except for
-        * iso_receive which can only be NULL when you don't request
-        * channels. */
+       /* Any of the following pointers can legally be NULL. */
 
        /* New host initialized.  Will also be called during
         * hpsb_register_highlevel for all hosts already installed. */
@@ -43,13 +41,6 @@ struct hpsb_highlevel {
         * You can not expect to be able to do stock hpsb_reads. */
        void (*host_reset)(struct hpsb_host *host);
 
-       /* An isochronous packet was received.  Channel contains the channel
-        * number for your convenience, it is also contained in the included
-        * packet header (first quadlet, CRCs are missing).  You may get called
-        * for channel/host combinations you did not request. */
-       void (*iso_receive)(struct hpsb_host *host, int channel,
-                           quadlet_t *data, size_t length);
-
        /* A write request was received on either the FCP_COMMAND (direction =
         * 0) or the FCP_RESPONSE (direction = 1) register.  The cts arg
         * contains the cts field (first byte of data). */
@@ -109,7 +100,6 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
                     u16 flags);
-void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length);
 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
                           void *data, size_t length);
 
@@ -125,10 +115,6 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
                            struct hpsb_address_ops *ops, u64 start, u64 end);
 int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
                              u64 start);
-int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                       unsigned int channel);
-void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
-                          unsigned int channel);
 
 void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
 void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
index bd0755c789c52d469fd85aa842398117bccc0909..8dd09d8504196eecbe750887ec23f702667b105d 100644 (file)
@@ -154,15 +154,16 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
 
        memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
        h->device.parent = dev;
+       set_dev_node(&h->device, dev_to_node(dev));
        snprintf(h->device.bus_id, BUS_ID_SIZE, "fw-host%d", h->id);
 
-       h->class_dev.dev = &h->device;
-       h->class_dev.class = &hpsb_host_class;
-       snprintf(h->class_dev.class_id, BUS_ID_SIZE, "fw-host%d", h->id);
+       h->host_dev.parent = &h->device;
+       h->host_dev.class = &hpsb_host_class;
+       snprintf(h->host_dev.bus_id, BUS_ID_SIZE, "fw-host%d", h->id);
 
        if (device_register(&h->device))
                goto fail;
-       if (class_device_register(&h->class_dev)) {
+       if (device_register(&h->host_dev)) {
                device_unregister(&h->device);
                goto fail;
        }
@@ -202,7 +203,7 @@ void hpsb_remove_host(struct hpsb_host *host)
        host->driver = &dummy_driver;
        highlevel_remove_host(host);
 
-       class_device_unregister(&host->class_dev);
+       device_unregister(&host->host_dev);
        device_unregister(&host->device);
 }
 
index feb55d032294f0559e17d655dbe20d501d311a47..e4e8aeb4d7788d2caf2ef7d5821dbf77a038c27d 100644 (file)
@@ -28,8 +28,6 @@ struct hpsb_host {
        struct timer_list timeout;
        unsigned long timeout_interval;
 
-       unsigned char iso_listen_count[64];
-
        int node_count;      /* number of identified nodes on this bus */
        int selfid_count;    /* total number of SelfIDs received */
        int nodes_active;    /* number of nodes with active link layer */
@@ -57,7 +55,7 @@ struct hpsb_host {
        struct hpsb_host_driver *driver;
        struct pci_dev *pdev;
        struct device device;
-       struct class_device class_dev;
+       struct device host_dev;
 
        struct delayed_work delayed_reset;
        unsigned config_roms:31;
@@ -99,12 +97,6 @@ enum devctl_cmd {
        /* Cancel all outstanding async requests without resetting the bus.
         * Return void. */
        CANCEL_REQUESTS,
-
-       /* Start or stop receiving isochronous channel in arg.  Return void.
-        * This acts as an optimization hint, hosts are not required not to
-        * listen on unrequested channels. */
-       ISO_LISTEN_CHANNEL,
-       ISO_UNLISTEN_CHANNEL
 };
 
 enum isoctl_cmd {
index 8f71b6a06aa0b45cbb8dcef0aca25e4ecfb33ddd..0fc8c6e559e4a64d160bfbc0c7fcd4a04d8538e5 100644 (file)
@@ -1028,11 +1028,6 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
                handle_incoming_packet(host, tcode, data, size, write_acked);
                break;
 
-
-       case TCODE_ISO_DATA:
-               highlevel_iso_receive(host, data, size);
-               break;
-
        case TCODE_CYCLE_START:
                /* simply ignore this packet if it is passed on */
                break;
@@ -1316,7 +1311,6 @@ EXPORT_SYMBOL(hpsb_make_streampacket);
 EXPORT_SYMBOL(hpsb_make_lockpacket);
 EXPORT_SYMBOL(hpsb_make_lock64packet);
 EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_make_isopacket);
 EXPORT_SYMBOL(hpsb_read);
 EXPORT_SYMBOL(hpsb_write);
 EXPORT_SYMBOL(hpsb_packet_success);
@@ -1327,8 +1321,6 @@ EXPORT_SYMBOL(hpsb_unregister_highlevel);
 EXPORT_SYMBOL(hpsb_register_addrspace);
 EXPORT_SYMBOL(hpsb_unregister_addrspace);
 EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
-EXPORT_SYMBOL(hpsb_listen_channel);
-EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(hpsb_get_hostinfo);
 EXPORT_SYMBOL(hpsb_create_hostinfo);
 EXPORT_SYMBOL(hpsb_destroy_hostinfo);
index ad526523d0ef85fa556beda8b8b63d2e01fab424..21d50f73a210cbadfc6c39e128da8e06d0fa9310 100644 (file)
@@ -24,9 +24,8 @@ struct hpsb_packet {
 
        nodeid_t node_id;
 
-       /* Async and Iso types should be clear, raw means send-as-is, do not
-        * CRC!  Byte swapping shall still be done in this case. */
-       enum { hpsb_async, hpsb_iso, hpsb_raw } __attribute__((packed)) type;
+       /* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
+       enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
 
        /* Okay, this is core internal and a no care for hosts.
         * queued   = queued for sending
@@ -37,7 +36,7 @@ struct hpsb_packet {
                hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
        } __attribute__((packed)) state;
 
-       /* These are core internal. */
+       /* These are core-internal. */
        signed char tlabel;
        signed char ack_code;
        unsigned char tcode;
@@ -62,11 +61,15 @@ struct hpsb_packet {
        /* Store jiffies for implementing bus timeouts. */
        unsigned long sendtime;
 
-       /* Sizes are in bytes. *data can be DMA-mapped. */
+       /* Core-internal.  */
        size_t allocated_data_size;     /* as allocated */
+
+       /* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
        size_t data_size;               /* as filled in */
        size_t header_size;             /* as filled in, not counting the CRC */
-       quadlet_t *data;
+
+       /* Buffers */
+       quadlet_t *data;                /* can be DMA-mapped */
        quadlet_t header[5];
        quadlet_t embedded_data[0];     /* keep as last member */
 };
index 40078ce930c86035ea2d5453ebc0f85851dd1fa1..c39c70a8aa9fce1e8eae54cdd0df6ab3a0c4a1e5 100644 (file)
@@ -89,18 +89,6 @@ static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
        packet->expect_response = 1;
 }
 
-static void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
-                           int tag, int sync)
-{
-       packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
-           | (TCODE_ISO_DATA << 4) | sync;
-
-       packet->header_size = 4;
-       packet->data_size = length;
-       packet->type = hpsb_iso;
-       packet->tcode = TCODE_ISO_DATA;
-}
-
 static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
 {
        packet->header[0] = data;
@@ -491,24 +479,6 @@ struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
        return p;
 }
 
-struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
-                                       int length, int channel,
-                                       int tag, int sync)
-{
-       struct hpsb_packet *p;
-
-       p = hpsb_alloc_packet(length);
-       if (!p)
-               return NULL;
-
-       p->host = host;
-       fill_iso_packet(p, length, channel, tag, sync);
-
-       p->generation = get_hpsb_generation(host);
-
-       return p;
-}
-
 /*
  * FIXME - these functions should probably read from / write to user space to
  * avoid in kernel buffers for user space callers
index 86b8ee692ea7711bc868c407e816871ce7b6c969..d2d5bc3546d74093b2fe0ce56ef913b63ef6648e 100644 (file)
@@ -19,8 +19,6 @@ struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
                                           nodeid_t node, u64 addr, int extcode,
                                           octlet_t *data, octlet_t arg);
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
-struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, int length,
-                                       int channel, int tag, int sync);
 struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
                                          nodeid_t node, u64 addr,
                                          quadlet_t *buffer, size_t length);
index 81b3864d2ba785b51b25d597965a608ff7879fcb..c4d3d4131f01728725496526687de8a55906bc20 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/freezer.h>
 #include <asm/atomic.h>
+#include <asm/semaphore.h>
 
 #include "csr.h"
 #include "highlevel.h"
@@ -145,8 +146,6 @@ static struct csr1212_bus_ops nodemgr_csr_ops = {
  * but now we are much simpler because of the LDM.
  */
 
-static DEFINE_MUTEX(nodemgr_serialize);
-
 struct host_info {
        struct hpsb_host *host;
        struct list_head list;
@@ -154,7 +153,7 @@ struct host_info {
 };
 
 static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
+static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
                          char *buffer, int buffer_size);
 static void nodemgr_resume_ne(struct node_entry *ne);
 static void nodemgr_remove_ne(struct node_entry *ne);
@@ -165,37 +164,38 @@ struct bus_type ieee1394_bus_type = {
        .match          = nodemgr_bus_match,
 };
 
-static void host_cls_release(struct class_device *class_dev)
+static void host_cls_release(struct device *dev)
 {
-       put_device(&container_of((class_dev), struct hpsb_host, class_dev)->device);
+       put_device(&container_of((dev), struct hpsb_host, host_dev)->device);
 }
 
 struct class hpsb_host_class = {
        .name           = "ieee1394_host",
-       .release        = host_cls_release,
+       .dev_release    = host_cls_release,
 };
 
-static void ne_cls_release(struct class_device *class_dev)
+static void ne_cls_release(struct device *dev)
 {
-       put_device(&container_of((class_dev), struct node_entry, class_dev)->device);
+       put_device(&container_of((dev), struct node_entry, node_dev)->device);
 }
 
 static struct class nodemgr_ne_class = {
        .name           = "ieee1394_node",
-       .release        = ne_cls_release,
+       .dev_release    = ne_cls_release,
 };
 
-static void ud_cls_release(struct class_device *class_dev)
+static void ud_cls_release(struct device *dev)
 {
-       put_device(&container_of((class_dev), struct unit_directory, class_dev)->device);
+       put_device(&container_of((dev), struct unit_directory, unit_dev)->device);
 }
 
 /* The name here is only so that unit directory hotplug works with old
- * style hotplug, which only ever did unit directories anyway. */
+ * style hotplug, which only ever did unit directories anyway.
+ */
 static struct class nodemgr_ud_class = {
        .name           = "ieee1394",
-       .release        = ud_cls_release,
-       .uevent         = nodemgr_uevent,
+       .dev_release    = ud_cls_release,
+       .dev_uevent     = nodemgr_uevent,
 };
 
 static struct hpsb_highlevel nodemgr_highlevel;
@@ -730,11 +730,11 @@ static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
 
 static void nodemgr_remove_uds(struct node_entry *ne)
 {
-       struct class_device *cdev;
+       struct device *dev;
        struct unit_directory *tmp, *ud;
 
-       /* Iteration over nodemgr_ud_class.children has to be protected by
-        * nodemgr_ud_class.sem, but class_device_unregister() will eventually
+       /* Iteration over nodemgr_ud_class.devices has to be protected by
+        * nodemgr_ud_class.sem, but device_unregister() will eventually
         * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
         * release the semaphore, and then unregister the ud. Since this code
         * may be called from other contexts besides the knodemgrds, protect the
@@ -744,9 +744,9 @@ static void nodemgr_remove_uds(struct node_entry *ne)
        for (;;) {
                ud = NULL;
                down(&nodemgr_ud_class.sem);
-               list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-                       tmp = container_of(cdev, struct unit_directory,
-                                          class_dev);
+               list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+                       tmp = container_of(dev, struct unit_directory,
+                                          unit_dev);
                        if (tmp->ne == ne) {
                                ud = tmp;
                                break;
@@ -755,7 +755,7 @@ static void nodemgr_remove_uds(struct node_entry *ne)
                up(&nodemgr_ud_class.sem);
                if (ud == NULL)
                        break;
-               class_device_unregister(&ud->class_dev);
+               device_unregister(&ud->unit_dev);
                device_unregister(&ud->device);
        }
        mutex_unlock(&nodemgr_serialize_remove_uds);
@@ -772,10 +772,9 @@ static void nodemgr_remove_ne(struct node_entry *ne)
 
        HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
                   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
-
        nodemgr_remove_uds(ne);
 
-       class_device_unregister(&ne->class_dev);
+       device_unregister(&ne->node_dev);
        device_unregister(dev);
 
        put_device(dev);
@@ -783,7 +782,9 @@ static void nodemgr_remove_ne(struct node_entry *ne)
 
 static int __nodemgr_remove_host_dev(struct device *dev, void *data)
 {
-       nodemgr_remove_ne(container_of(dev, struct node_entry, device));
+       if (dev->bus == &ieee1394_bus_type)
+               nodemgr_remove_ne(container_of(dev, struct node_entry,
+                                 device));
        return 0;
 }
 
@@ -850,14 +851,14 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
        snprintf(ne->device.bus_id, BUS_ID_SIZE, "%016Lx",
                 (unsigned long long)(ne->guid));
 
-       ne->class_dev.dev = &ne->device;
-       ne->class_dev.class = &nodemgr_ne_class;
-       snprintf(ne->class_dev.class_id, BUS_ID_SIZE, "%016Lx",
-                (unsigned long long)(ne->guid));
+       ne->node_dev.parent = &ne->device;
+       ne->node_dev.class = &nodemgr_ne_class;
+       snprintf(ne->node_dev.bus_id, BUS_ID_SIZE, "%016Lx",
+               (unsigned long long)(ne->guid));
 
        if (device_register(&ne->device))
                goto fail_devreg;
-       if (class_device_register(&ne->class_dev))
+       if (device_register(&ne->node_dev))
                goto fail_classdevreg;
        get_device(&ne->device);
 
@@ -885,12 +886,12 @@ fail_alloc:
 
 static struct node_entry *find_entry_by_guid(u64 guid)
 {
-       struct class_device *cdev;
+       struct device *dev;
        struct node_entry *ne, *ret_ne = NULL;
 
        down(&nodemgr_ne_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
+       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+               ne = container_of(dev, struct node_entry, node_dev);
 
                if (ne->guid == guid) {
                        ret_ne = ne;
@@ -906,12 +907,12 @@ static struct node_entry *find_entry_by_guid(u64 guid)
 static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
                                               nodeid_t nodeid)
 {
-       struct class_device *cdev;
+       struct device *dev;
        struct node_entry *ne, *ret_ne = NULL;
 
        down(&nodemgr_ne_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
+       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+               ne = container_of(dev, struct node_entry, node_dev);
 
                if (ne->host == host && ne->nodeid == nodeid) {
                        ret_ne = ne;
@@ -935,14 +936,14 @@ static void nodemgr_register_device(struct node_entry *ne,
        snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
                 ne->device.bus_id, ud->id);
 
-       ud->class_dev.dev = &ud->device;
-       ud->class_dev.class = &nodemgr_ud_class;
-       snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
+       ud->unit_dev.parent = &ud->device;
+       ud->unit_dev.class = &nodemgr_ud_class;
+       snprintf(ud->unit_dev.bus_id, BUS_ID_SIZE, "%s-%u",
                 ne->device.bus_id, ud->id);
 
        if (device_register(&ud->device))
                goto fail_devreg;
-       if (class_device_register(&ud->class_dev))
+       if (device_register(&ud->unit_dev))
                goto fail_classdevreg;
        get_device(&ud->device);
 
@@ -1159,7 +1160,7 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
 
 #ifdef CONFIG_HOTPLUG
 
-static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
+static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
                          char *buffer, int buffer_size)
 {
        struct unit_directory *ud;
@@ -1169,10 +1170,10 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
        /* ieee1394:venNmoNspNverN */
        char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
 
-       if (!cdev)
+       if (!dev)
                return -ENODEV;
 
-       ud = container_of(cdev, struct unit_directory, class_dev);
+       ud = container_of(dev, struct unit_directory, unit_dev);
 
        if (ud->ne->in_limbo || ud->ignore_driver)
                return -ENODEV;
@@ -1207,7 +1208,7 @@ do {                                                              \
 
 #else
 
-static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
+static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
                          char *buffer, int buffer_size)
 {
        return -ENODEV;
@@ -1378,8 +1379,10 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
 
 static void nodemgr_suspend_ne(struct node_entry *ne)
 {
-       struct class_device *cdev;
+       struct device *dev;
        struct unit_directory *ud;
+       struct device_driver *drv;
+       int error;
 
        HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
                   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
@@ -1388,15 +1391,24 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
        WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
 
        down(&nodemgr_ud_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-               ud = container_of(cdev, struct unit_directory, class_dev);
+       list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+               ud = container_of(dev, struct unit_directory, unit_dev);
                if (ud->ne != ne)
                        continue;
 
-               if (ud->device.driver &&
-                   (!ud->device.driver->suspend ||
-                     ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
+               drv = get_driver(ud->device.driver);
+               if (!drv)
+                       continue;
+
+               error = 1; /* release if suspend is not implemented */
+               if (drv->suspend) {
+                       down(&ud->device.sem);
+                       error = drv->suspend(&ud->device, PMSG_SUSPEND);
+                       up(&ud->device.sem);
+               }
+               if (error)
                        device_release_driver(&ud->device);
+               put_driver(drv);
        }
        up(&nodemgr_ud_class.sem);
 }
@@ -1404,20 +1416,29 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
 
 static void nodemgr_resume_ne(struct node_entry *ne)
 {
-       struct class_device *cdev;
+       struct device *dev;
        struct unit_directory *ud;
+       struct device_driver *drv;
 
        ne->in_limbo = 0;
        device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
 
        down(&nodemgr_ud_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-               ud = container_of(cdev, struct unit_directory, class_dev);
+       list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+               ud = container_of(dev, struct unit_directory, unit_dev);
                if (ud->ne != ne)
                        continue;
 
-               if (ud->device.driver && ud->device.driver->resume)
-                       ud->device.driver->resume(&ud->device);
+               drv = get_driver(ud->device.driver);
+               if (!drv)
+                       continue;
+
+               if (drv->resume) {
+                       down(&ud->device.sem);
+                       drv->resume(&ud->device);
+                       up(&ud->device.sem);
+               }
+               put_driver(drv);
        }
        up(&nodemgr_ud_class.sem);
 
@@ -1428,23 +1449,32 @@ static void nodemgr_resume_ne(struct node_entry *ne)
 
 static void nodemgr_update_pdrv(struct node_entry *ne)
 {
+       struct device *dev;
        struct unit_directory *ud;
+       struct device_driver *drv;
        struct hpsb_protocol_driver *pdrv;
-       struct class_device *cdev;
+       int error;
 
        down(&nodemgr_ud_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-               ud = container_of(cdev, struct unit_directory, class_dev);
+       list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+               ud = container_of(dev, struct unit_directory, unit_dev);
                if (ud->ne != ne)
                        continue;
 
-               if (ud->device.driver) {
-                       pdrv = container_of(ud->device.driver,
-                                           struct hpsb_protocol_driver,
-                                           driver);
-                       if (pdrv->update && pdrv->update(ud))
-                               device_release_driver(&ud->device);
+               drv = get_driver(ud->device.driver);
+               if (!drv)
+                       continue;
+
+               error = 0;
+               pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
+               if (pdrv->update) {
+                       down(&ud->device.sem);
+                       error = pdrv->update(ud);
+                       up(&ud->device.sem);
                }
+               if (error)
+                       device_release_driver(&ud->device);
+               put_driver(drv);
        }
        up(&nodemgr_ud_class.sem);
 }
@@ -1509,7 +1539,7 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
 static void nodemgr_node_probe(struct host_info *hi, int generation)
 {
        struct hpsb_host *host = hi->host;
-       struct class_device *cdev;
+       struct device *dev;
        struct node_entry *ne;
 
        /* Do some processing of the nodes we've probed. This pulls them
@@ -1522,13 +1552,13 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
         * improvement...) */
 
        down(&nodemgr_ne_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
+       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+               ne = container_of(dev, struct node_entry, node_dev);
                if (!ne->needs_probe)
                        nodemgr_probe_ne(hi, ne, generation);
        }
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
+       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+               ne = container_of(dev, struct node_entry, node_dev);
                if (ne->needs_probe)
                        nodemgr_probe_ne(hi, ne, generation);
        }
@@ -1686,18 +1716,12 @@ static int nodemgr_host_thread(void *__hi)
                if (kthread_should_stop())
                        goto exit;
 
-               if (mutex_lock_interruptible(&nodemgr_serialize)) {
-                       if (try_to_freeze())
-                               continue;
-                       goto exit;
-               }
-
                /* Pause for 1/4 second in 1/16 second intervals,
                 * to make sure things settle down. */
                g = get_hpsb_generation(host);
                for (i = 0; i < 4 ; i++) {
                        if (msleep_interruptible(63) || kthread_should_stop())
-                               goto unlock_exit;
+                               goto exit;
 
                        /* Now get the generation in which the node ID's we collect
                         * are valid.  During the bus scan we will use this generation
@@ -1715,7 +1739,6 @@ static int nodemgr_host_thread(void *__hi)
                if (!nodemgr_check_irm_capability(host, reset_cycles) ||
                    !nodemgr_do_irm_duties(host, reset_cycles)) {
                        reset_cycles++;
-                       mutex_unlock(&nodemgr_serialize);
                        continue;
                }
                reset_cycles = 0;
@@ -1732,11 +1755,7 @@ static int nodemgr_host_thread(void *__hi)
 
                /* Update some of our sysfs symlinks */
                nodemgr_update_host_dev_links(host);
-
-               mutex_unlock(&nodemgr_serialize);
        }
-unlock_exit:
-       mutex_unlock(&nodemgr_serialize);
 exit:
        HPSB_VERBOSE("NodeMgr: Exiting thread");
        return 0;
@@ -1756,13 +1775,13 @@ exit:
  */
 int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
 {
-       struct class_device *cdev;
+       struct device *dev;
        struct hpsb_host *host;
        int error = 0;
 
        down(&hpsb_host_class.sem);
-       list_for_each_entry(cdev, &hpsb_host_class.children, node) {
-               host = container_of(cdev, struct hpsb_host, class_dev);
+       list_for_each_entry(dev, &hpsb_host_class.devices, node) {
+               host = container_of(dev, struct hpsb_host, host_dev);
 
                if ((error = cb(host, data)))
                        break;
index 4530b29d941c37c0bc74debaeab810920057b363..919e92e2a9556b12045fca7371f8faf6e955e679 100644 (file)
@@ -84,7 +84,7 @@ struct unit_directory {
        int length;             /* Number of quadlets */
 
        struct device device;
-       struct class_device class_dev;
+       struct device unit_dev;
 
        struct csr1212_keyval *ud_kv;
        u32 lun;                /* logical unit number immediate value */
@@ -107,7 +107,7 @@ struct node_entry {
        u32 capabilities;
 
        struct device device;
-       struct class_device class_dev;
+       struct device node_dev;
 
        /* Means this node is not attached anymore */
        int in_limbo;
index 5dadfd296f79c4796e414e3de301a3c4f9714569..5667c8102efc0dcc56d14a786e602a7437ab4596 100644 (file)
@@ -138,19 +138,6 @@ printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->
 #define DBGMSG(fmt, args...) do {} while (0)
 #endif
 
-#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
-#define OHCI_DMA_ALLOC(fmt, args...) \
-       HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
-               ++global_outstanding_dmas, ## args)
-#define OHCI_DMA_FREE(fmt, args...) \
-       HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
-               --global_outstanding_dmas, ## args)
-static int global_outstanding_dmas = 0;
-#else
-#define OHCI_DMA_ALLOC(fmt, args...) do {} while (0)
-#define OHCI_DMA_FREE(fmt, args...) do {} while (0)
-#endif
-
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) \
 printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
@@ -170,7 +157,6 @@ static void dma_trm_reset(struct dma_trm_ctx *d);
 static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
                             enum context_type type, int ctx, int num_desc,
                             int buf_size, int split_buf_size, int context_base);
-static void stop_dma_rcv_ctx(struct dma_rcv_ctx *d);
 static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
 
 static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
@@ -533,9 +519,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
        initialize_dma_trm_ctx(&ohci->at_req_context);
        initialize_dma_trm_ctx(&ohci->at_resp_context);
        
-       /* Initialize IR Legacy DMA channel mask */
-       ohci->ir_legacy_channels = 0;
-
        /* Accept AR requests from all nodes */
        reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
 
@@ -733,7 +716,6 @@ static void insert_packet(struct ti_ohci *ohci,
                                 pci_map_single(ohci->dev, packet->data,
                                                packet->data_size,
                                                PCI_DMA_TODEVICE));
-                       OHCI_DMA_ALLOC("single, block transmit packet");
 
                         d->prg_cpu[idx]->end.branchAddress = 0;
                         d->prg_cpu[idx]->end.status = 0;
@@ -783,7 +765,6 @@ static void insert_packet(struct ti_ohci *ohci,
                 d->prg_cpu[idx]->end.address = cpu_to_le32(
                                pci_map_single(ohci->dev, packet->data,
                                packet->data_size, PCI_DMA_TODEVICE));
-               OHCI_DMA_ALLOC("single, iso transmit packet");
 
                 d->prg_cpu[idx]->end.branchAddress = 0;
                 d->prg_cpu[idx]->end.status = 0;
@@ -884,36 +865,9 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
                return -EOVERFLOW;
        }
 
-       /* Decide whether we have an iso, a request, or a response packet */
        if (packet->type == hpsb_raw)
                d = &ohci->at_req_context;
-       else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) {
-               /* The legacy IT DMA context is initialized on first
-                * use.  However, the alloc cannot be run from
-                * interrupt context, so we bail out if that is the
-                * case. I don't see anyone sending ISO packets from
-                * interrupt context anyway... */
-
-               if (ohci->it_legacy_context.ohci == NULL) {
-                       if (in_interrupt()) {
-                               PRINT(KERN_ERR,
-                                     "legacy IT context cannot be initialized during interrupt");
-                               return -EINVAL;
-                       }
-
-                       if (alloc_dma_trm_ctx(ohci, &ohci->it_legacy_context,
-                                             DMA_CTX_ISO, 0, IT_NUM_DESC,
-                                             OHCI1394_IsoXmitContextBase) < 0) {
-                               PRINT(KERN_ERR,
-                                     "error initializing legacy IT context");
-                               return -ENOMEM;
-                       }
-
-                       initialize_dma_trm_ctx(&ohci->it_legacy_context);
-               }
-
-               d = &ohci->it_legacy_context;
-       } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
+       else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
                d = &ohci->at_resp_context;
        else
                d = &ohci->at_req_context;
@@ -932,9 +886,7 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
 {
        struct ti_ohci *ohci = host->hostdata;
-       int retval = 0;
-       unsigned long flags;
-       int phy_reg;
+       int retval = 0, phy_reg;
 
        switch (cmd) {
        case RESET_BUS:
@@ -1027,117 +979,6 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
                dma_trm_reset(&ohci->at_resp_context);
                break;
 
-       case ISO_LISTEN_CHANNEL:
-        {
-               u64 mask;
-               struct dma_rcv_ctx *d = &ohci->ir_legacy_context;
-               int ir_legacy_active;
-
-               if (arg<0 || arg>63) {
-                       PRINT(KERN_ERR,
-                             "%s: IS0 listen channel %d is out of range",
-                             __FUNCTION__, arg);
-                       return -EFAULT;
-               }
-
-               mask = (u64)0x1<<arg;
-
-                spin_lock_irqsave(&ohci->IR_channel_lock, flags);
-
-               if (ohci->ISO_channel_usage & mask) {
-                       PRINT(KERN_ERR,
-                             "%s: IS0 listen channel %d is already used",
-                             __FUNCTION__, arg);
-                       spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-                       return -EFAULT;
-               }
-
-               ir_legacy_active = ohci->ir_legacy_channels;
-
-               ohci->ISO_channel_usage |= mask;
-               ohci->ir_legacy_channels |= mask;
-
-                spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-
-               if (!ir_legacy_active) {
-                       if (ohci1394_register_iso_tasklet(ohci,
-                                         &ohci->ir_legacy_tasklet) < 0) {
-                               PRINT(KERN_ERR, "No IR DMA context available");
-                               return -EBUSY;
-                       }
-
-                       /* the IR context can be assigned to any DMA context
-                        * by ohci1394_register_iso_tasklet */
-                       d->ctx = ohci->ir_legacy_tasklet.context;
-                       d->ctrlSet = OHCI1394_IsoRcvContextControlSet +
-                               32*d->ctx;
-                       d->ctrlClear = OHCI1394_IsoRcvContextControlClear +
-                               32*d->ctx;
-                       d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx;
-                       d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx;
-
-                       initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
-
-                       if (printk_ratelimit())
-                               DBGMSG("IR legacy activated");
-               }
-
-                spin_lock_irqsave(&ohci->IR_channel_lock, flags);
-
-               if (arg>31)
-                       reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet,
-                                 1<<(arg-32));
-               else
-                       reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet,
-                                 1<<arg);
-
-                spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-                DBGMSG("Listening enabled on channel %d", arg);
-                break;
-        }
-       case ISO_UNLISTEN_CHANNEL:
-        {
-               u64 mask;
-
-               if (arg<0 || arg>63) {
-                       PRINT(KERN_ERR,
-                             "%s: IS0 unlisten channel %d is out of range",
-                             __FUNCTION__, arg);
-                       return -EFAULT;
-               }
-
-               mask = (u64)0x1<<arg;
-
-                spin_lock_irqsave(&ohci->IR_channel_lock, flags);
-
-               if (!(ohci->ISO_channel_usage & mask)) {
-                       PRINT(KERN_ERR,
-                             "%s: IS0 unlisten channel %d is not used",
-                             __FUNCTION__, arg);
-                       spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-                       return -EFAULT;
-               }
-
-               ohci->ISO_channel_usage &= ~mask;
-               ohci->ir_legacy_channels &= ~mask;
-
-               if (arg>31)
-                       reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear,
-                                 1<<(arg-32));
-               else
-                       reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear,
-                                 1<<arg);
-
-                spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-                DBGMSG("Listening disabled on channel %d", arg);
-
-               if (ohci->ir_legacy_channels == 0) {
-                       stop_dma_rcv_ctx(&ohci->ir_legacy_context);
-                       DBGMSG("ISO legacy receive context stopped");
-               }
-
-                break;
-        }
        default:
                PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",
                        cmd);
@@ -2869,12 +2710,10 @@ static void dma_trm_tasklet (unsigned long data)
                list_del_init(&packet->driver_list);
                hpsb_packet_sent(ohci->host, packet, ack);
 
-               if (datasize) {
+               if (datasize)
                        pci_unmap_single(ohci->dev,
                                         cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
                                         datasize, PCI_DMA_TODEVICE);
-                       OHCI_DMA_FREE("single Xmit data packet");
-               }
 
                d->sent_ind = (d->sent_ind+1)%d->num_desc;
                d->free_prgs++;
@@ -2885,22 +2724,6 @@ static void dma_trm_tasklet (unsigned long data)
        spin_unlock_irqrestore(&d->lock, flags);
 }
 
-static void stop_dma_rcv_ctx(struct dma_rcv_ctx *d)
-{
-       if (d->ctrlClear) {
-               ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
-
-               if (d->type == DMA_CTX_ISO) {
-                       /* disable interrupts */
-                       reg_write(d->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << d->ctx);
-                       ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_legacy_tasklet);
-               } else {
-                       tasklet_kill(&d->task);
-               }
-       }
-}
-
-
 static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
 {
        int i;
@@ -2913,23 +2736,19 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
 
        if (d->buf_cpu) {
                for (i=0; i<d->num_desc; i++)
-                       if (d->buf_cpu[i] && d->buf_bus[i]) {
+                       if (d->buf_cpu[i] && d->buf_bus[i])
                                pci_free_consistent(
                                        ohci->dev, d->buf_size,
                                        d->buf_cpu[i], d->buf_bus[i]);
-                               OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i);
-                       }
                kfree(d->buf_cpu);
                kfree(d->buf_bus);
        }
        if (d->prg_cpu) {
                for (i=0; i<d->num_desc; i++)
-                       if (d->prg_cpu[i] && d->prg_bus[i]) {
-                               pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]);
-                               OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i);
-                       }
+                       if (d->prg_cpu[i] && d->prg_bus[i])
+                               pci_pool_free(d->prg_pool, d->prg_cpu[i],
+                                             d->prg_bus[i]);
                pci_pool_destroy(d->prg_pool);
-               OHCI_DMA_FREE("dma_rcv prg pool");
                kfree(d->prg_cpu);
                kfree(d->prg_bus);
        }
@@ -2998,13 +2817,10 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
        }
        num_allocs++;
 
-       OHCI_DMA_ALLOC("dma_rcv prg pool");
-
        for (i=0; i<d->num_desc; i++) {
                d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
                                                     d->buf_size,
                                                     d->buf_bus+i);
-               OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i);
 
                if (d->buf_cpu[i] != NULL) {
                        memset(d->buf_cpu[i], 0, d->buf_size);
@@ -3016,7 +2832,6 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
                }
 
                d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-               OHCI_DMA_ALLOC("pool dma_rcv prg[%d]", i);
 
                 if (d->prg_cpu[i] != NULL) {
                         memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
@@ -3030,18 +2845,11 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
 
         spin_lock_init(&d->lock);
 
-       if (type == DMA_CTX_ISO) {
-               ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet,
-                                         OHCI_ISO_MULTICHANNEL_RECEIVE,
-                                         dma_rcv_tasklet, (unsigned long) d);
-       } else {
-               d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-               d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-               d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-
-               tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d);
-       }
+       d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+       d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+       d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
 
+       tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d);
        return 0;
 }
 
@@ -3057,12 +2865,10 @@ static void free_dma_trm_ctx(struct dma_trm_ctx *d)
 
        if (d->prg_cpu) {
                for (i=0; i<d->num_desc; i++)
-                       if (d->prg_cpu[i] && d->prg_bus[i]) {
-                               pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]);
-                               OHCI_DMA_FREE("pool dma_trm prg[%d]", i);
-                       }
+                       if (d->prg_cpu[i] && d->prg_bus[i])
+                               pci_pool_free(d->prg_pool, d->prg_cpu[i],
+                                             d->prg_bus[i]);
                pci_pool_destroy(d->prg_pool);
-               OHCI_DMA_FREE("dma_trm prg pool");
                kfree(d->prg_cpu);
                kfree(d->prg_bus);
        }
@@ -3108,11 +2914,8 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
        }
        num_allocs++;
 
-       OHCI_DMA_ALLOC("dma_rcv prg pool");
-
        for (i = 0; i < d->num_desc; i++) {
                d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-               OHCI_DMA_ALLOC("pool dma_trm prg[%d]", i);
 
                 if (d->prg_cpu[i] != NULL) {
                         memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
@@ -3127,28 +2930,10 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
         spin_lock_init(&d->lock);
 
        /* initialize tasklet */
-       if (type == DMA_CTX_ISO) {
-               ohci1394_init_iso_tasklet(&ohci->it_legacy_tasklet, OHCI_ISO_TRANSMIT,
-                                         dma_trm_tasklet, (unsigned long) d);
-               if (ohci1394_register_iso_tasklet(ohci,
-                                                 &ohci->it_legacy_tasklet) < 0) {
-                       PRINT(KERN_ERR, "No IT DMA context available");
-                       free_dma_trm_ctx(d);
-                       return -EBUSY;
-               }
-
-               /* IT can be assigned to any context by register_iso_tasklet */
-               d->ctx = ohci->it_legacy_tasklet.context;
-               d->ctrlSet = OHCI1394_IsoXmitContextControlSet + 16 * d->ctx;
-               d->ctrlClear = OHCI1394_IsoXmitContextControlClear + 16 * d->ctx;
-               d->cmdPtr = OHCI1394_IsoXmitCommandPtr + 16 * d->ctx;
-       } else {
-               d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-               d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-               d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-               tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);
-       }
-
+       d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+       d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+       d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
+       tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d);
        return 0;
 }
 
@@ -3294,7 +3079,6 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
        ohci->csr_config_rom_cpu =
                pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
                                     &ohci->csr_config_rom_bus);
-       OHCI_DMA_ALLOC("consistent csr_config_rom");
        if (ohci->csr_config_rom_cpu == NULL)
                FAIL(-ENOMEM, "Failed to allocate buffer config rom");
        ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
@@ -3303,8 +3087,6 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
        ohci->selfid_buf_cpu =
                pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
                       &ohci->selfid_buf_bus);
-       OHCI_DMA_ALLOC("consistent selfid_buf");
-
        if (ohci->selfid_buf_cpu == NULL)
                FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
        ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
@@ -3377,20 +3159,6 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
        ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
-       /* Allocate the IR DMA context right here so we don't have
-        * to do it in interrupt path - note that this doesn't
-        * waste much memory and avoids the jugglery required to
-        * allocate it in IRQ path. */
-       if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
-                             DMA_CTX_ISO, 0, IR_NUM_DESC,
-                             IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-                             OHCI1394_IsoRcvContextBase) < 0) {
-               FAIL(-ENOMEM, "Cannot allocate IR Legacy DMA context");
-       }
-
-       /* We hopefully don't have to pre-allocate IT DMA like we did
-        * for IR DMA above. Allocate it on-demand and mark inactive. */
-       ohci->it_legacy_context.ohci = NULL;
        spin_lock_init(&ohci->event_lock);
 
        /*
@@ -3483,20 +3251,16 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
                free_dma_rcv_ctx(&ohci->ar_resp_context);
                free_dma_trm_ctx(&ohci->at_req_context);
                free_dma_trm_ctx(&ohci->at_resp_context);
-               free_dma_rcv_ctx(&ohci->ir_legacy_context);
-               free_dma_trm_ctx(&ohci->it_legacy_context);
 
        case OHCI_INIT_HAVE_SELFID_BUFFER:
                pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
                                    ohci->selfid_buf_cpu,
                                    ohci->selfid_buf_bus);
-               OHCI_DMA_FREE("consistent selfid_buf");
 
        case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
                pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
                                    ohci->csr_config_rom_cpu,
                                    ohci->csr_config_rom_bus);
-               OHCI_DMA_FREE("consistent csr_config_rom");
 
        case OHCI_INIT_HAVE_IOMAPPING:
                iounmap(ohci->registers);
index f1ad539e7c1b34d2567c18cd1df89926e92f299e..4320bf010495c3bb7eabc0c76bfd600ecd3588da 100644 (file)
@@ -190,23 +190,10 @@ struct ti_ohci {
        unsigned long ir_multichannel_used; /* ditto */
         spinlock_t IR_channel_lock;
 
-       /* iso receive (legacy API) */
-       u64 ir_legacy_channels; /* note: this differs from ISO_channel_usage;
-                                  it only accounts for channels listened to
-                                  by the legacy API, so that we can know when
-                                  it is safe to free the legacy API context */
-
-       struct dma_rcv_ctx ir_legacy_context;
-       struct ohci1394_iso_tasklet ir_legacy_tasklet;
-
         /* iso transmit */
        int nb_iso_xmit_ctx;
        unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
 
-       /* iso transmit (legacy API) */
-       struct dma_trm_ctx it_legacy_context;
-       struct ohci1394_iso_tasklet it_legacy_tasklet;
-
         u64 ISO_channel_usage;
 
         /* IEEE-1394 part follows */
@@ -221,7 +208,6 @@ struct ti_ohci {
 
        /* Tasklets for iso receive and transmit, used by video1394
         * and dv1394 */
-
        struct list_head iso_tasklet_list;
        spinlock_t iso_tasklet_list_lock;
 
index 0742befe92270f0d9557072dc59a6b2771e5197c..d1a5bcdb5e0be9c5bab2facb893e996731cda317 100644 (file)
@@ -477,7 +477,11 @@ static void send_next(struct ti_lynx *lynx, int what)
         struct lynx_send_data *d;
         struct hpsb_packet *packet;
 
+#if 0 /* has been removed from ieee1394 core */
         d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
+#else
+       d = &lynx->async;
+#endif
         if (!list_empty(&d->pcl_queue)) {
                 PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo");
                 BUG();
@@ -511,9 +515,11 @@ static void send_next(struct ti_lynx *lynx, int what)
         case hpsb_async:
                 pcl.buffer[0].control |= PCL_CMD_XMT;
                 break;
+#if 0 /* has been removed from ieee1394 core */
         case hpsb_iso:
                 pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
                 break;
+#endif
         case hpsb_raw:
                 pcl.buffer[0].control |= PCL_CMD_UNFXMT;
                 break;
@@ -542,9 +548,11 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
         case hpsb_raw:
                 d = &lynx->async;
                 break;
+#if 0 /* has been removed from ieee1394 core */
         case hpsb_iso:
                 d = &lynx->iso_send;
                 break;
+#endif
         default:
                 PRINT(KERN_ERR, lynx->id, "invalid packet type %d",
                       packet->type);
@@ -797,7 +805,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
                }
 
                 break;
-
+#if 0 /* has been removed from ieee1394 core */
         case ISO_LISTEN_CHANNEL:
                 spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
 
@@ -819,7 +827,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
 
                 spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
                 break;
-
+#endif
         default:
                 PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);
                 retval = -1;
@@ -1009,11 +1017,11 @@ static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
                                 pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
                                                  packet->data_size, PCI_DMA_TODEVICE);
                         }
-
+#if 0 /* has been removed from ieee1394 core */
                         if (!list_empty(&lynx->iso_send.queue)) {
                                 send_next(lynx, hpsb_iso);
                         }
-
+#endif
                         spin_unlock(&lynx->iso_send.queue_lock);
 
                         if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
index 50daabf6e5fa38317ce247246945a40191975db7..a06aaad5b448da6072a0c4469b60cfa64eafa1e3 100644 (file)
@@ -36,11 +36,6 @@ struct file_info {
 
         u8 __user *fcp_buffer;
 
-       /* old ISO API */
-        u64 listen_channels;
-        quadlet_t __user *iso_buffer;
-        size_t iso_buffer_length;
-
         u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
 
        /* new rawiso API */
index f1d05eeb9f5190216b68504dc78fcc1fb7ef38fe..336e5ff4cfcf6f111cf5c57d6a043c5767d1513d 100644 (file)
@@ -98,21 +98,6 @@ static struct hpsb_address_ops arm_ops = {
 
 static void queue_complete_cb(struct pending_request *req);
 
-#include <asm/current.h>
-static void print_old_iso_deprecation(void)
-{
-       static pid_t p;
-
-       if (p == current->pid)
-               return;
-       p = current->pid;
-       printk(KERN_WARNING "raw1394: WARNING - Program \"%s\" uses unsupported"
-              " isochronous request types which will be removed in a next"
-              " kernel release\n", current->comm);
-       printk(KERN_WARNING "raw1394: Update your software to use libraw1394's"
-              " newer interface\n");
-}
-
 static struct pending_request *__alloc_pending_request(gfp_t flags)
 {
        struct pending_request *req;
@@ -297,67 +282,6 @@ static void host_reset(struct hpsb_host *host)
        spin_unlock_irqrestore(&host_info_lock, flags);
 }
 
-static void iso_receive(struct hpsb_host *host, int channel, quadlet_t * data,
-                       size_t length)
-{
-       unsigned long flags;
-       struct host_info *hi;
-       struct file_info *fi;
-       struct pending_request *req, *req_next;
-       struct iso_block_store *ibs = NULL;
-       LIST_HEAD(reqs);
-
-       if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
-               HPSB_INFO("dropped iso packet");
-               return;
-       }
-
-       spin_lock_irqsave(&host_info_lock, flags);
-       hi = find_host_info(host);
-
-       if (hi != NULL) {
-               list_for_each_entry(fi, &hi->file_info_list, list) {
-                       if (!(fi->listen_channels & (1ULL << channel)))
-                               continue;
-
-                       req = __alloc_pending_request(GFP_ATOMIC);
-                       if (!req)
-                               break;
-
-                       if (!ibs) {
-                               ibs = kmalloc(sizeof(*ibs) + length,
-                                             GFP_ATOMIC);
-                               if (!ibs) {
-                                       kfree(req);
-                                       break;
-                               }
-
-                               atomic_add(length, &iso_buffer_size);
-                               atomic_set(&ibs->refcount, 0);
-                               ibs->data_size = length;
-                               memcpy(ibs->data, data, length);
-                       }
-
-                       atomic_inc(&ibs->refcount);
-
-                       req->file_info = fi;
-                       req->ibs = ibs;
-                       req->data = ibs->data;
-                       req->req.type = RAW1394_REQ_ISO_RECEIVE;
-                       req->req.generation = get_hpsb_generation(host);
-                       req->req.misc = 0;
-                       req->req.recvb = ptr2int(fi->iso_buffer);
-                       req->req.length = min(length, fi->iso_buffer_length);
-
-                       list_add_tail(&req->list, &reqs);
-               }
-       }
-       spin_unlock_irqrestore(&host_info_lock, flags);
-
-       list_for_each_entry_safe(req, req_next, &reqs, list)
-           queue_complete_req(req);
-}
-
 static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
                        int cts, u8 * data, size_t length)
 {
@@ -434,7 +358,11 @@ struct compat_raw1394_req {
 
        __u64 sendb;
        __u64 recvb;
-} __attribute__((packed));
+}
+#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
+__attribute__((packed))
+#endif
+;
 
 static const char __user *raw1394_compat_write(const char __user *buf)
 {
@@ -459,7 +387,7 @@ static const char __user *raw1394_compat_write(const char __user *buf)
 static int
 raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
 {
-       struct compat_raw1394_req __user *cr = (typeof(cr)) r;
+       struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
        if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) ||
            P(type) ||
            P(error) ||
@@ -587,7 +515,7 @@ static int state_opened(struct file_info *fi, struct pending_request *req)
 
        req->req.length = 0;
        queue_complete_req(req);
-       return sizeof(struct raw1394_request);
+       return 0;
 }
 
 static int state_initialized(struct file_info *fi, struct pending_request *req)
@@ -601,7 +529,7 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
                req->req.generation = atomic_read(&internal_generation);
                req->req.length = 0;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        switch (req->req.type) {
@@ -673,44 +601,7 @@ out_set_card:
        }
 
        queue_complete_req(req);
-       return sizeof(struct raw1394_request);
-}
-
-static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
-{
-       int channel = req->req.misc;
-
-       if ((channel > 63) || (channel < -64)) {
-               req->req.error = RAW1394_ERROR_INVALID_ARG;
-       } else if (channel >= 0) {
-               /* allocate channel req.misc */
-               if (fi->listen_channels & (1ULL << channel)) {
-                       req->req.error = RAW1394_ERROR_ALREADY;
-               } else {
-                       if (hpsb_listen_channel
-                           (&raw1394_highlevel, fi->host, channel)) {
-                               req->req.error = RAW1394_ERROR_ALREADY;
-                       } else {
-                               fi->listen_channels |= 1ULL << channel;
-                               fi->iso_buffer = int2ptr(req->req.recvb);
-                               fi->iso_buffer_length = req->req.length;
-                       }
-               }
-       } else {
-               /* deallocate channel (one's complement neg) req.misc */
-               channel = ~channel;
-
-               if (fi->listen_channels & (1ULL << channel)) {
-                       hpsb_unlisten_channel(&raw1394_highlevel, fi->host,
-                                             channel);
-                       fi->listen_channels &= ~(1ULL << channel);
-               } else {
-                       req->req.error = RAW1394_ERROR_INVALID_ARG;
-               }
-       }
-
-       req->req.length = 0;
-       queue_complete_req(req);
+       return 0;
 }
 
 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
@@ -865,7 +756,7 @@ static int handle_async_request(struct file_info *fi,
        if (req->req.error) {
                req->req.length = 0;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        hpsb_set_packet_complete_task(packet,
@@ -883,51 +774,7 @@ static int handle_async_request(struct file_info *fi,
                hpsb_free_tlabel(packet);
                queue_complete_req(req);
        }
-       return sizeof(struct raw1394_request);
-}
-
-static int handle_iso_send(struct file_info *fi, struct pending_request *req,
-                          int channel)
-{
-       unsigned long flags;
-       struct hpsb_packet *packet;
-
-       packet = hpsb_make_isopacket(fi->host, req->req.length, channel & 0x3f,
-                                    (req->req.misc >> 16) & 0x3,
-                                    req->req.misc & 0xf);
-       if (!packet)
-               return -ENOMEM;
-
-       packet->speed_code = req->req.address & 0x3;
-
-       req->packet = packet;
-
-       if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-                          req->req.length)) {
-               req->req.error = RAW1394_ERROR_MEMFAULT;
-               req->req.length = 0;
-               queue_complete_req(req);
-               return sizeof(struct raw1394_request);
-       }
-
-       req->req.length = 0;
-       hpsb_set_packet_complete_task(packet,
-                                     (void (*)(void *))queue_complete_req,
-                                     req);
-
-       spin_lock_irqsave(&fi->reqlists_lock, flags);
-       list_add_tail(&req->list, &fi->req_pending);
-       spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-       /* Update the generation of the packet just before sending. */
-       packet->generation = req->req.generation;
-
-       if (hpsb_send_packet(packet) < 0) {
-               req->req.error = RAW1394_ERROR_SEND_ERROR;
-               queue_complete_req(req);
-       }
-
-       return sizeof(struct raw1394_request);
+       return 0;
 }
 
 static int handle_async_send(struct file_info *fi, struct pending_request *req)
@@ -943,7 +790,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
                req->req.error = RAW1394_ERROR_INVALID_ARG;
                req->req.length = 0;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        data_size = req->req.length - header_length;
@@ -957,7 +804,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
                req->req.error = RAW1394_ERROR_MEMFAULT;
                req->req.length = 0;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        if (copy_from_user
@@ -966,7 +813,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
                req->req.error = RAW1394_ERROR_MEMFAULT;
                req->req.length = 0;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        packet->type = hpsb_async;
@@ -994,7 +841,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
                queue_complete_req(req);
        }
 
-       return sizeof(struct raw1394_request);
+       return 0;
 }
 
 static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
@@ -1869,7 +1716,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
                spin_lock_irqsave(&host_info_lock, flags);
                list_add_tail(&addr->addr_list, &fi->addr_list);
                spin_unlock_irqrestore(&host_info_lock, flags);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
        retval =
            hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops,
@@ -1887,7 +1734,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
                return (-EALREADY);
        }
        free_pending_request(req);      /* immediate success or fail */
-       return sizeof(struct raw1394_request);
+       return 0;
 }
 
 static int arm_unregister(struct file_info *fi, struct pending_request *req)
@@ -1955,7 +1802,7 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
                vfree(addr->addr_space_buffer);
                kfree(addr);
                free_pending_request(req);      /* immediate success or fail */
-               return sizeof(struct raw1394_request);
+               return 0;
        }
        retval =
            hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
@@ -1971,7 +1818,7 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
        vfree(addr->addr_space_buffer);
        kfree(addr);
        free_pending_request(req);      /* immediate success or fail */
-       return sizeof(struct raw1394_request);
+       return 0;
 }
 
 /* Copy data from ARM buffer(s) to user buffer. */
@@ -2013,7 +1860,7 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req)
                                 * queue no response, and therefore nobody
                                 * will free it. */
                                free_pending_request(req);
-                               return sizeof(struct raw1394_request);
+                               return 0;
                        } else {
                                DBGMSG("arm_get_buf request exceeded mapping");
                                spin_unlock_irqrestore(&host_info_lock, flags);
@@ -2065,7 +1912,7 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req)
                                 * queue no response, and therefore nobody
                                 * will free it. */
                                free_pending_request(req);
-                               return sizeof(struct raw1394_request);
+                               return 0;
                        } else {
                                DBGMSG("arm_set_buf request exceeded mapping");
                                spin_unlock_irqrestore(&host_info_lock, flags);
@@ -2086,7 +1933,7 @@ static int reset_notification(struct file_info *fi, struct pending_request *req)
            (req->req.misc == RAW1394_NOTIFY_ON)) {
                fi->notification = (u8) req->req.misc;
                free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-               return sizeof(struct raw1394_request);
+               return 0;
        }
        /* error EINVAL (22) invalid argument */
        return (-EINVAL);
@@ -2119,12 +1966,12 @@ static int write_phypacket(struct file_info *fi, struct pending_request *req)
                req->req.length = 0;
                queue_complete_req(req);
        }
-       return sizeof(struct raw1394_request);
+       return 0;
 }
 
 static int get_config_rom(struct file_info *fi, struct pending_request *req)
 {
-       int ret = sizeof(struct raw1394_request);
+       int ret = 0;
        quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
        int status;
 
@@ -2154,7 +2001,7 @@ static int get_config_rom(struct file_info *fi, struct pending_request *req)
 
 static int update_config_rom(struct file_info *fi, struct pending_request *req)
 {
-       int ret = sizeof(struct raw1394_request);
+       int ret = 0;
        quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
        if (!data)
                return -ENOMEM;
@@ -2221,7 +2068,7 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req)
 
                        hpsb_update_config_rom_image(fi->host);
                        free_pending_request(req);
-                       return sizeof(struct raw1394_request);
+                       return 0;
                }
        }
 
@@ -2286,7 +2133,7 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req)
                /* we have to free the request, because we queue no response,
                 * and therefore nobody will free it */
                free_pending_request(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        } else {
                for (dentry =
                     fi->csr1212_dirs[dr]->value.directory.dentries_head;
@@ -2311,11 +2158,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
 
        case RAW1394_REQ_ECHO:
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
-
-       case RAW1394_REQ_ISO_SEND:
-               print_old_iso_deprecation();
-               return handle_iso_send(fi, req, node);
+               return 0;
 
        case RAW1394_REQ_ARM_REGISTER:
                return arm_register(fi, req);
@@ -2332,27 +2175,30 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
        case RAW1394_REQ_RESET_NOTIFY:
                return reset_notification(fi, req);
 
+       case RAW1394_REQ_ISO_SEND:
        case RAW1394_REQ_ISO_LISTEN:
-               print_old_iso_deprecation();
-               handle_iso_listen(fi, req);
-               return sizeof(struct raw1394_request);
+               printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n");
+               req->req.error = RAW1394_ERROR_COMPAT;
+               req->req.misc = RAW1394_KERNELAPI_VERSION;
+               queue_complete_req(req);
+               return 0;
 
        case RAW1394_REQ_FCP_LISTEN:
                handle_fcp_listen(fi, req);
-               return sizeof(struct raw1394_request);
+               return 0;
 
        case RAW1394_REQ_RESET_BUS:
                if (req->req.misc == RAW1394_LONG_RESET) {
                        DBGMSG("busreset called (type: LONG)");
                        hpsb_reset_bus(fi->host, LONG_RESET);
                        free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                       return sizeof(struct raw1394_request);
+                       return 0;
                }
                if (req->req.misc == RAW1394_SHORT_RESET) {
                        DBGMSG("busreset called (type: SHORT)");
                        hpsb_reset_bus(fi->host, SHORT_RESET);
                        free_pending_request(req);      /* we have to free the request, because we queue no response, and therefore nobody will free it */
-                       return sizeof(struct raw1394_request);
+                       return 0;
                }
                /* error EINVAL (22) invalid argument */
                return (-EINVAL);
@@ -2371,7 +2217,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
                req->req.generation = get_hpsb_generation(fi->host);
                req->req.length = 0;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        switch (req->req.type) {
@@ -2384,7 +2230,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
        if (req->req.length == 0) {
                req->req.error = RAW1394_ERROR_INVALID_ARG;
                queue_complete_req(req);
-               return sizeof(struct raw1394_request);
+               return 0;
        }
 
        return handle_async_request(fi, req, node);
@@ -2395,7 +2241,7 @@ static ssize_t raw1394_write(struct file *file, const char __user * buffer,
 {
        struct file_info *fi = (struct file_info *)file->private_data;
        struct pending_request *req;
-       ssize_t retval = 0;
+       ssize_t retval = -EBADFD;
 
 #ifdef CONFIG_COMPAT
        if (count == sizeof(struct compat_raw1394_req) &&
@@ -2437,6 +2283,9 @@ static ssize_t raw1394_write(struct file *file, const char __user * buffer,
 
        if (retval < 0) {
                free_pending_request(req);
+       } else {
+               BUG_ON(retval);
+               retval = count;
        }
 
        return retval;
@@ -2802,6 +2651,103 @@ static int raw1394_ioctl(struct inode *inode, struct file *file,
        return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+struct raw1394_iso_packets32 {
+        __u32 n_packets;
+        compat_uptr_t infos;
+} __attribute__((packed));
+
+struct raw1394_cycle_timer32 {
+        __u32 cycle_timer;
+        __u64 local_time;
+}
+#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
+__attribute__((packed))
+#endif
+;
+
+#define RAW1394_IOC_ISO_RECV_PACKETS32          \
+        _IOW ('#', 0x25, struct raw1394_iso_packets32)
+#define RAW1394_IOC_ISO_XMIT_PACKETS32          \
+        _IOW ('#', 0x27, struct raw1394_iso_packets32)
+#define RAW1394_IOC_GET_CYCLE_TIMER32           \
+        _IOR ('#', 0x30, struct raw1394_cycle_timer32)
+
+static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
+                                          struct raw1394_iso_packets32 __user *arg)
+{
+       compat_uptr_t infos32;
+       void *infos;
+       long err = -EFAULT;
+       struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
+
+       if (!copy_in_user(&dst->n_packets, &arg->n_packets, sizeof arg->n_packets) &&
+           !copy_from_user(&infos32, &arg->infos, sizeof infos32)) {
+               infos = compat_ptr(infos32);
+               if (!copy_to_user(&dst->infos, &infos, sizeof infos))
+                       err = raw1394_ioctl(NULL, file, cmd, (unsigned long)dst);
+       }
+       return err;
+}
+
+static long raw1394_read_cycle_timer32(struct file_info *fi, void __user * uaddr)
+{
+       struct raw1394_cycle_timer32 ct;
+       int err;
+
+       err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
+       if (!err)
+               if (copy_to_user(uaddr, &ct, sizeof(ct)))
+                       err = -EFAULT;
+       return err;
+}
+
+static long raw1394_compat_ioctl(struct file *file,
+                                unsigned int cmd, unsigned long arg)
+{
+       struct file_info *fi = file->private_data;
+       void __user *argp = (void __user *)arg;
+       long err;
+
+       lock_kernel();
+       switch (cmd) {
+       /* These requests have same format as long as 'int' has same size. */
+       case RAW1394_IOC_ISO_RECV_INIT:
+       case RAW1394_IOC_ISO_RECV_START:
+       case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
+       case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
+       case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:
+       case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
+       case RAW1394_IOC_ISO_RECV_FLUSH:
+       case RAW1394_IOC_ISO_XMIT_RECV_STOP:
+       case RAW1394_IOC_ISO_XMIT_INIT:
+       case RAW1394_IOC_ISO_XMIT_START:
+       case RAW1394_IOC_ISO_XMIT_SYNC:
+       case RAW1394_IOC_ISO_GET_STATUS:
+       case RAW1394_IOC_ISO_SHUTDOWN:
+       case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
+               err = raw1394_ioctl(NULL, file, cmd, arg);
+               break;
+       /* These request have different format. */
+       case RAW1394_IOC_ISO_RECV_PACKETS32:
+               err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_RECV_PACKETS, argp);
+               break;
+       case RAW1394_IOC_ISO_XMIT_PACKETS32:
+               err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_XMIT_PACKETS, argp);
+               break;
+       case RAW1394_IOC_GET_CYCLE_TIMER32:
+               err = raw1394_read_cycle_timer32(fi, argp);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       unlock_kernel();
+
+       return err;
+}
+#endif
+
 static unsigned int raw1394_poll(struct file *file, poll_table * pt)
 {
        struct file_info *fi = file->private_data;
@@ -2861,14 +2807,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
        if (fi->iso_state != RAW1394_ISO_INACTIVE)
                raw1394_iso_shutdown(fi);
 
-       for (i = 0; i < 64; i++) {
-               if (fi->listen_channels & (1ULL << i)) {
-                       hpsb_unlisten_channel(&raw1394_highlevel, fi->host, i);
-               }
-       }
-
        spin_lock_irqsave(&host_info_lock, flags);
-       fi->listen_channels = 0;
 
        fail = 0;
        /* set address-entries invalid */
@@ -3030,7 +2969,6 @@ static struct hpsb_highlevel raw1394_highlevel = {
        .add_host = add_host,
        .remove_host = remove_host,
        .host_reset = host_reset,
-       .iso_receive = iso_receive,
        .fcp_request = fcp_request,
 };
 
@@ -3041,7 +2979,9 @@ static const struct file_operations raw1394_fops = {
        .write = raw1394_write,
        .mmap = raw1394_mmap,
        .ioctl = raw1394_ioctl,
-       // .compat_ioctl = ... someone needs to do this
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = raw1394_compat_ioctl,
+#endif
        .poll = raw1394_poll,
        .open = raw1394_open,
        .release = raw1394_release,
@@ -3054,9 +2994,9 @@ static int __init init_raw1394(void)
        hpsb_register_highlevel(&raw1394_highlevel);
 
        if (IS_ERR
-           (class_device_create
-            (hpsb_protocol_class, NULL,
-             MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), NULL,
+           (device_create(
+             hpsb_protocol_class, NULL,
+             MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
              RAW1394_DEVICE_NAME))) {
                ret = -EFAULT;
                goto out_unreg;
@@ -3083,9 +3023,9 @@ static int __init init_raw1394(void)
        goto out;
 
       out_dev:
-       class_device_destroy(hpsb_protocol_class,
-                            MKDEV(IEEE1394_MAJOR,
-                                  IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+       device_destroy(hpsb_protocol_class,
+                      MKDEV(IEEE1394_MAJOR,
+                            IEEE1394_MINOR_BLOCK_RAW1394 * 16));
       out_unreg:
        hpsb_unregister_highlevel(&raw1394_highlevel);
       out:
@@ -3094,9 +3034,9 @@ static int __init init_raw1394(void)
 
 static void __exit cleanup_raw1394(void)
 {
-       class_device_destroy(hpsb_protocol_class,
-                            MKDEV(IEEE1394_MAJOR,
-                                  IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+       device_destroy(hpsb_protocol_class,
+                      MKDEV(IEEE1394_MAJOR,
+                            IEEE1394_MINOR_BLOCK_RAW1394 * 16));
        cdev_del(&raw1394_cdev);
        hpsb_unregister_highlevel(&raw1394_highlevel);
        hpsb_unregister_protocol(&raw1394_driver);
index 7bd22ee1afbb1d56a2a71e9c86cd86b3ad5bfc43..963ac20373d20c860ac7d4f89e5db819b68cfbae 100644 (file)
 #define RAW1394_REQ_ASYNC_WRITE     101
 #define RAW1394_REQ_LOCK            102
 #define RAW1394_REQ_LOCK64          103
-#define RAW1394_REQ_ISO_SEND        104
+#define RAW1394_REQ_ISO_SEND        104 /* removed ABI, now a no-op */
 #define RAW1394_REQ_ASYNC_SEND      105
 #define RAW1394_REQ_ASYNC_STREAM    106
 
-#define RAW1394_REQ_ISO_LISTEN      200
+#define RAW1394_REQ_ISO_LISTEN      200 /* removed ABI, now a no-op */
 #define RAW1394_REQ_FCP_LISTEN      201
 #define RAW1394_REQ_RESET_BUS       202
 #define RAW1394_REQ_GET_ROM         203
index 3f873cc7e247a7944d4ac27359600daf378fb1f7..e0c385a3b45079efc796904d588733a3f5a08449 100644 (file)
@@ -118,14 +118,13 @@ MODULE_PARM_DESC(max_speed, "Force max speed "
                 "(3 = 800Mb/s, 2 = 400Mb/s, 1 = 200Mb/s, 0 = 100Mb/s)");
 
 /*
- * Set serialize_io to 1 if you'd like only one scsi command sent
- * down to us at a time (debugging). This might be necessary for very
- * badly behaved sbp2 devices.
+ * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs.
+ * This is and always has been buggy in multiple subtle ways. See above TODOs.
  */
 static int sbp2_serialize_io = 1;
-module_param_named(serialize_io, sbp2_serialize_io, int, 0444);
-MODULE_PARM_DESC(serialize_io, "Serialize I/O coming from scsi drivers "
-                "(default = 1, faster = 0)");
+module_param_named(serialize_io, sbp2_serialize_io, bool, 0444);
+MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers "
+                "(default = Y, faster but buggy = N)");
 
 /*
  * Bump up max_sectors if you'd like to support very large sized
@@ -154,9 +153,9 @@ MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
  * are possible on OXFW911 and newer Oxsemi bridges.
  */
 static int sbp2_exclusive_login = 1;
-module_param_named(exclusive_login, sbp2_exclusive_login, int, 0644);
+module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644);
 MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
-                "(default = 1)");
+                "(default = Y, use N for concurrent initiators)");
 
 /*
  * If any of the following workarounds is required for your device to work,
index 44402b9d82a8ab0200cf435e7bd7336e5e2a80aa..333a4bb767434997bc0fa06e6fd922a063d46c86 100644 (file)
@@ -67,7 +67,7 @@ struct sbp2_command_orb {
 #define ORB_SET_LUN(v)                 ((v) & 0xffff)
 #define ORB_SET_FUNCTION(v)            (((v) & 0xf) << 16)
 #define ORB_SET_RECONNECT(v)           (((v) & 0xf) << 20)
-#define ORB_SET_EXCLUSIVE(v)           (((v) & 0x1) << 28)
+#define ORB_SET_EXCLUSIVE(v)           ((v) ? 1 << 28 : 0)
 #define ORB_SET_LOGIN_RESP_LENGTH(v)   ((v) & 0xffff)
 #define ORB_SET_PASSWD_LENGTH(v)       (((v) & 0xffff) << 16)
 
index 87ebd0846c3410d56afbc520180046322bc44cdc..bd28adfd7afc6742e7859ced1fffcd374a8a8717 100644 (file)
@@ -1340,9 +1340,9 @@ static void video1394_add_host (struct hpsb_host *host)
        hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
 
        minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
-       class_device_create(hpsb_protocol_class, NULL, MKDEV(
-               IEEE1394_MAJOR, minor), 
-               NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
+       device_create(hpsb_protocol_class, NULL,
+                     MKDEV(IEEE1394_MAJOR, minor),
+                     "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
 }
 
 
@@ -1351,8 +1351,8 @@ static void video1394_remove_host (struct hpsb_host *host)
        struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
 
        if (ohci)
-               class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
-                       IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
+               device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+                              IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
        return;
 }
 
index be6b93c20f606b9e477746e81688d7abe25bcdda..ab4b2d9b5327a881da8a2bf13748d29ea72328fa 100644 (file)
@@ -30,6 +30,7 @@ struct evdev {
        wait_queue_head_t wait;
        struct evdev_client *grab;
        struct list_head client_list;
+       struct device dev;
 };
 
 struct evdev_client {
@@ -94,8 +95,10 @@ static int evdev_flush(struct file *file, fl_owner_t id)
        return input_flush_device(&evdev->handle, file);
 }
 
-static void evdev_free(struct evdev *evdev)
+static void evdev_free(struct device *dev)
 {
+       struct evdev *evdev = container_of(dev, struct evdev, dev);
+
        evdev_table[evdev->minor] = NULL;
        kfree(evdev);
 }
@@ -114,12 +117,10 @@ static int evdev_release(struct inode *inode, struct file *file)
        list_del(&client->node);
        kfree(client);
 
-       if (!--evdev->open) {
-               if (evdev->exist)
-                       input_close_device(&evdev->handle);
-               else
-                       evdev_free(evdev);
-       }
+       if (!--evdev->open && evdev->exist)
+               input_close_device(&evdev->handle);
+
+       put_device(&evdev->dev);
 
        return 0;
 }
@@ -139,24 +140,32 @@ static int evdev_open(struct inode *inode, struct file *file)
        if (!evdev || !evdev->exist)
                return -ENODEV;
 
+       get_device(&evdev->dev);
+
        client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
+       if (!client) {
+               error = -ENOMEM;
+               goto err_put_evdev;
+       }
 
        client->evdev = evdev;
        list_add_tail(&client->node, &evdev->client_list);
 
        if (!evdev->open++ && evdev->exist) {
                error = input_open_device(&evdev->handle);
-               if (error) {
-                       list_del(&client->node);
-                       kfree(client);
-                       return error;
-               }
+               if (error)
+                       goto err_free_client;
        }
 
        file->private_data = client;
        return 0;
+
+ err_free_client:
+       list_del(&client->node);
+       kfree(client);
+ err_put_evdev:
+       put_device(&evdev->dev);
+       return error;
 }
 
 #ifdef CONFIG_COMPAT
@@ -625,8 +634,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
                         const struct input_device_id *id)
 {
        struct evdev *evdev;
-       struct class_device *cdev;
-       dev_t devt;
        int minor;
        int error;
 
@@ -649,38 +656,32 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
        evdev->handle.name = evdev->name;
        evdev->handle.handler = handler;
        evdev->handle.private = evdev;
-       sprintf(evdev->name, "event%d", minor);
-
-       evdev_table[minor] = evdev;
+       snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
 
-       devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
+       snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id),
+                "event%d", minor);
+       evdev->dev.class = &input_class;
+       evdev->dev.parent = &dev->dev;
+       evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
+       evdev->dev.release = evdev_free;
+       device_initialize(&evdev->dev);
 
-       cdev = class_device_create(&input_class, &dev->cdev, devt,
-                                  dev->cdev.dev, evdev->name);
-       if (IS_ERR(cdev)) {
-               error = PTR_ERR(cdev);
-               goto err_free_evdev;
-       }
+       evdev_table[minor] = evdev;
 
-       /* temporary symlink to keep userspace happy */
-       error = sysfs_create_link(&input_class.subsys.kobj,
-                                 &cdev->kobj, evdev->name);
+       error = device_add(&evdev->dev);
        if (error)
-               goto err_cdev_destroy;
+               goto err_free_evdev;
 
        error = input_register_handle(&evdev->handle);
        if (error)
-               goto err_remove_link;
+               goto err_delete_evdev;
 
        return 0;
 
- err_remove_link:
-       sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
- err_cdev_destroy:
-       class_device_destroy(&input_class, devt);
+ err_delete_evdev:
+       device_del(&evdev->dev);
  err_free_evdev:
-       kfree(evdev);
-       evdev_table[minor] = NULL;
+       put_device(&evdev->dev);
        return error;
 }
 
@@ -690,10 +691,8 @@ static void evdev_disconnect(struct input_handle *handle)
        struct evdev_client *client;
 
        input_unregister_handle(handle);
+       device_del(&evdev->dev);
 
-       sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
-       class_device_destroy(&input_class,
-                       MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
        evdev->exist = 0;
 
        if (evdev->open) {
@@ -702,8 +701,9 @@ static void evdev_disconnect(struct input_handle *handle)
                list_for_each_entry(client, &evdev->client_list, node)
                        kill_fasync(&client->fasync, SIGIO, POLL_HUP);
                wake_up_interruptible(&evdev->wait);
-       } else
-               evdev_free(evdev);
+       }
+
+       put_device(&evdev->dev);
 }
 
 static const struct input_device_id evdev_ids[] = {
index ccd8abafcb708c2f4aedf962c5f27f4dbe9ca0dc..75b4d2a83dd99ff842308e1a96400cd809aac383 100644 (file)
@@ -442,7 +442,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
                printk(KERN_ERR
                        "input: failed to attach handler %s to device %s, "
                        "error: %d\n",
-                       handler->name, kobject_name(&dev->cdev.kobj), error);
+                       handler->name, kobject_name(&dev->dev.kobj), error);
 
        return error;
 }
@@ -527,7 +527,7 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
 static int input_devices_seq_show(struct seq_file *seq, void *v)
 {
        struct input_dev *dev = container_of(v, struct input_dev, node);
-       const char *path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
+       const char *path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
        struct input_handle *handle;
 
        seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
@@ -682,15 +682,17 @@ static inline int input_proc_init(void) { return 0; }
 static inline void input_proc_exit(void) { }
 #endif
 
-#define INPUT_DEV_STRING_ATTR_SHOW(name)                                       \
-static ssize_t input_dev_show_##name(struct class_device *dev, char *buf)      \
-{                                                                              \
-       struct input_dev *input_dev = to_input_dev(dev);                        \
-                                                                               \
-       return scnprintf(buf, PAGE_SIZE, "%s\n",                                \
-                        input_dev->name ? input_dev->name : "");               \
-}                                                                              \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL);
+#define INPUT_DEV_STRING_ATTR_SHOW(name)                               \
+static ssize_t input_dev_show_##name(struct device *dev,               \
+                                    struct device_attribute *attr,     \
+                                    char *buf)                         \
+{                                                                      \
+       struct input_dev *input_dev = to_input_dev(dev);                \
+                                                                       \
+       return scnprintf(buf, PAGE_SIZE, "%s\n",                        \
+                        input_dev->name ? input_dev->name : "");       \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)
 
 INPUT_DEV_STRING_ATTR_SHOW(name);
 INPUT_DEV_STRING_ATTR_SHOW(phys);
@@ -744,7 +746,9 @@ static int input_print_modalias(char *buf, int size, struct input_dev *id,
        return len;
 }
 
-static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf)
+static ssize_t input_dev_show_modalias(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
 {
        struct input_dev *id = to_input_dev(dev);
        ssize_t len;
@@ -753,13 +757,13 @@ static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf)
 
        return min_t(int, len, PAGE_SIZE);
 }
-static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
+static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
 
 static struct attribute *input_dev_attrs[] = {
-       &class_device_attr_name.attr,
-       &class_device_attr_phys.attr,
-       &class_device_attr_uniq.attr,
-       &class_device_attr_modalias.attr,
+       &dev_attr_name.attr,
+       &dev_attr_phys.attr,
+       &dev_attr_uniq.attr,
+       &dev_attr_modalias.attr,
        NULL
 };
 
@@ -767,13 +771,15 @@ static struct attribute_group input_dev_attr_group = {
        .attrs  = input_dev_attrs,
 };
 
-#define INPUT_DEV_ID_ATTR(name)                                                        \
-static ssize_t input_dev_show_id_##name(struct class_device *dev, char *buf)   \
-{                                                                              \
-       struct input_dev *input_dev = to_input_dev(dev);                        \
-       return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);         \
-}                                                                              \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL);
+#define INPUT_DEV_ID_ATTR(name)                                                \
+static ssize_t input_dev_show_id_##name(struct device *dev,            \
+                                       struct device_attribute *attr,  \
+                                       char *buf)                      \
+{                                                                      \
+       struct input_dev *input_dev = to_input_dev(dev);                \
+       return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)
 
 INPUT_DEV_ID_ATTR(bustype);
 INPUT_DEV_ID_ATTR(vendor);
@@ -781,10 +787,10 @@ INPUT_DEV_ID_ATTR(product);
 INPUT_DEV_ID_ATTR(version);
 
 static struct attribute *input_dev_id_attrs[] = {
-       &class_device_attr_bustype.attr,
-       &class_device_attr_vendor.attr,
-       &class_device_attr_product.attr,
-       &class_device_attr_version.attr,
+       &dev_attr_bustype.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_product.attr,
+       &dev_attr_version.attr,
        NULL
 };
 
@@ -813,15 +819,17 @@ static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
        return len;
 }
 
-#define INPUT_DEV_CAP_ATTR(ev, bm)                                             \
-static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf)    \
-{                                                                              \
-       struct input_dev *input_dev = to_input_dev(dev);                        \
-       int len = input_print_bitmap(buf, PAGE_SIZE,                            \
-                                    input_dev->bm##bit, ev##_MAX, 1);          \
-       return min_t(int, len, PAGE_SIZE);                                      \
-}                                                                              \
-static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL);
+#define INPUT_DEV_CAP_ATTR(ev, bm)                                     \
+static ssize_t input_dev_show_cap_##bm(struct device *dev,             \
+                                      struct device_attribute *attr,   \
+                                      char *buf)                       \
+{                                                                      \
+       struct input_dev *input_dev = to_input_dev(dev);                \
+       int len = input_print_bitmap(buf, PAGE_SIZE,                    \
+                                    input_dev->bm##bit, ev##_MAX, 1);  \
+       return min_t(int, len, PAGE_SIZE);                              \
+}                                                                      \
+static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)
 
 INPUT_DEV_CAP_ATTR(EV, ev);
 INPUT_DEV_CAP_ATTR(KEY, key);
@@ -834,15 +842,15 @@ INPUT_DEV_CAP_ATTR(FF, ff);
 INPUT_DEV_CAP_ATTR(SW, sw);
 
 static struct attribute *input_dev_caps_attrs[] = {
-       &class_device_attr_ev.attr,
-       &class_device_attr_key.attr,
-       &class_device_attr_rel.attr,
-       &class_device_attr_abs.attr,
-       &class_device_attr_msc.attr,
-       &class_device_attr_led.attr,
-       &class_device_attr_snd.attr,
-       &class_device_attr_ff.attr,
-       &class_device_attr_sw.attr,
+       &dev_attr_ev.attr,
+       &dev_attr_key.attr,
+       &dev_attr_rel.attr,
+       &dev_attr_abs.attr,
+       &dev_attr_msc.attr,
+       &dev_attr_led.attr,
+       &dev_attr_snd.attr,
+       &dev_attr_ff.attr,
+       &dev_attr_sw.attr,
        NULL
 };
 
@@ -858,9 +866,9 @@ static struct attribute_group *input_dev_attr_groups[] = {
        NULL
 };
 
-static void input_dev_release(struct class_device *class_dev)
+static void input_dev_release(struct device *device)
 {
-       struct input_dev *dev = to_input_dev(class_dev);
+       struct input_dev *dev = to_input_dev(device);
 
        input_ff_destroy(dev);
        kfree(dev);
@@ -947,10 +955,10 @@ static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_ind
                        return err;                                     \
        } while (0)
 
-static int input_dev_uevent(struct class_device *cdev, char **envp,
+static int input_dev_uevent(struct device *device, char **envp,
                            int num_envp, char *buffer, int buffer_size)
 {
-       struct input_dev *dev = to_input_dev(cdev);
+       struct input_dev *dev = to_input_dev(device);
        int i = 0;
        int len = 0;
 
@@ -988,10 +996,14 @@ static int input_dev_uevent(struct class_device *cdev, char **envp,
        return 0;
 }
 
+static struct device_type input_dev_type = {
+       .groups         = input_dev_attr_groups,
+       .release        = input_dev_release,
+       .uevent         = input_dev_uevent,
+};
+
 struct class input_class = {
-       .name                   = "input",
-       .release                = input_dev_release,
-       .uevent                 = input_dev_uevent,
+       .name           = "input",
 };
 EXPORT_SYMBOL_GPL(input_class);
 
@@ -1010,9 +1022,9 @@ struct input_dev *input_allocate_device(void)
 
        dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
        if (dev) {
-               dev->cdev.class = &input_class;
-               dev->cdev.groups = input_dev_attr_groups;
-               class_device_initialize(&dev->cdev);
+               dev->dev.type = &input_dev_type;
+               dev->dev.class = &input_class;
+               device_initialize(&dev->dev);
                mutex_init(&dev->mutex);
                INIT_LIST_HEAD(&dev->h_list);
                INIT_LIST_HEAD(&dev->node);
@@ -1131,17 +1143,17 @@ int input_register_device(struct input_dev *dev)
 
        list_add_tail(&dev->node, &input_dev_list);
 
-       snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
+       snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
                 "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
 
-       if (!dev->cdev.dev)
-               dev->cdev.dev = dev->dev.parent;
+       if (dev->cdev.dev)
+               dev->dev.parent = dev->cdev.dev;
 
-       error = class_device_add(&dev->cdev);
+       error = device_add(&dev->dev);
        if (error)
                return error;
 
-       path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
+       path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
        printk(KERN_INFO "input: %s as %s\n",
                dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
        kfree(path);
@@ -1173,7 +1185,7 @@ void input_unregister_device(struct input_dev *dev)
 
        list_del_init(&dev->node);
 
-       class_device_unregister(&dev->cdev);
+       device_unregister(&dev->dev);
 
        input_wakeup_procfs_readers();
 }
index 10e3b7bc925fd7b68ca8e7bb418d39471caa776c..a9a0180bfd462f1c31895641a75448e596630bcc 100644 (file)
@@ -43,6 +43,8 @@ struct joydev {
        struct input_handle handle;
        wait_queue_head_t wait;
        struct list_head client_list;
+       struct device dev;
+
        struct js_corr corr[ABS_MAX + 1];
        struct JS_DATA_SAVE_TYPE glue;
        int nabs;
@@ -138,8 +140,10 @@ static int joydev_fasync(int fd, struct file *file, int on)
        return retval < 0 ? retval : 0;
 }
 
-static void joydev_free(struct joydev *joydev)
+static void joydev_free(struct device *dev)
 {
+       struct joydev *joydev = container_of(dev, struct joydev, dev);
+
        joydev_table[joydev->minor] = NULL;
        kfree(joydev);
 }
@@ -154,12 +158,10 @@ static int joydev_release(struct inode *inode, struct file *file)
        list_del(&client->node);
        kfree(client);
 
-       if (!--joydev->open) {
-               if (joydev->exist)
-                       input_close_device(&joydev->handle);
-               else
-                       joydev_free(joydev);
-       }
+       if (!--joydev->open && joydev->exist)
+               input_close_device(&joydev->handle);
+
+       put_device(&joydev->dev);
 
        return 0;
 }
@@ -178,24 +180,32 @@ static int joydev_open(struct inode *inode, struct file *file)
        if (!joydev || !joydev->exist)
                return -ENODEV;
 
+       get_device(&joydev->dev);
+
        client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
+       if (!client) {
+               error = -ENOMEM;
+               goto err_put_joydev;
+       }
 
        client->joydev = joydev;
        list_add_tail(&client->node, &joydev->client_list);
 
        if (!joydev->open++ && joydev->exist) {
                error = input_open_device(&joydev->handle);
-               if (error) {
-                       list_del(&client->node);
-                       kfree(client);
-                       return error;
-               }
+               if (error)
+                       goto err_free_client;
        }
 
        file->private_data = client;
        return 0;
+
+ err_free_client:
+       list_del(&client->node);
+       kfree(client);
+ err_put_joydev:
+       put_device(&joydev->dev);
+       return error;
 }
 
 static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
@@ -481,8 +491,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
                          const struct input_device_id *id)
 {
        struct joydev *joydev;
-       struct class_device *cdev;
-       dev_t devt;
        int i, j, t, minor;
        int error;
 
@@ -505,7 +513,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
        joydev->handle.name = joydev->name;
        joydev->handle.handler = handler;
        joydev->handle.private = joydev;
-       sprintf(joydev->name, "js%d", minor);
+       snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
 
        for (i = 0; i < ABS_MAX + 1; i++)
                if (test_bit(i, dev->absbit)) {
@@ -547,36 +555,30 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
                joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
        }
 
-       joydev_table[minor] = joydev;
-
-       devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
+       snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
+                "js%d", minor);
+       joydev->dev.class = &input_class;
+       joydev->dev.parent = &dev->dev;
+       joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
+       joydev->dev.release = joydev_free;
+       device_initialize(&joydev->dev);
 
-       cdev = class_device_create(&input_class, &dev->cdev, devt,
-                                  dev->cdev.dev, joydev->name);
-       if (IS_ERR(cdev)) {
-               error = PTR_ERR(cdev);
-               goto err_free_joydev;
-       }
+       joydev_table[minor] = joydev;
 
-       /* temporary symlink to keep userspace happy */
-       error = sysfs_create_link(&input_class.subsys.kobj,
-                                 &cdev->kobj, joydev->name);
+       error = device_add(&joydev->dev);
        if (error)
-               goto err_cdev_destroy;
+               goto err_free_joydev;
 
        error = input_register_handle(&joydev->handle);
        if (error)
-               goto err_remove_link;
+               goto err_delete_joydev;
 
        return 0;
 
- err_remove_link:
-       sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
- err_cdev_destroy:
-       class_device_destroy(&input_class, devt);
+ err_delete_joydev:
+       device_del(&joydev->dev);
  err_free_joydev:
-       joydev_table[minor] = NULL;
-       kfree(joydev);
+       put_device(&joydev->dev);
        return error;
 }
 
@@ -587,9 +589,8 @@ static void joydev_disconnect(struct input_handle *handle)
        struct joydev_client *client;
 
        input_unregister_handle(handle);
+       device_del(&joydev->dev);
 
-       sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
-       class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
        joydev->exist = 0;
 
        if (joydev->open) {
@@ -597,8 +598,9 @@ static void joydev_disconnect(struct input_handle *handle)
                list_for_each_entry(client, &joydev->client_list, node)
                        kill_fasync(&client->fasync, SIGIO, POLL_HUP);
                wake_up_interruptible(&joydev->wait);
-       } else
-               joydev_free(joydev);
+       }
+
+       put_device(&joydev->dev);
 }
 
 static const struct input_device_id joydev_blacklist[] = {
index b0023452ec90a78c7297804ded4c0c3757d900dd..12db72d83ea0b254e048de0d68016010b153228d 100644 (file)
@@ -268,4 +268,11 @@ config JOYSTICK_XPAD
          To compile this driver as a module, choose M here: the
          module will be called xpad.
 
+config JOYSTICK_XPAD_FF
+       bool "X-Box gamepad rumble support"
+       depends on JOYSTICK_XPAD && INPUT
+       select INPUT_FF_MEMLESS
+       ---help---
+         Say Y here if you want to take advantage of xbox 360 rumble features.
+
 endif
index 555319e6378c47620d9a187b3493c5c82cfe0553..4ed3a3eadf1964eaad388e4f603720910e675811 100644 (file)
@@ -320,10 +320,10 @@ static int multiport_io(struct gameport* gameport, int sendflags, int sendcode,
 
 static int dig_mode_start(struct gameport *gameport, u32 *packet)
 {
-       int i, seq_len = sizeof(init_seq)/sizeof(int);
+       int i;
        int flags, tries = 0, bads = 0;
 
-       for (i = 0; i < seq_len; i++) {     /* Send magic sequence */
+       for (i = 0; i < ARRAY_SIZE(init_seq); i++) {     /* Send magic sequence */
                if (init_seq[i])
                        gameport_trigger(gameport);
                udelay(GRIP_INIT_DELAY);
index 8c8cd95a6989dbf8ffd5c2105b08c0837867dc9e..244089c52650f1af2eae67185f05c3277abdfe3a 100644 (file)
@@ -8,6 +8,7 @@
  *                    Ivan Hawkes <blackhawk@ivanhawkes.com>
  *               2005 Dominic Cerquetti <binary1230@yahoo.com>
  *               2006 Adam Buchbinder <adam.buchbinder@gmail.com>
+ *               2007 Jan Kratochvil <honza@jikos.cz>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -28,6 +29,7 @@
  *  - information from     http://euc.jp/periphs/xbox-controller.ja.html
  *  - the iForce driver    drivers/char/joystick/iforce.c
  *  - the skeleton-driver  drivers/usb/usb-skeleton.c
+ *  - Xbox 360 information http://www.free60.org/wiki/Gamepad
  *
  * Thanks to:
  *  - ITO Takayuki for providing essential xpad information on his website
@@ -88,6 +90,9 @@
 #define MAP_DPAD_TO_AXES       1
 #define MAP_DPAD_UNKNOWN       -1
 
+#define XTYPE_XBOX        0
+#define XTYPE_XBOX360     1
+
 static int dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
@@ -97,40 +102,42 @@ static const struct xpad_device {
        u16 idProduct;
        char *name;
        u8 dpad_mapping;
+       u8 xtype;
 } xpad_device[] = {
-       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
-       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
-       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
-       { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES },
-       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
-       { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES },
-       { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES },
-       { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES },
-       { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES },
-       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
-       { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES },
-       { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES },
-       { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES },
-       { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES },
-       { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS },
-       { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES },
-       { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS },
-       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES },
-       { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES },
-       { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES },
-       { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES },
-       { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES},
-       { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES },
-       { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES },
-       { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES },
-       { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES },
-       { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES },
-       { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES },
-       { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES },
-       { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS },
-       { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS },
-       { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES },
-       { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
+       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_XBOX }
 };
 
 static const signed short xpad_btn[] = {
@@ -146,6 +153,12 @@ static const signed short xpad_btn_pad[] = {
        -1                              /* terminating entry */
 };
 
+static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
+       BTN_TL, BTN_TR,         /* Button LB/RB */
+       BTN_MODE,               /* The big X button */
+       -1
+};
+
 static const signed short xpad_abs[] = {
        ABS_X, ABS_Y,           /* left stick */
        ABS_RX, ABS_RY,         /* right stick */
@@ -159,8 +172,12 @@ static const signed short xpad_abs_pad[] = {
        -1                      /* terminating entry */
 };
 
+/* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only
+ * USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols,
+ * but we need only one of them. */
 static struct usb_device_id xpad_table [] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* X-Box USB-IF not approved class */
+       { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) },   /* X-Box 360 controller */
        { }
 };
 
@@ -174,9 +191,16 @@ struct usb_xpad {
        unsigned char *idata;           /* input data */
        dma_addr_t idata_dma;
 
+#ifdef CONFIG_JOYSTICK_XPAD_FF
+       struct urb *irq_out;            /* urb for interrupt out report */
+       unsigned char *odata;           /* output data */
+       dma_addr_t odata_dma;
+#endif
+
        char phys[65];                  /* physical device path */
 
        int dpad_mapping;               /* map d-pad to buttons or to axes */
+       int xtype;                      /* type of xbox device */
 };
 
 /*
@@ -212,8 +236,8 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
        } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
                input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
                input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-               input_report_key(dev, BTN_0,     data[2] & 0x01); // up
-               input_report_key(dev, BTN_1,     data[2] & 0x02); // down
+               input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */
+               input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */
        }
 
        /* start/back buttons and stick press left/right */
@@ -235,6 +259,64 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
        input_sync(dev);
 }
 
+/*
+ *     xpad360_process_packet
+ *
+ *     Completes a request by converting the data into events for the
+ *     input subsystem. It is version for xbox 360 controller
+ *
+ *     The used report descriptor was taken from:
+ *             http://www.free60.org/wiki/Gamepad
+ */
+
+static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+{
+       struct input_dev *dev = xpad->dev;
+
+       /* digital pad */
+       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
+               input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+       } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
+               /* dpad as buttons (right, left, down, up) */
+               input_report_key(dev, BTN_LEFT, data[2] & 0x04);
+               input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
+               input_report_key(dev, BTN_0, data[2] & 0x01);   /* up */
+               input_report_key(dev, BTN_1, data[2] & 0x02);   /* down */
+       }
+
+       /* start/back buttons */
+       input_report_key(dev, BTN_START,  data[2] & 0x10);
+       input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+
+       /* stick press left/right */
+       input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
+       input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
+
+       /* buttons A,B,X,Y,TL,TR and MODE */
+       input_report_key(dev, BTN_A,    data[3] & 0x10);
+       input_report_key(dev, BTN_B,    data[3] & 0x20);
+       input_report_key(dev, BTN_X,    data[3] & 0x40);
+       input_report_key(dev, BTN_Y,    data[3] & 0x80);
+       input_report_key(dev, BTN_TL,   data[3] & 0x01);
+       input_report_key(dev, BTN_TR,   data[3] & 0x02);
+       input_report_key(dev, BTN_MODE, data[3] & 0x04);
+
+       /* left stick */
+       input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6]));
+       input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8]));
+
+       /* right stick */
+       input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10]));
+       input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12]));
+
+       /* triggers left/right */
+       input_report_abs(dev, ABS_Z, data[4]);
+       input_report_abs(dev, ABS_RZ, data[5]);
+
+       input_sync(dev);
+}
+
 static void xpad_irq_in(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -255,7 +337,10 @@ static void xpad_irq_in(struct urb *urb)
                goto exit;
        }
 
-       xpad_process_packet(xpad, 0, xpad->idata);
+       if (xpad->xtype == XTYPE_XBOX360)
+               xpad360_process_packet(xpad, 0, xpad->idata);
+       else
+               xpad_process_packet(xpad, 0, xpad->idata);
 
 exit:
        retval = usb_submit_urb (urb, GFP_ATOMIC);
@@ -264,7 +349,114 @@ exit:
                     __FUNCTION__, retval);
 }
 
-static int xpad_open (struct input_dev *dev)
+#ifdef CONFIG_JOYSTICK_XPAD_FF
+static void xpad_irq_out(struct urb *urb)
+{
+       int retval;
+
+       switch (urb->status) {
+               case 0:
+               /* success */
+               break;
+               case -ECONNRESET:
+               case -ENOENT:
+               case -ESHUTDOWN:
+                       /* this urb is terminated, clean up */
+                       dbg("%s - urb shutting down with status: %d",  __FUNCTION__, urb->status);
+                       return;
+               default:
+                       dbg("%s - nonzero urb status received: %d",  __FUNCTION__, urb->status);
+                       goto exit;
+       }
+
+exit:
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               err("%s - usb_submit_urb failed with result %d",
+                  __FUNCTION__, retval);
+}
+
+static int xpad_play_effect(struct input_dev *dev, void *data,
+                           struct ff_effect *effect)
+{
+       struct usb_xpad *xpad = input_get_drvdata(dev);
+
+       if (effect->type == FF_RUMBLE) {
+               __u16 strong = effect->u.rumble.strong_magnitude;
+               __u16 weak = effect->u.rumble.weak_magnitude;
+               xpad->odata[0] = 0x00;
+               xpad->odata[1] = 0x08;
+               xpad->odata[2] = 0x00;
+               xpad->odata[3] = strong / 256;
+               xpad->odata[4] = weak / 256;
+               xpad->odata[5] = 0x00;
+               xpad->odata[6] = 0x00;
+               xpad->odata[7] = 0x00;
+               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       }
+
+       return 0;
+}
+
+static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
+{
+       struct usb_endpoint_descriptor *ep_irq_out;
+       int error = -ENOMEM;
+
+       if (xpad->xtype != XTYPE_XBOX360)
+               return 0;
+
+       xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
+                                      GFP_ATOMIC, &xpad->odata_dma );
+       if (!xpad->odata)
+               goto fail1;
+
+       xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
+       if (!xpad->irq_out)
+               goto fail2;
+
+       ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
+       usb_fill_int_urb(xpad->irq_out, xpad->udev,
+                        usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
+                        xpad->odata, XPAD_PKT_LEN,
+                        xpad_irq_out, xpad, ep_irq_out->bInterval);
+       xpad->irq_out->transfer_dma = xpad->odata_dma;
+       xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+       error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+       if (error)
+               goto fail2;
+
+       return 0;
+
+ fail2:        usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
+ fail1:        return error;
+}
+
+static void xpad_stop_ff(struct usb_xpad *xpad)
+{
+       if (xpad->xtype == XTYPE_XBOX360)
+               usb_kill_urb(xpad->irq_out);
+}
+
+static void xpad_deinit_ff(struct usb_xpad *xpad)
+{
+       if (xpad->xtype == XTYPE_XBOX360) {
+               usb_free_urb(xpad->irq_out);
+               usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
+                               xpad->odata, xpad->odata_dma);
+       }
+}
+
+#else
+static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
+static void xpad_stop_ff(struct usb_xpad *xpad) { }
+static void xpad_deinit_ff(struct usb_xpad *xpad) { }
+#endif
+
+static int xpad_open(struct input_dev *dev)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
@@ -275,11 +467,12 @@ static int xpad_open (struct input_dev *dev)
        return 0;
 }
 
-static void xpad_close (struct input_dev *dev)
+static void xpad_close(struct input_dev *dev)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
        usb_kill_urb(xpad->irq_in);
+       xpad_stop_ff(xpad);
 }
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -335,6 +528,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        xpad->udev = udev;
        xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+       xpad->xtype = xpad_device[i].xtype;
        if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
                xpad->dpad_mapping = dpad_to_buttons;
        xpad->dev = input_dev;
@@ -356,6 +550,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        /* set up buttons */
        for (i = 0; xpad_btn[i] >= 0; i++)
                set_bit(xpad_btn[i], input_dev->keybit);
+       if (xpad->xtype == XTYPE_XBOX360)
+               for (i = 0; xpad360_btn[i] >= 0; i++)
+                       set_bit(xpad360_btn[i], input_dev->keybit);
        if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
                for (i = 0; xpad_btn_pad[i] >= 0; i++)
                        set_bit(xpad_btn_pad[i], input_dev->keybit);
@@ -367,6 +564,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
                    xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
 
+       error = xpad_init_ff(intf, xpad);
+       if (error)
+               goto fail2;
+
        ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -396,10 +597,10 @@ static void xpad_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        if (xpad) {
-               usb_kill_urb(xpad->irq_in);
                input_unregister_device(xpad->dev);
+               xpad_deinit_ff(xpad);
                usb_free_urb(xpad->irq_in);
-               usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
+               usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
                                xpad->idata, xpad->idata_dma);
                kfree(xpad);
        }
index 9950fcb33650a6ef015fe3343e527249df47f58f..41fc3d03b6eb495759cb93fbb7611e2acf76b712 100644 (file)
@@ -89,7 +89,7 @@ static unsigned char atkbd_set2_keycode[512] = {
          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
        173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
-       159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
+       159,  0,115,  0,164,  0,  0,116,158,  0,172,166,  0,  0,  0,142,
        157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
        226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
          0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
@@ -111,7 +111,7 @@ static unsigned char atkbd_set3_keycode[512] = {
         82, 83, 80, 76, 77, 72, 69, 98,  0, 96, 81,  0, 78, 73, 55,183,
 
        184,185,186,187, 74, 94, 92, 93,  0,  0,  0,125,126,127,112,  0,
-         0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
+         0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168,
        148,149,147,140
 };
 
index f9e82c9ca42191142dcab70ed8493072bc049d39..ebe5eacf299036c3b0c47ceac0f365c0a39bcec6 100644 (file)
@@ -140,7 +140,7 @@ static int pxakbd_resume(struct platform_device *pdev)
                KPREC = pdata->reg_kprec;
 
                /* Enable unit clock */
-               pxa_set_cken(CKEN19_KEYPAD, 1);
+               pxa_set_cken(CKEN_KEYPAD, 1);
        }
 
        mutex_unlock(&input_dev->mutex);
index 88e29074ac901c461aa687c995c3f58ae4fa353c..9b26574f1466a179a8a7782931855f2d946e3947 100644 (file)
@@ -65,9 +65,13 @@ config INPUT_COBALT_BTNS
 config INPUT_WISTRON_BTNS
        tristate "x86 Wistron laptop button interface"
        depends on X86 && !X86_64
+       select INPUT_POLLDEV
+       select NEW_LEDS
+       select LEDS_CLASS
        help
          Say Y here for support of Winstron laptop button interface, used on
-         laptops of various brands, including Acer and Fujitsu-Siemens.
+         laptops of various brands, including Acer and Fujitsu-Siemens. If
+         available, mail and wifi leds will be controlable via /sys/class/leds.
 
          To compile this driver as a module, choose M here: the module will
          be called wistron_btns.
index 961aad7a0476236c0002f1f476f8d482dcb2616b..60121f10f8d91203d481603c9295af4f52495390 100644 (file)
 #include <linux/io.h>
 #include <linux/dmi.h>
 #include <linux/init.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/mc146818rtc.h>
 #include <linux/module.h>
 #include <linux/preempt.h>
 #include <linux/string.h>
-#include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
+#include <linux/leds.h>
 
-/*
- * Number of attempts to read data from queue per poll;
- * the queue can hold up to 31 entries
- */
-#define MAX_POLL_ITERATIONS 64
-
-#define POLL_FREQUENCY 10 /* Number of polls per second */
-
-#if POLL_FREQUENCY > HZ
-#error "POLL_FREQUENCY too high"
-#endif
+/* How often we poll keys - msecs */
+#define POLL_INTERVAL_DEFAULT  500 /* when idle */
+#define POLL_INTERVAL_BURST    100 /* when a key was recently pressed */
 
 /* BIOS subsystem IDs */
 #define WIFI           0x35
 #define BLUETOOTH      0x34
+#define MAIL_LED       0x31
 
 MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
 MODULE_DESCRIPTION("Wistron laptop button driver");
 MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.2");
+MODULE_VERSION("0.3");
 
 static int force; /* = 0; */
 module_param(force, bool, 0);
@@ -248,9 +242,10 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
 #define FE_WIFI_LED 0x02
 #define FE_UNTESTED 0x80
 
-static const struct key_entry *keymap; /* = NULL; Current key map */
+static struct key_entry *keymap; /* = NULL; Current key map */
 static int have_wifi;
 static int have_bluetooth;
+static int have_leds;
 
 static int __init dmi_matched(struct dmi_system_id *dmi)
 {
@@ -263,6 +258,8 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
                else if (key->type == KE_BLUETOOTH)
                        have_bluetooth = 1;
        }
+       have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED);
+
        return 1;
 }
 
@@ -966,118 +963,163 @@ static int __init select_keymap(void)
 
  /* Input layer interface */
 
-static struct input_dev *input_dev;
+static struct input_polled_dev *wistron_idev;
+static unsigned long jiffies_last_press;
+static int wifi_enabled;
+static int bluetooth_enabled;
 
-static int __devinit setup_input_dev(void)
+static void report_key(struct input_dev *dev, unsigned int keycode)
 {
-       const struct key_entry *key;
-       int error;
+       input_report_key(dev, keycode, 1);
+       input_sync(dev);
+       input_report_key(dev, keycode, 0);
+       input_sync(dev);
+}
 
-       input_dev = input_allocate_device();
-       if (!input_dev)
-               return -ENOMEM;
+static void report_switch(struct input_dev *dev, unsigned int code, int value)
+{
+       input_report_switch(dev, code, value);
+       input_sync(dev);
+}
 
-       input_dev->name = "Wistron laptop buttons";
-       input_dev->phys = "wistron/input0";
-       input_dev->id.bustype = BUS_HOST;
-       input_dev->cdev.dev = &wistron_device->dev;
 
-       for (key = keymap; key->type != KE_END; key++) {
-               switch (key->type) {
-                       case KE_KEY:
-                               set_bit(EV_KEY, input_dev->evbit);
-                               set_bit(key->keycode, input_dev->keybit);
-                               break;
+ /* led management */
+static void wistron_mail_led_set(struct led_classdev *led_cdev,
+                               enum led_brightness value)
+{
+       bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0);
+}
 
-                       case KE_SW:
-                               set_bit(EV_SW, input_dev->evbit);
-                               set_bit(key->sw.code, input_dev->swbit);
-                               break;
+/* same as setting up wifi card, but for laptops on which the led is managed */
+static void wistron_wifi_led_set(struct led_classdev *led_cdev,
+                               enum led_brightness value)
+{
+       bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0);
+}
 
-                       default:
-                               ;
-               }
-       }
+static struct led_classdev wistron_mail_led = {
+       .name                   = "mail:green",
+       .brightness_set         = wistron_mail_led_set,
+};
 
-       /* reads information flags on KE_END */
-       if (key->code & FE_UNTESTED)
-               printk(KERN_WARNING "Untested laptop multimedia keys, "
-                       "please report success or failure to eric.piel"
-                       "@tremplin-utc.net\n");
+static struct led_classdev wistron_wifi_led = {
+       .name                   = "wifi:red",
+       .brightness_set         = wistron_wifi_led_set,
+};
 
-       error = input_register_device(input_dev);
-       if (error) {
-               input_free_device(input_dev);
-               return error;
+static void __devinit wistron_led_init(struct device *parent)
+{
+       if (have_leds & FE_WIFI_LED) {
+               u16 wifi = bios_get_default_setting(WIFI);
+               if (wifi & 1) {
+                       wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
+                       if (led_classdev_register(parent, &wistron_wifi_led))
+                               have_leds &= ~FE_WIFI_LED;
+                       else
+                               bios_set_state(WIFI, wistron_wifi_led.brightness);
+
+               } else
+                       have_leds &= ~FE_WIFI_LED;
        }
 
-       return 0;
+       if (have_leds & FE_MAIL_LED) {
+               /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
+               wistron_mail_led.brightness = LED_OFF;
+               if (led_classdev_register(parent, &wistron_mail_led))
+                       have_leds &= ~FE_MAIL_LED;
+               else
+                       bios_set_state(MAIL_LED, wistron_mail_led.brightness);
+       }
 }
 
-static void report_key(unsigned keycode)
+static void __devexit wistron_led_remove(void)
 {
-       input_report_key(input_dev, keycode, 1);
-       input_sync(input_dev);
-       input_report_key(input_dev, keycode, 0);
-       input_sync(input_dev);
+       if (have_leds & FE_MAIL_LED)
+               led_classdev_unregister(&wistron_mail_led);
+
+       if (have_leds & FE_WIFI_LED)
+               led_classdev_unregister(&wistron_wifi_led);
 }
 
-static void report_switch(unsigned code, int value)
+static inline void wistron_led_suspend(void)
 {
-       input_report_switch(input_dev, code, value);
-       input_sync(input_dev);
+       if (have_leds & FE_MAIL_LED)
+               led_classdev_suspend(&wistron_mail_led);
+
+       if (have_leds & FE_WIFI_LED)
+               led_classdev_suspend(&wistron_wifi_led);
 }
 
- /* Driver core */
+static inline void wistron_led_resume(void)
+{
+       if (have_leds & FE_MAIL_LED)
+               led_classdev_resume(&wistron_mail_led);
 
-static int wifi_enabled;
-static int bluetooth_enabled;
+       if (have_leds & FE_WIFI_LED)
+               led_classdev_resume(&wistron_wifi_led);
+}
+
+static struct key_entry *wistron_get_entry_by_scancode(int code)
+{
+       struct key_entry *key;
 
-static void poll_bios(unsigned long);
+       for (key = keymap; key->type != KE_END; key++)
+               if (code == key->code)
+                       return key;
 
-static struct timer_list poll_timer = TIMER_INITIALIZER(poll_bios, 0, 0);
+       return NULL;
+}
 
-static void handle_key(u8 code)
+static struct key_entry *wistron_get_entry_by_keycode(int keycode)
 {
-       const struct key_entry *key;
+       struct key_entry *key;
 
-       for (key = keymap; key->type != KE_END; key++) {
-               if (code == key->code) {
-                       switch (key->type) {
-                       case KE_KEY:
-                               report_key(key->keycode);
-                               break;
+       for (key = keymap; key->type != KE_END; key++)
+               if (key->type == KE_KEY && keycode == key->keycode)
+                       return key;
 
-                       case KE_SW:
-                               report_switch(key->sw.code, key->sw.value);
-                               break;
+       return NULL;
+}
 
-                       case KE_WIFI:
-                               if (have_wifi) {
-                                       wifi_enabled = !wifi_enabled;
-                                       bios_set_state(WIFI, wifi_enabled);
-                               }
-                               break;
+static void handle_key(u8 code)
+{
+       const struct key_entry *key = wistron_get_entry_by_scancode(code);
 
-                       case KE_BLUETOOTH:
-                               if (have_bluetooth) {
-                                       bluetooth_enabled = !bluetooth_enabled;
-                                       bios_set_state(BLUETOOTH, bluetooth_enabled);
-                               }
-                               break;
+       if (key) {
+               switch (key->type) {
+               case KE_KEY:
+                       report_key(wistron_idev->input, key->keycode);
+                       break;
 
-                       case KE_END:
-                               break;
-                       default:
-                               BUG();
+               case KE_SW:
+                       report_switch(wistron_idev->input,
+                                     key->sw.code, key->sw.value);
+                       break;
+
+               case KE_WIFI:
+                       if (have_wifi) {
+                               wifi_enabled = !wifi_enabled;
+                               bios_set_state(WIFI, wifi_enabled);
+                       }
+                       break;
+
+               case KE_BLUETOOTH:
+                       if (have_bluetooth) {
+                               bluetooth_enabled = !bluetooth_enabled;
+                               bios_set_state(BLUETOOTH, bluetooth_enabled);
                        }
-                       return;
+                       break;
+
+               default:
+                       BUG();
                }
-       }
-       printk(KERN_NOTICE "wistron_btns: Unknown key code %02X\n", code);
+               jiffies_last_press = jiffies;
+       } else
+               printk(KERN_NOTICE
+                       "wistron_btns: Unknown key code %02X\n", code);
 }
 
-static void poll_bios(unsigned long discard)
+static void poll_bios(bool discard)
 {
        u8 qlen;
        u16 val;
@@ -1090,15 +1132,118 @@ static void poll_bios(unsigned long discard)
                if (val != 0 && !discard)
                        handle_key((u8)val);
        }
+}
+
+static void wistron_flush(struct input_polled_dev *dev)
+{
+       /* Flush stale event queue */
+       poll_bios(true);
+}
+
+static void wistron_poll(struct input_polled_dev *dev)
+{
+       poll_bios(false);
+
+       /* Increase poll frequency if user is currently pressing keys (< 2s ago) */
+       if (time_before(jiffies, jiffies_last_press + 2 * HZ))
+               dev->poll_interval = POLL_INTERVAL_BURST;
+       else
+               dev->poll_interval = POLL_INTERVAL_DEFAULT;
+}
+
+static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+       const struct key_entry *key = wistron_get_entry_by_scancode(scancode);
+
+       if (key && key->type == KE_KEY) {
+               *keycode = key->keycode;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+       struct key_entry *key;
+       int old_keycode;
+
+       if (keycode < 0 || keycode > KEY_MAX)
+               return -EINVAL;
+
+       key = wistron_get_entry_by_scancode(scancode);
+       if (key && key->type == KE_KEY) {
+               old_keycode = key->keycode;
+               key->keycode = keycode;
+               set_bit(keycode, dev->keybit);
+               if (!wistron_get_entry_by_keycode(old_keycode))
+                       clear_bit(old_keycode, dev->keybit);
+               return 0;
+       }
 
-       mod_timer(&poll_timer, jiffies + HZ / POLL_FREQUENCY);
+       return -EINVAL;
 }
 
+static int __devinit setup_input_dev(void)
+{
+       const struct key_entry *key;
+       struct input_dev *input_dev;
+       int error;
+
+       wistron_idev = input_allocate_polled_device();
+       if (!wistron_idev)
+               return -ENOMEM;
+
+       wistron_idev->flush = wistron_flush;
+       wistron_idev->poll = wistron_poll;
+       wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
+
+       input_dev = wistron_idev->input;
+       input_dev->name = "Wistron laptop buttons";
+       input_dev->phys = "wistron/input0";
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->dev.parent = &wistron_device->dev;
+
+       input_dev->getkeycode = wistron_getkeycode;
+       input_dev->setkeycode = wistron_setkeycode;
+
+       for (key = keymap; key->type != KE_END; key++) {
+               switch (key->type) {
+                       case KE_KEY:
+                               set_bit(EV_KEY, input_dev->evbit);
+                               set_bit(key->keycode, input_dev->keybit);
+                               break;
+
+                       case KE_SW:
+                               set_bit(EV_SW, input_dev->evbit);
+                               set_bit(key->sw.code, input_dev->swbit);
+                               break;
+
+                       default:
+                               break;
+               }
+       }
+
+       /* reads information flags on KE_END */
+       if (key->code & FE_UNTESTED)
+               printk(KERN_WARNING "Untested laptop multimedia keys, "
+                       "please report success or failure to eric.piel"
+                       "@tremplin-utc.net\n");
+
+       error = input_register_polled_device(wistron_idev);
+       if (error) {
+               input_free_polled_device(wistron_idev);
+               return error;
+       }
+
+       return 0;
+}
+
+/* Driver core */
+
 static int __devinit wistron_probe(struct platform_device *dev)
 {
-       int err = setup_input_dev();
-       if (err)
-               return err;
+       int err;
 
        bios_attach();
        cmos_address = bios_get_cmos_address();
@@ -1125,15 +1270,21 @@ static int __devinit wistron_probe(struct platform_device *dev)
                        bios_set_state(BLUETOOTH, bluetooth_enabled);
        }
 
-       poll_bios(1); /* Flush stale event queue and arm timer */
+       wistron_led_init(&dev->dev);
+       err = setup_input_dev();
+       if (err) {
+               bios_detach();
+               return err;
+       }
 
        return 0;
 }
 
 static int __devexit wistron_remove(struct platform_device *dev)
 {
-       del_timer_sync(&poll_timer);
-       input_unregister_device(input_dev);
+       wistron_led_remove();
+       input_unregister_polled_device(wistron_idev);
+       input_free_polled_device(wistron_idev);
        bios_detach();
 
        return 0;
@@ -1142,14 +1293,13 @@ static int __devexit wistron_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int wistron_suspend(struct platform_device *dev, pm_message_t state)
 {
-       del_timer_sync(&poll_timer);
-
        if (have_wifi)
                bios_set_state(WIFI, 0);
 
        if (have_bluetooth)
                bios_set_state(BLUETOOTH, 0);
 
+       wistron_led_suspend();
        return 0;
 }
 
@@ -1161,7 +1311,8 @@ static int wistron_resume(struct platform_device *dev)
        if (have_bluetooth)
                bios_set_state(BLUETOOTH, bluetooth_enabled);
 
-       poll_bios(1);
+       wistron_led_resume();
+       poll_bios(true);
 
        return 0;
 }
index 50e06e8dd05d764a2af87fe7aa8d5c5e6f52db94..7bbea097cda2849108a9e5c052101226059e1802 100644 (file)
@@ -216,4 +216,20 @@ config MOUSE_HIL
        help
          Say Y here to support HIL pointers.
 
+config MOUSE_GPIO
+       tristate "GPIO mouse"
+       depends on GENERIC_GPIO
+       select INPUT_POLLDEV
+       help
+         This driver simulates a mouse on GPIO lines of various CPUs (and some
+         other chips).
+
+         Say Y here if your device has buttons or a simple joystick connected
+         directly to GPIO lines. Your board-specific setup logic must also
+         provide a platform device and platform data saying which GPIOs are
+         used.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gpio_mouse.
+
 endif
index aa4ba878533f13956b7afe867639fc43714fc894..9e6e36330820e7d9dc4092a45e2cfd53a6530204 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_MOUSE_PS2)               += psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)     += sermouse.o
 obj-$(CONFIG_MOUSE_HIL)                += hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)    += vsxxxaa.o
+obj-$(CONFIG_MOUSE_GPIO)       += gpio_mouse.o
 
 psmouse-objs := psmouse-base.o synaptics.o
 
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
new file mode 100644 (file)
index 0000000..0936d6b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Driver for simulating a mouse on GPIO lines.
+ *
+ * Copyright (C) 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 <linux/init.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input-polldev.h>
+#include <linux/gpio_mouse.h>
+
+#include <asm/gpio.h>
+
+/*
+ * Timer function which is run every scan_ms ms when the device is opened.
+ * The dev input varaible is set to the the input_dev pointer.
+ */
+static void gpio_mouse_scan(struct input_polled_dev *dev)
+{
+       struct gpio_mouse_platform_data *gpio = dev->private;
+       struct input_dev *input = dev->input;
+       int x, y;
+
+       if (gpio->bleft >= 0)
+               input_report_key(input, BTN_LEFT,
+                               gpio_get_value(gpio->bleft) ^ gpio->polarity);
+       if (gpio->bmiddle >= 0)
+               input_report_key(input, BTN_MIDDLE,
+                               gpio_get_value(gpio->bmiddle) ^ gpio->polarity);
+       if (gpio->bright >= 0)
+               input_report_key(input, BTN_RIGHT,
+                               gpio_get_value(gpio->bright) ^ gpio->polarity);
+
+       x = (gpio_get_value(gpio->right) ^ gpio->polarity)
+               - (gpio_get_value(gpio->left) ^ gpio->polarity);
+       y = (gpio_get_value(gpio->down) ^ gpio->polarity)
+               - (gpio_get_value(gpio->up) ^ gpio->polarity);
+
+       input_report_rel(input, REL_X, x);
+       input_report_rel(input, REL_Y, y);
+       input_sync(input);
+}
+
+static int __init gpio_mouse_probe(struct platform_device *pdev)
+{
+       struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
+       struct input_polled_dev *input_poll;
+       struct input_dev *input;
+       int pin, i;
+       int error;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data\n");
+               error = -ENXIO;
+               goto out;
+       }
+
+       if (pdata->scan_ms < 0) {
+               dev_err(&pdev->dev, "invalid scan time\n");
+               error = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
+               pin = pdata->pins[i];
+
+               if (pin < 0) {
+
+                       if (i <= GPIO_MOUSE_PIN_RIGHT) {
+                               /* Mouse direction is required. */
+                               dev_err(&pdev->dev,
+                                       "missing GPIO for directions\n");
+                               error = -EINVAL;
+                               goto out_free_gpios;
+                       }
+
+                       if (i == GPIO_MOUSE_PIN_BLEFT)
+                               dev_dbg(&pdev->dev, "no left button defined\n");
+
+               } else {
+                       error = gpio_request(pin, "gpio_mouse");
+                       if (error) {
+                               dev_err(&pdev->dev, "fail %d pin (%d idx)\n",
+                                       pin, i);
+                               goto out_free_gpios;
+                       }
+
+                       gpio_direction_input(pin);
+               }
+       }
+
+       input_poll = input_allocate_polled_device();
+       if (!input_poll) {
+               dev_err(&pdev->dev, "not enough memory for input device\n");
+               error = -ENOMEM;
+               goto out_free_gpios;
+       }
+
+       platform_set_drvdata(pdev, input_poll);
+
+       /* set input-polldev handlers */
+       input_poll->private = pdata;
+       input_poll->poll = gpio_mouse_scan;
+       input_poll->poll_interval = pdata->scan_ms;
+
+       input = input_poll->input;
+       input->name = pdev->name;
+       input->id.bustype = BUS_HOST;
+       input->dev.parent = &pdev->dev;
+
+       input_set_capability(input, EV_REL, REL_X);
+       input_set_capability(input, EV_REL, REL_Y);
+       if (pdata->bleft >= 0)
+               input_set_capability(input, EV_KEY, BTN_LEFT);
+       if (pdata->bmiddle >= 0)
+               input_set_capability(input, EV_KEY, BTN_MIDDLE);
+       if (pdata->bright >= 0)
+               input_set_capability(input, EV_KEY, BTN_RIGHT);
+
+       error = input_register_polled_device(input_poll);
+       if (error) {
+               dev_err(&pdev->dev, "could not register input device\n");
+               goto out_free_polldev;
+       }
+
+       dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n",
+                       pdata->scan_ms,
+                       pdata->bleft < 0 ? "" : "left ",
+                       pdata->bmiddle < 0 ? "" : "middle ",
+                       pdata->bright < 0 ? "" : "right");
+
+       return 0;
+
+ out_free_polldev:
+       input_free_polled_device(input_poll);
+       platform_set_drvdata(pdev, NULL);
+
+ out_free_gpios:
+       while (--i >= 0) {
+               pin = pdata->pins[i];
+               if (pin)
+                       gpio_free(pin);
+       }
+ out:
+       return error;
+}
+
+static int __devexit gpio_mouse_remove(struct platform_device *pdev)
+{
+       struct input_polled_dev *input = platform_get_drvdata(pdev);
+       struct gpio_mouse_platform_data *pdata = input->private;
+       int pin, i;
+
+       input_unregister_polled_device(input);
+       input_free_polled_device(input);
+
+       for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
+               pin = pdata->pins[i];
+               if (pin >= 0)
+                       gpio_free(pin);
+       }
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+struct platform_driver gpio_mouse_device_driver = {
+       .remove         = __devexit_p(gpio_mouse_remove),
+       .driver         = {
+               .name   = "gpio_mouse",
+       }
+};
+
+static int __init gpio_mouse_init(void)
+{
+       return platform_driver_probe(&gpio_mouse_device_driver,
+                       gpio_mouse_probe);
+}
+module_init(gpio_mouse_init);
+
+static void __exit gpio_mouse_exit(void)
+{
+       platform_driver_unregister(&gpio_mouse_device_driver);
+}
+module_exit(gpio_mouse_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("GPIO mouse driver");
+MODULE_LICENSE("GPL");
index f15f695777f8ff6b0c352a948a9a1bc0fe942a2f..b9f0fb2530e2357cb1f39ff1e52d48cf764ccc1b 100644 (file)
@@ -177,6 +177,15 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
                packet[1] |= (packet[0] & 0x40) << 1;
        }
 
+/*
+ * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first
+ * byte.
+ */
+       if (psmouse->type == PSMOUSE_CORTRON) {
+               input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
+               packet[0] |= 0x08;
+       }
+
 /*
  * Generic PS/2 Mouse
  */
@@ -539,6 +548,20 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
        return 0;
 }
 
+/*
+ * Cortron PS/2 protocol detection. There's no special way to detect it, so it
+ * must be forced by sysfs protocol writing.
+ */
+static int cortron_detect(struct psmouse *psmouse, int set_properties)
+{
+       if (set_properties) {
+               psmouse->vendor = "Cortron";
+               psmouse->name = "PS/2 Trackball";
+               set_bit(BTN_SIDE, psmouse->dev->keybit);
+       }
+
+       return 0;
+}
 
 /*
  * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
@@ -739,6 +762,12 @@ static const struct psmouse_protocol psmouse_protocols[] = {
                .detect         = touchkit_ps2_detect,
        },
 #endif
+       {
+               .type           = PSMOUSE_CORTRON,
+               .name           = "CortronPS/2",
+               .alias          = "cortps",
+               .detect         = cortron_detect,
+       },
        {
                .type           = PSMOUSE_AUTO,
                .name           = "auto",
index 3964e8acbc54da1b96c2f67fd12bc9f13ca61151..27a68835b5ba1559cd3a498a1730cd18de516d8e 100644 (file)
@@ -88,6 +88,7 @@ enum psmouse_type {
        PSMOUSE_LIFEBOOK,
        PSMOUSE_TRACKPOINT,
        PSMOUSE_TOUCHKIT_PS2,
+       PSMOUSE_CORTRON,
        PSMOUSE_AUTO            /* This one should always be last */
 };
 
index 3f4866d8d18c85a8dae983273ba578e2e1df3d8f..9173916b8be5f34b84a02d1697ad8bdcc0483676 100644 (file)
@@ -64,6 +64,7 @@ struct mousedev {
        wait_queue_head_t wait;
        struct list_head client_list;
        struct input_handle handle;
+       struct device dev;
 
        struct list_head mixdev_node;
        int mixdev_open;
@@ -112,7 +113,7 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 static struct input_handler mousedev_handler;
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
-static struct mousedev mousedev_mix;
+static struct mousedev *mousedev_mix;
 static LIST_HEAD(mousedev_mix_list);
 
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
@@ -218,10 +219,10 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
 
        if (value) {
                set_bit(index, &mousedev->packet.buttons);
-               set_bit(index, &mousedev_mix.packet.buttons);
+               set_bit(index, &mousedev_mix->packet.buttons);
        } else {
                clear_bit(index, &mousedev->packet.buttons);
-               clear_bit(index, &mousedev_mix.packet.buttons);
+               clear_bit(index, &mousedev_mix->packet.buttons);
        }
 }
 
@@ -287,11 +288,11 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
                         * motion packet so we won't mess current position.
                         */
                        set_bit(0, &mousedev->packet.buttons);
-                       set_bit(0, &mousedev_mix.packet.buttons);
-                       mousedev_notify_readers(mousedev, &mousedev_mix.packet);
-                       mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
+                       set_bit(0, &mousedev_mix->packet.buttons);
+                       mousedev_notify_readers(mousedev, &mousedev_mix->packet);
+                       mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet);
                        clear_bit(0, &mousedev->packet.buttons);
-                       clear_bit(0, &mousedev_mix.packet.buttons);
+                       clear_bit(0, &mousedev_mix->packet.buttons);
                }
                mousedev->touch = mousedev->pkt_count = 0;
                mousedev->frac_dx = 0;
@@ -343,7 +344,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
                                }
 
                                mousedev_notify_readers(mousedev, &mousedev->packet);
-                               mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
+                               mousedev_notify_readers(mousedev_mix, &mousedev->packet);
 
                                mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
                                mousedev->packet.abs_event = 0;
@@ -362,8 +363,10 @@ static int mousedev_fasync(int fd, struct file *file, int on)
        return retval < 0 ? retval : 0;
 }
 
-static void mousedev_free(struct mousedev *mousedev)
+static void mousedev_free(struct device *dev)
 {
+       struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
+
        mousedev_table[mousedev->minor] = NULL;
        kfree(mousedev);
 }
@@ -372,15 +375,16 @@ static int mixdev_add_device(struct mousedev *mousedev)
 {
        int error;
 
-       if (mousedev_mix.open) {
+       if (mousedev_mix->open) {
                error = input_open_device(&mousedev->handle);
                if (error)
                        return error;
 
                mousedev->open++;
-               mousedev->mixdev_open++;
+               mousedev->mixdev_open = 1;
        }
 
+       get_device(&mousedev->dev);
        list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
 
        return 0;
@@ -395,36 +399,40 @@ static void mixdev_remove_device(struct mousedev *mousedev)
        }
 
        list_del_init(&mousedev->mixdev_node);
+       put_device(&mousedev->dev);
 }
 
 static void mixdev_open_devices(void)
 {
        struct mousedev *mousedev;
 
+       if (mousedev_mix->open++)
+               return;
+
        list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-               if (mousedev->exist && !mousedev->open) {
-                       if (input_open_device(&mousedev->handle))
-                               continue;
+               if (!mousedev->mixdev_open) {
+                       if (!mousedev->open && mousedev->exist)
+                               if (input_open_device(&mousedev->handle))
+                                       continue;
 
                        mousedev->open++;
-                       mousedev->mixdev_open++;
+                       mousedev->mixdev_open = 1;
                }
        }
 }
 
 static void mixdev_close_devices(void)
 {
-       struct mousedev *mousedev, *next;
+       struct mousedev *mousedev;
 
-       list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) {
+       if (--mousedev_mix->open)
+               return;
+
+       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
                if (mousedev->mixdev_open) {
                        mousedev->mixdev_open = 0;
-                       if (!--mousedev->open) {
-                               if (mousedev->exist)
-                                       input_close_device(&mousedev->handle);
-                               else
-                                       mousedev_free(mousedev);
-                       }
+                       if (!--mousedev->open && mousedev->exist)
+                               input_close_device(&mousedev->handle);
                }
        }
 }
@@ -439,14 +447,12 @@ static int mousedev_release(struct inode *inode, struct file *file)
        list_del(&client->node);
        kfree(client);
 
-       if (!--mousedev->open) {
-               if (mousedev->minor == MOUSEDEV_MIX)
-                       mixdev_close_devices();
-               else if (mousedev->exist)
-                       input_close_device(&mousedev->handle);
-               else
-                       mousedev_free(mousedev);
-       }
+       if (mousedev->minor == MOUSEDEV_MIX)
+               mixdev_close_devices();
+       else if (!--mousedev->open && mousedev->exist)
+               input_close_device(&mousedev->handle);
+
+       put_device(&mousedev->dev);
 
        return 0;
 }
@@ -473,9 +479,13 @@ static int mousedev_open(struct inode *inode, struct file *file)
        if (!mousedev)
                return -ENODEV;
 
+       get_device(&mousedev->dev);
+
        client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
+       if (!client) {
+               error = -ENOMEM;
+               goto err_put_mousedev;
+       }
 
        spin_lock_init(&client->packet_lock);
        client->pos_x = xres / 2;
@@ -483,21 +493,23 @@ static int mousedev_open(struct inode *inode, struct file *file)
        client->mousedev = mousedev;
        list_add_tail(&client->node, &mousedev->client_list);
 
-       if (!mousedev->open++) {
-               if (mousedev->minor == MOUSEDEV_MIX)
-                       mixdev_open_devices();
-               else if (mousedev->exist) {
-                       error = input_open_device(&mousedev->handle);
-                       if (error) {
-                               list_del(&client->node);
-                               kfree(client);
-                               return error;
-                       }
-               }
+       if (mousedev->minor == MOUSEDEV_MIX)
+               mixdev_open_devices();
+       else if (!mousedev->open++ && mousedev->exist) {
+               error = input_open_device(&mousedev->handle);
+               if (error)
+                       goto err_free_client;
        }
 
        file->private_data = client;
        return 0;
+
+ err_free_client:
+       list_del(&client->node);
+       kfree(client);
+ err_put_mousedev:
+       put_device(&mousedev->dev);
+       return error;
 }
 
 static inline int mousedev_limit_delta(int delta, int limit)
@@ -680,57 +692,96 @@ static const struct file_operations mousedev_fops = {
        .fasync =       mousedev_fasync,
 };
 
-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
-                           const struct input_device_id *id)
+static struct mousedev *mousedev_create(struct input_dev *dev,
+                                       struct input_handler *handler,
+                                       int minor)
 {
        struct mousedev *mousedev;
-       struct class_device *cdev;
-       dev_t devt;
-       int minor;
        int error;
 
-       for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
-       if (minor == MOUSEDEV_MINORS) {
-               printk(KERN_ERR "mousedev: no more free mousedev devices\n");
-               return -ENFILE;
-       }
-
        mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
-       if (!mousedev)
-               return -ENOMEM;
+       if (!mousedev) {
+               error = -ENOMEM;
+               goto err_out;
+       }
 
        INIT_LIST_HEAD(&mousedev->client_list);
        INIT_LIST_HEAD(&mousedev->mixdev_node);
        init_waitqueue_head(&mousedev->wait);
 
+       if (minor == MOUSEDEV_MIX)
+               strlcpy(mousedev->name, "mice", sizeof(mousedev->name));
+       else
+               snprintf(mousedev->name, sizeof(mousedev->name),
+                        "mouse%d", minor);
+
        mousedev->minor = minor;
        mousedev->exist = 1;
        mousedev->handle.dev = dev;
        mousedev->handle.name = mousedev->name;
        mousedev->handle.handler = handler;
        mousedev->handle.private = mousedev;
-       sprintf(mousedev->name, "mouse%d", minor);
 
-       mousedev_table[minor] = mousedev;
+       strlcpy(mousedev->dev.bus_id, mousedev->name,
+               sizeof(mousedev->dev.bus_id));
+       mousedev->dev.class = &input_class;
+       if (dev)
+               mousedev->dev.parent = &dev->dev;
+       mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
+       mousedev->dev.release = mousedev_free;
+       device_initialize(&mousedev->dev);
 
-       devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
+       mousedev_table[minor] = mousedev;
 
-       cdev = class_device_create(&input_class, &dev->cdev, devt,
-                                  dev->cdev.dev, mousedev->name);
-       if (IS_ERR(cdev)) {
-               error = PTR_ERR(cdev);
+       error = device_add(&mousedev->dev);
+       if (error)
                goto err_free_mousedev;
+
+       return mousedev;
+
+ err_free_mousedev:
+       put_device(&mousedev->dev);
+ err_out:
+       return ERR_PTR(error);
+}
+
+static void mousedev_destroy(struct mousedev *mousedev)
+{
+       struct mousedev_client *client;
+
+       device_del(&mousedev->dev);
+       mousedev->exist = 0;
+
+       if (mousedev->open) {
+               input_close_device(&mousedev->handle);
+               list_for_each_entry(client, &mousedev->client_list, node)
+                       kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+               wake_up_interruptible(&mousedev->wait);
        }
 
-       /* temporary symlink to keep userspace happy */
-       error = sysfs_create_link(&input_class.subsys.kobj,
-                                 &cdev->kobj, mousedev->name);
-       if (error)
-               goto err_cdev_destroy;
+       put_device(&mousedev->dev);
+}
+
+static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+                           const struct input_device_id *id)
+{
+       struct mousedev *mousedev;
+       int minor;
+       int error;
+
+       for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+       if (minor == MOUSEDEV_MINORS) {
+               printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+               return -ENFILE;
+       }
+
+       mousedev = mousedev_create(dev, handler, minor);
+       if (IS_ERR(mousedev))
+               return PTR_ERR(mousedev);
 
        error = input_register_handle(&mousedev->handle);
        if (error)
-               goto err_remove_link;
+               goto err_delete_mousedev;
 
        error = mixdev_add_device(mousedev);
        if (error)
@@ -740,37 +791,18 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev
 
  err_unregister_handle:
        input_unregister_handle(&mousedev->handle);
- err_remove_link:
-       sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
- err_cdev_destroy:
-       class_device_destroy(&input_class, devt);
- err_free_mousedev:
-       mousedev_table[minor] = NULL;
-       kfree(mousedev);
+ err_delete_mousedev:
+       device_unregister(&mousedev->dev);
        return error;
 }
 
 static void mousedev_disconnect(struct input_handle *handle)
 {
        struct mousedev *mousedev = handle->private;
-       struct mousedev_client *client;
-
-       input_unregister_handle(handle);
-
-       sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
-       class_device_destroy(&input_class,
-                       MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
-       mousedev->exist = 0;
 
        mixdev_remove_device(mousedev);
-
-       if (mousedev->open) {
-               input_close_device(handle);
-               list_for_each_entry(client, &mousedev->client_list, node)
-                       kill_fasync(&client->fasync, SIGIO, POLL_HUP);
-               wake_up_interruptible(&mousedev->wait);
-       } else
-               mousedev_free(mousedev);
+       input_unregister_handle(handle);
+       mousedev_destroy(mousedev);
 }
 
 static const struct input_device_id mousedev_ids[] = {
@@ -822,25 +854,16 @@ static int psaux_registered;
 
 static int __init mousedev_init(void)
 {
-       struct class_device *cdev;
        int error;
 
+       mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
+       if (IS_ERR(mousedev_mix))
+               return PTR_ERR(mousedev_mix);
+
        error = input_register_handler(&mousedev_handler);
-       if (error)
+       if (error) {
+               mousedev_destroy(mousedev_mix);
                return error;
-
-       memset(&mousedev_mix, 0, sizeof(struct mousedev));
-       INIT_LIST_HEAD(&mousedev_mix.client_list);
-       init_waitqueue_head(&mousedev_mix.wait);
-       mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
-       mousedev_mix.exist = 1;
-       mousedev_mix.minor = MOUSEDEV_MIX;
-
-       cdev = class_device_create(&input_class, NULL,
-                       MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice");
-       if (IS_ERR(cdev)) {
-               input_unregister_handler(&mousedev_handler);
-               return PTR_ERR(cdev);
        }
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
@@ -863,9 +886,8 @@ static void __exit mousedev_exit(void)
        if (psaux_registered)
                misc_deregister(&psaux_mouse);
 #endif
-       class_device_destroy(&input_class,
-                       MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX));
        input_unregister_handler(&mousedev_handler);
+       mousedev_destroy(mousedev_mix);
 }
 
 module_init(mousedev_init);
index 887357666c683f0337dfe8dfef3756fd3fe77ad2..0403622ae26752976327823802861b321b521d69 100644 (file)
@@ -160,7 +160,7 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou
 {
        struct serio_raw_list *list = file->private_data;
        struct serio_raw *serio_raw = list->serio_raw;
-       char c;
+       char uninitialized_var(c);
        ssize_t retval = 0;
 
        if (!serio_raw->serio)
index cc0a498763d8db609e7dd03d5086f50010931765..94683f58c9e18ec5b933d7721ab3b07467ae9a1c 100644 (file)
@@ -82,8 +82,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.5 (May-15-2004)"
-#define DRIVER_AUTHOR  "Bryan W. Headley/Chris Atenasio"
+#define DRIVER_VERSION "v2.3 (May 2, 2007)"
+#define DRIVER_AUTHOR  "Bryan W. Headley/Chris Atenasio/Cedric Brun/Rene van Paassen"
 #define DRIVER_DESC    "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)"
 
 /*
  * (returned as Report 3 - absolute coordinates from the mouse)
  *
  *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     1     0
+ * byte0   0     0     0     0     0     0     1     1
  * byte1  X7    X6    X5    X4    X3    X2    X1    X0
  * byte2  X15   X14   X13   X12   X11   X10   X9    X8
  * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
  * (returned as Report 5 - macrokeys from the mouse)
  *
  *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     1     0     0
+ * byte0   0     0     0     0     0     1     0     1
  * byte1   0     0     0    BS2   BS    Tip   IR    DV
  * byte2   0     0     0     0     0     0     1     0
  * byte3   0     0     0    K4    K3    K2    K1    K0
 #define AIPTEK_WHEEL_DISABLE                           (-10101)
 
        /* ToolCode values, which BTW are 0x140 .. 0x14f
-        * We have things set up such that if TOOL_BUTTON_FIRED_BIT is
-        * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx.
-        *
-        * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will
-        * get reset.
+        * We have things set up such that if the tool button has changed,
+        * the tools get reset.
         */
-#define TOOL_BUTTON(x)                                 ((x) & 0x14f)
-#define TOOL_BUTTON_FIRED(x)                           ((x) & 0x200)
-#define TOOL_BUTTON_FIRED_BIT                          0x200
        /* toolMode codes
         */
 #define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
 
        /* Mouse button programming
         */
-#define AIPTEK_MOUSE_LEFT_BUTTON               0x01
-#define AIPTEK_MOUSE_RIGHT_BUTTON              0x02
-#define AIPTEK_MOUSE_MIDDLE_BUTTON             0x04
+#define AIPTEK_MOUSE_LEFT_BUTTON               0x04
+#define AIPTEK_MOUSE_RIGHT_BUTTON              0x08
+#define AIPTEK_MOUSE_MIDDLE_BUTTON             0x10
 
        /* Stylus button programming
         */
@@ -294,7 +288,6 @@ struct aiptek_features {
        int modelCode;          /* Tablet model code (not unique) */
        int firmwareCode;       /* prom/eeprom version            */
        char usbPath[64 + 1];   /* device's physical usb path     */
-       char inputPath[64 + 1]; /* input device path              */
 };
 
 struct aiptek_settings {
@@ -327,9 +320,32 @@ struct aiptek {
        int inDelay;                            /* jitter: in jitter delay?      */
        unsigned long endDelay;                 /* jitter: time when delay ends  */
        int previousJitterable;                 /* jitterable prev value     */
+
+       int lastMacro;                          /* macro key to reset            */
+       int previousToolMode;                   /* pen, pencil, brush, etc. tool */
        unsigned char *data;                    /* incoming packet data          */
 };
 
+static const int eventTypes[] = {
+        EV_KEY, EV_ABS, EV_REL, EV_MSC,
+};
+
+static const int absEvents[] = {
+        ABS_X, ABS_Y, ABS_PRESSURE, ABS_TILT_X, ABS_TILT_Y,
+        ABS_WHEEL, ABS_MISC,
+};
+
+static const int relEvents[] = {
+        REL_X, REL_Y, REL_WHEEL,
+};
+
+static const int buttonEvents[] = {
+       BTN_LEFT, BTN_RIGHT, BTN_MIDDLE,
+       BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_PENCIL, BTN_TOOL_AIRBRUSH,
+       BTN_TOOL_BRUSH, BTN_TOOL_MOUSE, BTN_TOOL_LENS, BTN_TOUCH,
+       BTN_STYLUS, BTN_STYLUS2,
+};
+
 /*
  * Permit easy lookup of keyboard events to send, versus
  * the bitmap which comes from the tablet. This hides the
@@ -345,23 +361,39 @@ static const int macroKeyEvents[] = {
 };
 
 /***********************************************************************
- * Relative reports deliver values in 2's complement format to
- * deal with negative offsets.
+ * Map values to strings and back. Every map shoudl have the following
+ * as its last element: { NULL, AIPTEK_INVALID_VALUE }.
  */
-static int aiptek_convert_from_2s_complement(unsigned char c)
+#define AIPTEK_INVALID_VALUE   -1
+
+struct aiptek_map {
+       const char *string;
+       int value;
+};
+
+static int map_str_to_val(const struct aiptek_map *map, const char *str, size_t count)
 {
-       int ret;
-       unsigned char b = c;
-       int negate = 0;
+       const struct aiptek_map *p;
 
-       if ((b & 0x80) != 0) {
-               b = ~b;
-               b--;
-               negate = 1;
-       }
-       ret = b;
-       ret = (negate == 1) ? -ret : ret;
-       return ret;
+       if (str[count - 1] == '\n')
+               count--;
+
+       for (p = map; p->string; p++)
+               if (!strncmp(str, p->string, count))
+                       return p->value;
+
+       return AIPTEK_INVALID_VALUE;
+}
+
+static const char *map_val_to_str(const struct aiptek_map *map, int val)
+{
+       const struct aiptek_map *p;
+
+       for (p = map; p->value != AIPTEK_INVALID_VALUE; p++)
+               if (val == p->value)
+                       return p->string;
+
+       return "unknown";
 }
 
 /***********************************************************************
@@ -385,6 +417,9 @@ static int aiptek_convert_from_2s_complement(unsigned char c)
  * Proximity. Why two events? I thought it interesting to know if the
  * Proximity event occurred while the tablet was in absolute or relative
  * mode.
+ * Update: REL_MISC proved not to be such a good idea. With REL_MISC you
+ * get an event transmitted each time. ABS_MISC works better, since it
+ * can be set and re-set. Thus, only using ABS_MISC from now on.
  *
  * Other tablets use the notion of a certain minimum stylus pressure
  * to infer proximity. While that could have been done, that is yet
@@ -441,8 +476,8 @@ static void aiptek_irq(struct urb *urb)
                        aiptek->diagnostic =
                            AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
                } else {
-                       x = aiptek_convert_from_2s_complement(data[2]);
-                       y = aiptek_convert_from_2s_complement(data[3]);
+                       x = (signed char) data[2];
+                       y = (signed char) data[3];
 
                        /* jitterable keeps track of whether any button has been pressed.
                         * We're also using it to remap the physical mouse button mask
@@ -451,18 +486,20 @@ static void aiptek_irq(struct urb *urb)
                         * that a non-zero value indicates that one or more
                         * mouse button was pressed.)
                         */
-                       jitterable = data[5] & 0x07;
+                       jitterable = data[1] & 0x07;
 
-                       left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-                       right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-                       middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+                       left = (data[1] & aiptek->curSetting.mouseButtonLeft >> 2) != 0 ? 1 : 0;
+                       right = (data[1] & aiptek->curSetting.mouseButtonRight >> 2) != 0 ? 1 : 0;
+                       middle = (data[1] & aiptek->curSetting.mouseButtonMiddle >> 2) != 0 ? 1 : 0;
 
                        input_report_key(inputdev, BTN_LEFT, left);
                        input_report_key(inputdev, BTN_MIDDLE, middle);
                        input_report_key(inputdev, BTN_RIGHT, right);
+
+                       input_report_abs(inputdev, ABS_MISC,
+                                        1 | AIPTEK_REPORT_TOOL_UNKNOWN);
                        input_report_rel(inputdev, REL_X, x);
                        input_report_rel(inputdev, REL_Y, y);
-                       input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
 
                        /* Wheel support is in the form of a single-event
                         * firing.
@@ -472,6 +509,11 @@ static void aiptek_irq(struct urb *urb)
                                                 aiptek->curSetting.wheel);
                                aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
                        }
+                       if (aiptek->lastMacro != -1) {
+                               input_report_key(inputdev,
+                                                macroKeyEvents[aiptek->lastMacro], 0);
+                               aiptek->lastMacro = -1;
+                       }
                        input_sync(inputdev);
                }
        }
@@ -489,8 +531,8 @@ static void aiptek_irq(struct urb *urb)
                        y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
                        z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
 
-                       p = (data[5] & 0x01) != 0 ? 1 : 0;
-                       dv = (data[5] & 0x02) != 0 ? 1 : 0;
+                       dv = (data[5] & 0x01) != 0 ? 1 : 0;
+                       p = (data[5] & 0x02) != 0 ? 1 : 0;
                        tip = (data[5] & 0x04) != 0 ? 1 : 0;
 
                        /* Use jitterable to re-arrange button masks
@@ -505,16 +547,18 @@ static void aiptek_irq(struct urb *urb)
                         * all 'bad' reports...
                         */
                        if (dv != 0) {
-                               /* If we've not already sent a tool_button_?? code, do
-                                * so now. Then set FIRED_BIT so it won't be resent unless
-                                * the user forces FIRED_BIT off.
+                               /* If the selected tool changed, reset the old
+                                * tool key, and set the new one.
                                 */
-                               if (TOOL_BUTTON_FIRED
-                                   (aiptek->curSetting.toolMode) == 0) {
+                               if (aiptek->previousToolMode !=
+                                   aiptek->curSetting.toolMode) {
+                                       input_report_key(inputdev,
+                                                        aiptek->previousToolMode, 0);
                                        input_report_key(inputdev,
-                                                        TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                        aiptek->curSetting.toolMode,
                                                         1);
-                                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                                       aiptek->previousToolMode =
+                                                 aiptek->curSetting.toolMode;
                                }
 
                                if (p != 0) {
@@ -550,6 +594,11 @@ static void aiptek_irq(struct urb *urb)
                                        }
                                }
                                input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
+                               if (aiptek->lastMacro != -1) {
+                                       input_report_key(inputdev,
+                                                        macroKeyEvents[aiptek->lastMacro], 0);
+                                       aiptek->lastMacro = -1;
+                               }
                                input_sync(inputdev);
                        }
                }
@@ -568,23 +617,25 @@ static void aiptek_irq(struct urb *urb)
 
                        jitterable = data[5] & 0x1c;
 
-                       p = (data[5] & 0x01) != 0 ? 1 : 0;
-                       dv = (data[5] & 0x02) != 0 ? 1 : 0;
+                       dv = (data[5] & 0x01) != 0 ? 1 : 0;
+                       p = (data[5] & 0x02) != 0 ? 1 : 0;
                        left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
                        right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
                        middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
 
                        if (dv != 0) {
-                               /* If we've not already sent a tool_button_?? code, do
-                                * so now. Then set FIRED_BIT so it won't be resent unless
-                                * the user forces FIRED_BIT off.
+                               /* If the selected tool changed, reset the old
+                                * tool key, and set the new one.
                                 */
-                               if (TOOL_BUTTON_FIRED
-                                   (aiptek->curSetting.toolMode) == 0) {
+                               if (aiptek->previousToolMode !=
+                                   aiptek->curSetting.toolMode) {
+                                       input_report_key(inputdev,
+                                                        aiptek->previousToolMode, 0);
                                        input_report_key(inputdev,
-                                                        TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                        aiptek->curSetting.toolMode,
                                                         1);
-                                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                                       aiptek->previousToolMode =
+                                                 aiptek->curSetting.toolMode;
                                }
 
                                if (p != 0) {
@@ -605,7 +656,12 @@ static void aiptek_irq(struct urb *urb)
                                                aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
                                        }
                                }
-                               input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
+                               input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
+                               if (aiptek->lastMacro != -1) {
+                                       input_report_key(inputdev,
+                                                        macroKeyEvents[aiptek->lastMacro], 0);
+                                       aiptek->lastMacro = -1;
+                               }
                                input_sync(inputdev);
                        }
                }
@@ -615,98 +671,83 @@ static void aiptek_irq(struct urb *urb)
        else if (data[0] == 4) {
                jitterable = data[1] & 0x18;
 
-               p = (data[1] & 0x01) != 0 ? 1 : 0;
-               dv = (data[1] & 0x02) != 0 ? 1 : 0;
+               dv = (data[1] & 0x01) != 0 ? 1 : 0;
+               p = (data[1] & 0x02) != 0 ? 1 : 0;
                tip = (data[1] & 0x04) != 0 ? 1 : 0;
                bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
                pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
 
-               macro = data[3];
+               macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1;
                z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
 
-               if (dv != 0) {
-                       /* If we've not already sent a tool_button_?? code, do
-                        * so now. Then set FIRED_BIT so it won't be resent unless
-                        * the user forces FIRED_BIT off.
+               if (dv) {
+                       /* If the selected tool changed, reset the old
+                        * tool key, and set the new one.
                         */
-                       if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+                       if (aiptek->previousToolMode !=
+                           aiptek->curSetting.toolMode) {
+                               input_report_key(inputdev,
+                                                aiptek->previousToolMode, 0);
                                input_report_key(inputdev,
-                                                TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                aiptek->curSetting.toolMode,
                                                 1);
-                               aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                               aiptek->previousToolMode =
+                                       aiptek->curSetting.toolMode;
                        }
+               }
 
-                       if (p != 0) {
-                               input_report_key(inputdev, BTN_TOUCH, tip);
-                               input_report_key(inputdev, BTN_STYLUS, bs);
-                               input_report_key(inputdev, BTN_STYLUS2, pck);
-                               input_report_abs(inputdev, ABS_PRESSURE, z);
-                       }
+               if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) {
+                       input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0);
+                       aiptek->lastMacro = -1;
+               }
 
-                       /* For safety, we're sending key 'break' codes for the
-                        * neighboring macro keys.
-                        */
-                       if (macro > 0) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro - 1], 0);
-                       }
-                       if (macro < 25) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro + 1], 0);
-                       }
-                       input_report_key(inputdev, macroKeyEvents[macro], p);
-                       input_report_abs(inputdev, ABS_MISC,
-                                        p | AIPTEK_REPORT_TOOL_STYLUS);
-                       input_sync(inputdev);
+               if (macro != -1 && macro != aiptek->lastMacro) {
+                       input_report_key(inputdev, macroKeyEvents[macro], 1);
+                       aiptek->lastMacro = macro;
                }
+               input_report_abs(inputdev, ABS_MISC,
+                                p | AIPTEK_REPORT_TOOL_STYLUS);
+               input_sync(inputdev);
        }
        /* Report 5s come from the macro keys when pressed by mouse
         */
        else if (data[0] == 5) {
                jitterable = data[1] & 0x1c;
 
-               p = (data[1] & 0x01) != 0 ? 1 : 0;
-               dv = (data[1] & 0x02) != 0 ? 1 : 0;
+               dv = (data[1] & 0x01) != 0 ? 1 : 0;
+               p = (data[1] & 0x02) != 0 ? 1 : 0;
                left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
                right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
                middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-               macro = data[3];
+               macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : 0;
 
-               if (dv != 0) {
-                       /* If we've not already sent a tool_button_?? code, do
-                        * so now. Then set FIRED_BIT so it won't be resent unless
-                        * the user forces FIRED_BIT off.
+               if (dv) {
+                       /* If the selected tool changed, reset the old
+                        * tool key, and set the new one.
                         */
-                       if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-                               input_report_key(inputdev,
-                                                TOOL_BUTTON(aiptek->curSetting.toolMode),
-                                                1);
-                               aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-                       }
-
-                       if (p != 0) {
-                               input_report_key(inputdev, BTN_LEFT, left);
-                               input_report_key(inputdev, BTN_MIDDLE, middle);
-                               input_report_key(inputdev, BTN_RIGHT, right);
+                       if (aiptek->previousToolMode !=
+                           aiptek->curSetting.toolMode) {
+                               input_report_key(inputdev,
+                                                aiptek->previousToolMode, 0);
+                               input_report_key(inputdev,
+                                                aiptek->curSetting.toolMode, 1);
+                               aiptek->previousToolMode = aiptek->curSetting.toolMode;
                        }
+               }
 
-                       /* For safety, we're sending key 'break' codes for the
-                        * neighboring macro keys.
-                        */
-                       if (macro > 0) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro - 1], 0);
-                       }
-                       if (macro < 25) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro + 1], 0);
-                       }
+               if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) {
+                       input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0);
+                       aiptek->lastMacro = -1;
+               }
 
+               if (macro != -1 && macro != aiptek->lastMacro) {
                        input_report_key(inputdev, macroKeyEvents[macro], 1);
-                       input_report_rel(inputdev, ABS_MISC,
-                                        p | AIPTEK_REPORT_TOOL_MOUSE);
-                       input_sync(inputdev);
+                       aiptek->lastMacro = macro;
                }
+
+               input_report_abs(inputdev, ABS_MISC,
+                                p | AIPTEK_REPORT_TOOL_MOUSE);
+               input_sync(inputdev);
        }
        /* We have no idea which tool can generate a report 6. Theoretically,
         * neither need to, having been given reports 4 & 5 for such use.
@@ -725,15 +766,18 @@ static void aiptek_irq(struct urb *urb)
                                         0);
                }
 
-               /* If we've not already sent a tool_button_?? code, do
-                * so now. Then set FIRED_BIT so it won't be resent unless
-                * the user forces FIRED_BIT off.
-                */
-               if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+               /* If the selected tool changed, reset the old
+                  tool key, and set the new one.
+               */
+               if (aiptek->previousToolMode !=
+                   aiptek->curSetting.toolMode) {
+                       input_report_key(inputdev,
+                                        aiptek->previousToolMode, 0);
                        input_report_key(inputdev,
-                                        TOOL_BUTTON(aiptek->curSetting.
-                                                    toolMode), 1);
-                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                                        aiptek->curSetting.toolMode,
+                                        1);
+                       aiptek->previousToolMode =
+                               aiptek->curSetting.toolMode;
                }
 
                input_report_key(inputdev, macroKeyEvents[macro], 1);
@@ -1007,9 +1051,6 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "%dx%d\n",
                        aiptek->inputdev->absmax[ABS_X] + 1,
                        aiptek->inputdev->absmax[ABS_Y] + 1);
@@ -1023,118 +1064,36 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr
  */
 static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL);
 
-/***********************************************************************
- * support routines for the 'product_id' file
- */
-static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n",
-                       aiptek->inputdev->id.product);
-}
-
-static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL);
-
-/***********************************************************************
- * support routines for the 'vendor_id' file
- */
-static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor);
-}
-
-static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL);
-
-/***********************************************************************
- * support routines for the 'vendor' file
- */
-static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       int retval;
-
-       if (aiptek == NULL)
-               return 0;
-
-       retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
-       return retval;
-}
-
-static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL);
-
-/***********************************************************************
- * support routines for the 'product' file
- */
-static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       int retval;
-
-       if (aiptek == NULL)
-               return 0;
-
-       retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
-       return retval;
-}
-
-static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL);
-
 /***********************************************************************
  * support routines for the 'pointer_mode' file. Note that this file
  * both displays current setting and allows reprogramming.
  */
+static struct aiptek_map pointer_mode_map[] = {
+       { "stylus",     AIPTEK_POINTER_ONLY_STYLUS_MODE },
+       { "mouse",      AIPTEK_POINTER_ONLY_MOUSE_MODE },
+       { "either",     AIPTEK_POINTER_EITHER_MODE },
+       { NULL,         AIPTEK_INVALID_VALUE }
+};
+
 static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.pointerMode) {
-       case AIPTEK_POINTER_ONLY_STYLUS_MODE:
-               s = "stylus";
-               break;
-
-       case AIPTEK_POINTER_ONLY_MOUSE_MODE:
-               s = "mouse";
-               break;
-
-       case AIPTEK_POINTER_EITHER_MODE:
-               s = "either";
-               break;
 
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(pointer_mode_map,
+                                       aiptek->curSetting.pointerMode));
 }
 
 static ssize_t
 store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       if (aiptek == NULL)
-               return 0;
+       int new_mode = map_str_to_val(pointer_mode_map, buf, count);
 
-       if (strcmp(buf, "stylus") == 0) {
-               aiptek->newSetting.pointerMode =
-                   AIPTEK_POINTER_ONLY_STYLUS_MODE;
-       } else if (strcmp(buf, "mouse") == 0) {
-               aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE;
-       } else if (strcmp(buf, "either") == 0) {
-               aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
-       }
+       if (new_mode == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
+
+       aiptek->newSetting.pointerMode = new_mode;
        return count;
 }
 
@@ -1146,44 +1105,32 @@ static DEVICE_ATTR(pointer_mode,
  * support routines for the 'coordinate_mode' file. Note that this file
  * both displays current setting and allows reprogramming.
  */
+
+static struct aiptek_map coordinate_mode_map[] = {
+       { "absolute",   AIPTEK_COORDINATE_ABSOLUTE_MODE },
+       { "relative",   AIPTEK_COORDINATE_RELATIVE_MODE },
+       { NULL,         AIPTEK_INVALID_VALUE }
+};
+
 static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
 
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.coordinateMode) {
-       case AIPTEK_COORDINATE_ABSOLUTE_MODE:
-               s = "absolute";
-               break;
-
-       case AIPTEK_COORDINATE_RELATIVE_MODE:
-               s = "relative";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(coordinate_mode_map,
+                                       aiptek->curSetting.coordinateMode));
 }
 
 static ssize_t
 store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       if (aiptek == NULL)
-               return 0;
+       int new_mode = map_str_to_val(coordinate_mode_map, buf, count);
 
-       if (strcmp(buf, "absolute") == 0) {
-               aiptek->newSetting.pointerMode =
-                   AIPTEK_COORDINATE_ABSOLUTE_MODE;
-       } else if (strcmp(buf, "relative") == 0) {
-               aiptek->newSetting.pointerMode =
-                   AIPTEK_COORDINATE_RELATIVE_MODE;
-       }
+       if (new_mode == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
+
+       aiptek->newSetting.coordinateMode = new_mode;
        return count;
 }
 
@@ -1195,73 +1142,37 @@ static DEVICE_ATTR(coordinate_mode,
  * support routines for the 'tool_mode' file. Note that this file
  * both displays current setting and allows reprogramming.
  */
+
+static struct aiptek_map tool_mode_map[] = {
+       { "mouse",      AIPTEK_TOOL_BUTTON_MOUSE_MODE },
+       { "eraser",     AIPTEK_TOOL_BUTTON_ERASER_MODE },
+       { "pencil",     AIPTEK_TOOL_BUTTON_PENCIL_MODE },
+       { "pen",        AIPTEK_TOOL_BUTTON_PEN_MODE },
+       { "brush",      AIPTEK_TOOL_BUTTON_BRUSH_MODE },
+       { "airbrush",   AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE },
+       { "lens",       AIPTEK_TOOL_BUTTON_LENS_MODE },
+       { NULL,         AIPTEK_INVALID_VALUE }
+};
+
 static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) {
-       case AIPTEK_TOOL_BUTTON_MOUSE_MODE:
-               s = "mouse";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_ERASER_MODE:
-               s = "eraser";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_PENCIL_MODE:
-               s = "pencil";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_PEN_MODE:
-               s = "pen";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_BRUSH_MODE:
-               s = "brush";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE:
-               s = "airbrush";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_LENS_MODE:
-               s = "lens";
-               break;
 
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(tool_mode_map,
+                                       aiptek->curSetting.toolMode));
 }
 
 static ssize_t
 store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       if (aiptek == NULL)
-               return 0;
+       int new_mode = map_str_to_val(tool_mode_map, buf, count);
 
-       if (strcmp(buf, "mouse") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE;
-       } else if (strcmp(buf, "eraser") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE;
-       } else if (strcmp(buf, "pencil") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE;
-       } else if (strcmp(buf, "pen") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
-       } else if (strcmp(buf, "brush") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE;
-       } else if (strcmp(buf, "airbrush") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE;
-       } else if (strcmp(buf, "lens") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE;
-       }
+       if (new_mode == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
 
+       aiptek->newSetting.toolMode = new_mode;
        return count;
 }
 
@@ -1277,9 +1188,6 @@ static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *att
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
                return snprintf(buf, PAGE_SIZE, "disable\n");
        } else {
@@ -1294,9 +1202,6 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char
        struct aiptek *aiptek = dev_get_drvdata(dev);
        int x;
 
-       if (aiptek == NULL)
-               return 0;
-
        if (strcmp(buf, "disable") == 0) {
                aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
        } else {
@@ -1319,9 +1224,6 @@ static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *att
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
                return snprintf(buf, PAGE_SIZE, "disable\n");
        } else {
@@ -1336,9 +1238,6 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char
        struct aiptek *aiptek = dev_get_drvdata(dev);
        int y;
 
-       if (aiptek == NULL)
-               return 0;
-
        if (strcmp(buf, "disable") == 0) {
                aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
        } else {
@@ -1361,9 +1260,6 @@ static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribut
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
 }
 
@@ -1372,9 +1268,6 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
        return count;
 }
@@ -1391,9 +1284,6 @@ static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_at
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        aiptek->curSetting.programmableDelay);
 }
@@ -1403,9 +1293,6 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr,
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
        return count;
 }
@@ -1414,23 +1301,6 @@ static DEVICE_ATTR(delay,
                   S_IRUGO | S_IWUGO,
                   show_tabletProgrammableDelay, store_tabletProgrammableDelay);
 
-/***********************************************************************
- * support routines for the 'input_path' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n",
-                       aiptek->features.inputPath);
-}
-
-static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL);
-
 /***********************************************************************
  * support routines for the 'event_count' file. Note that this file
  * only displays current setting.
@@ -1439,9 +1309,6 @@ static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attri
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
 }
 
@@ -1456,9 +1323,6 @@ static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_at
        struct aiptek *aiptek = dev_get_drvdata(dev);
        char *retMsg;
 
-       if (aiptek == NULL)
-               return 0;
-
        switch (aiptek->diagnostic) {
        case AIPTEK_DIAGNOSTIC_NA:
                retMsg = "no errors\n";
@@ -1493,45 +1357,32 @@ static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
  * support routines for the 'stylus_upper' file. Note that this file
  * both displays current setting and allows for setting changing.
  */
+
+static struct aiptek_map stylus_button_map[] = {
+       { "upper",      AIPTEK_STYLUS_UPPER_BUTTON },
+       { "lower",      AIPTEK_STYLUS_LOWER_BUTTON },
+       { NULL,         AIPTEK_INVALID_VALUE }
+};
+
 static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.stylusButtonUpper) {
-       case AIPTEK_STYLUS_UPPER_BUTTON:
-               s = "upper";
-               break;
-
-       case AIPTEK_STYLUS_LOWER_BUTTON:
-               s = "lower";
-               break;
 
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(stylus_button_map,
+                                       aiptek->curSetting.stylusButtonUpper));
 }
 
 static ssize_t
 store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
+       int new_button = map_str_to_val(stylus_button_map, buf, count);
 
-       if (aiptek == NULL)
-               return 0;
+       if (new_button == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
 
-       if (strcmp(buf, "upper") == 0) {
-               aiptek->newSetting.stylusButtonUpper =
-                   AIPTEK_STYLUS_UPPER_BUTTON;
-       } else if (strcmp(buf, "lower") == 0) {
-               aiptek->newSetting.stylusButtonUpper =
-                   AIPTEK_STYLUS_LOWER_BUTTON;
-       }
+       aiptek->newSetting.stylusButtonUpper = new_button;
        return count;
 }
 
@@ -1543,45 +1394,26 @@ static DEVICE_ATTR(stylus_upper,
  * support routines for the 'stylus_lower' file. Note that this file
  * both displays current setting and allows for setting changing.
  */
+
 static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.stylusButtonLower) {
-       case AIPTEK_STYLUS_UPPER_BUTTON:
-               s = "upper";
-               break;
-
-       case AIPTEK_STYLUS_LOWER_BUTTON:
-               s = "lower";
-               break;
 
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(stylus_button_map,
+                                       aiptek->curSetting.stylusButtonLower));
 }
 
 static ssize_t
 store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
+       int new_button = map_str_to_val(stylus_button_map, buf, count);
 
-       if (aiptek == NULL)
-               return 0;
+       if (new_button == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
 
-       if (strcmp(buf, "upper") == 0) {
-               aiptek->newSetting.stylusButtonLower =
-                   AIPTEK_STYLUS_UPPER_BUTTON;
-       } else if (strcmp(buf, "lower") == 0) {
-               aiptek->newSetting.stylusButtonLower =
-                   AIPTEK_STYLUS_LOWER_BUTTON;
-       }
+       aiptek->newSetting.stylusButtonLower = new_button;
        return count;
 }
 
@@ -1593,49 +1425,33 @@ static DEVICE_ATTR(stylus_lower,
  * support routines for the 'mouse_left' file. Note that this file
  * both displays current setting and allows for setting changing.
  */
+
+static struct aiptek_map mouse_button_map[] = {
+       { "left",       AIPTEK_MOUSE_LEFT_BUTTON },
+       { "middle",     AIPTEK_MOUSE_MIDDLE_BUTTON },
+       { "right",      AIPTEK_MOUSE_RIGHT_BUTTON },
+       { NULL,         AIPTEK_INVALID_VALUE }
+};
+
 static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.mouseButtonLeft) {
-       case AIPTEK_MOUSE_LEFT_BUTTON:
-               s = "left";
-               break;
-
-       case AIPTEK_MOUSE_MIDDLE_BUTTON:
-               s = "middle";
-               break;
-
-       case AIPTEK_MOUSE_RIGHT_BUTTON:
-               s = "right";
-               break;
 
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(mouse_button_map,
+                                       aiptek->curSetting.mouseButtonLeft));
 }
 
 static ssize_t
 store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
+       int new_button = map_str_to_val(mouse_button_map, buf, count);
 
-       if (aiptek == NULL)
-               return 0;
+       if (new_button == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
 
-       if (strcmp(buf, "left") == 0) {
-               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
-       } else if (strcmp(buf, "middle") == 0) {
-               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON;
-       } else if (strcmp(buf, "right") == 0) {
-               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON;
-       }
+       aiptek->newSetting.mouseButtonLeft = new_button;
        return count;
 }
 
@@ -1650,48 +1466,22 @@ static DEVICE_ATTR(mouse_left,
 static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
 
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.mouseButtonMiddle) {
-       case AIPTEK_MOUSE_LEFT_BUTTON:
-               s = "left";
-               break;
-
-       case AIPTEK_MOUSE_MIDDLE_BUTTON:
-               s = "middle";
-               break;
-
-       case AIPTEK_MOUSE_RIGHT_BUTTON:
-               s = "right";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(mouse_button_map,
+                                       aiptek->curSetting.mouseButtonMiddle));
 }
 
 static ssize_t
 store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
+       int new_button = map_str_to_val(mouse_button_map, buf, count);
 
-       if (aiptek == NULL)
-               return 0;
+       if (new_button == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
 
-       if (strcmp(buf, "left") == 0) {
-               aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON;
-       } else if (strcmp(buf, "middle") == 0) {
-               aiptek->newSetting.mouseButtonMiddle =
-                   AIPTEK_MOUSE_MIDDLE_BUTTON;
-       } else if (strcmp(buf, "right") == 0) {
-               aiptek->newSetting.mouseButtonMiddle =
-                   AIPTEK_MOUSE_RIGHT_BUTTON;
-       }
+       aiptek->newSetting.mouseButtonMiddle = new_button;
        return count;
 }
 
@@ -1706,47 +1496,22 @@ static DEVICE_ATTR(mouse_middle,
 static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.mouseButtonRight) {
-       case AIPTEK_MOUSE_LEFT_BUTTON:
-               s = "left";
-               break;
-
-       case AIPTEK_MOUSE_MIDDLE_BUTTON:
-               s = "middle";
-               break;
 
-       case AIPTEK_MOUSE_RIGHT_BUTTON:
-               s = "right";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       map_val_to_str(mouse_button_map,
+                                       aiptek->curSetting.mouseButtonRight));
 }
 
 static ssize_t
 store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
+       int new_button = map_str_to_val(mouse_button_map, buf, count);
 
-       if (aiptek == NULL)
-               return 0;
+       if (new_button == AIPTEK_INVALID_VALUE)
+               return -EINVAL;
 
-       if (strcmp(buf, "left") == 0) {
-               aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON;
-       } else if (strcmp(buf, "middle") == 0) {
-               aiptek->newSetting.mouseButtonRight =
-                   AIPTEK_MOUSE_MIDDLE_BUTTON;
-       } else if (strcmp(buf, "right") == 0) {
-               aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
-       }
+       aiptek->newSetting.mouseButtonRight = new_button;
        return count;
 }
 
@@ -1762,9 +1527,6 @@ static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *att
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
                return snprintf(buf, PAGE_SIZE, "disable\n");
        } else {
@@ -1778,9 +1540,6 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
        return count;
 }
@@ -1794,11 +1553,6 @@ static DEVICE_ATTR(wheel,
  */
 static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
        /* There is nothing useful to display, so a one-line manual
         * is in order...
         */
@@ -1811,9 +1565,6 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        /* We do not care what you write to this file. Merely the action
         * of writing to this file triggers a tablet reprogramming.
         */
@@ -1837,9 +1588,6 @@ static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *a
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
 }
 
@@ -1853,9 +1601,6 @@ static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
 }
 
@@ -1869,86 +1614,39 @@ static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *at
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       if (aiptek == NULL)
-               return 0;
-
        return snprintf(buf, PAGE_SIZE, "%04x\n",
                        aiptek->features.firmwareCode);
 }
 
 static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
 
-/***********************************************************************
- * This routine removes all existing sysfs files managed by this device
- * driver.
- */
-static void aiptek_delete_files(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_size);
-       device_remove_file(dev, &dev_attr_product_id);
-       device_remove_file(dev, &dev_attr_vendor_id);
-       device_remove_file(dev, &dev_attr_vendor);
-       device_remove_file(dev, &dev_attr_product);
-       device_remove_file(dev, &dev_attr_pointer_mode);
-       device_remove_file(dev, &dev_attr_coordinate_mode);
-       device_remove_file(dev, &dev_attr_tool_mode);
-       device_remove_file(dev, &dev_attr_xtilt);
-       device_remove_file(dev, &dev_attr_ytilt);
-       device_remove_file(dev, &dev_attr_jitter);
-       device_remove_file(dev, &dev_attr_delay);
-       device_remove_file(dev, &dev_attr_input_path);
-       device_remove_file(dev, &dev_attr_event_count);
-       device_remove_file(dev, &dev_attr_diagnostic);
-       device_remove_file(dev, &dev_attr_odm_code);
-       device_remove_file(dev, &dev_attr_model_code);
-       device_remove_file(dev, &dev_attr_firmware_code);
-       device_remove_file(dev, &dev_attr_stylus_lower);
-       device_remove_file(dev, &dev_attr_stylus_upper);
-       device_remove_file(dev, &dev_attr_mouse_left);
-       device_remove_file(dev, &dev_attr_mouse_middle);
-       device_remove_file(dev, &dev_attr_mouse_right);
-       device_remove_file(dev, &dev_attr_wheel);
-       device_remove_file(dev, &dev_attr_execute);
-}
-
-/***********************************************************************
- * This routine creates the sysfs files managed by this device
- * driver.
- */
-static int aiptek_add_files(struct device *dev)
-{
-       int ret;
+static struct attribute *aiptek_attributes[] = {
+       &dev_attr_size.attr,
+       &dev_attr_pointer_mode.attr,
+       &dev_attr_coordinate_mode.attr,
+       &dev_attr_tool_mode.attr,
+       &dev_attr_xtilt.attr,
+       &dev_attr_ytilt.attr,
+       &dev_attr_jitter.attr,
+       &dev_attr_delay.attr,
+       &dev_attr_event_count.attr,
+       &dev_attr_diagnostic.attr,
+       &dev_attr_odm_code.attr,
+       &dev_attr_model_code.attr,
+       &dev_attr_firmware_code.attr,
+       &dev_attr_stylus_lower.attr,
+       &dev_attr_stylus_upper.attr,
+       &dev_attr_mouse_left.attr,
+       &dev_attr_mouse_middle.attr,
+       &dev_attr_mouse_right.attr,
+       &dev_attr_wheel.attr,
+       &dev_attr_execute.attr,
+       NULL
+};
 
-       if ((ret = device_create_file(dev, &dev_attr_size)) ||
-           (ret = device_create_file(dev, &dev_attr_product_id)) ||
-           (ret = device_create_file(dev, &dev_attr_vendor_id)) ||
-           (ret = device_create_file(dev, &dev_attr_vendor)) ||
-           (ret = device_create_file(dev, &dev_attr_product)) ||
-           (ret = device_create_file(dev, &dev_attr_pointer_mode)) ||
-           (ret = device_create_file(dev, &dev_attr_coordinate_mode)) ||
-           (ret = device_create_file(dev, &dev_attr_tool_mode)) ||
-           (ret = device_create_file(dev, &dev_attr_xtilt)) ||
-           (ret = device_create_file(dev, &dev_attr_ytilt)) ||
-           (ret = device_create_file(dev, &dev_attr_jitter)) ||
-           (ret = device_create_file(dev, &dev_attr_delay)) ||
-           (ret = device_create_file(dev, &dev_attr_input_path)) ||
-           (ret = device_create_file(dev, &dev_attr_event_count)) ||
-           (ret = device_create_file(dev, &dev_attr_diagnostic)) ||
-           (ret = device_create_file(dev, &dev_attr_odm_code)) ||
-           (ret = device_create_file(dev, &dev_attr_model_code)) ||
-           (ret = device_create_file(dev, &dev_attr_firmware_code)) ||
-           (ret = device_create_file(dev, &dev_attr_stylus_lower)) ||
-           (ret = device_create_file(dev, &dev_attr_stylus_upper)) ||
-           (ret = device_create_file(dev, &dev_attr_mouse_left)) ||
-           (ret = device_create_file(dev, &dev_attr_mouse_middle)) ||
-           (ret = device_create_file(dev, &dev_attr_mouse_right)) ||
-           (ret = device_create_file(dev, &dev_attr_wheel)) ||
-           (ret = device_create_file(dev, &dev_attr_execute))) {
-               err("aiptek: killing own sysfs device files\n");
-               aiptek_delete_files(dev);
-       }
-       return ret;
-}
+static struct attribute_group aiptek_attribute_group = {
+       .attrs  = aiptek_attributes,
+};
 
 /***********************************************************************
  * This routine is called when a tablet has been identified. It basically
@@ -1961,8 +1659,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_endpoint_descriptor *endpoint;
        struct aiptek *aiptek;
        struct input_dev *inputdev;
-       struct input_handle *inputhandle;
-       struct list_head *node, *next;
        int i;
        int speeds[] = { 0,
                AIPTEK_PROGRAMMABLE_DELAY_50,
@@ -1984,17 +1680,23 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
        inputdev = input_allocate_device();
-       if (!aiptek || !inputdev)
+       if (!aiptek || !inputdev) {
+               warn("aiptek: cannot allocate memory or input device");
                goto fail1;
+        }
 
        aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
                                        GFP_ATOMIC, &aiptek->data_dma);
-       if (!aiptek->data)
+        if (!aiptek->data) {
+               warn("aiptek: cannot allocate usb buffer");
                goto fail1;
+       }
 
        aiptek->urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!aiptek->urb)
+       if (!aiptek->urb) {
+               warn("aiptek: cannot allocate urb");
                goto fail2;
+       }
 
        aiptek->inputdev = inputdev;
        aiptek->usbdev = usbdev;
@@ -2002,6 +1704,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
        aiptek->inDelay = 0;
        aiptek->endDelay = 0;
        aiptek->previousJitterable = 0;
+       aiptek->lastMacro = -1;
 
        /* Set up the curSettings struct. Said struct contains the current
         * programmable parameters. The newSetting struct contains changes
@@ -2054,36 +1757,23 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
        /* Now program the capacities of the tablet, in terms of being
         * an input device.
         */
-       inputdev->evbit[0] |= BIT(EV_KEY)
-           | BIT(EV_ABS)
-           | BIT(EV_REL)
-           | BIT(EV_MSC);
-
-       inputdev->absbit[0] |= BIT(ABS_MISC);
+       for (i = 0; i < ARRAY_SIZE(eventTypes); ++i)
+               __set_bit(eventTypes[i], inputdev->evbit);
 
-       inputdev->relbit[0] |=
-           (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC));
+       for (i = 0; i < ARRAY_SIZE(absEvents); ++i)
+               __set_bit(absEvents[i], inputdev->absbit);
 
-       inputdev->keybit[LONG(BTN_LEFT)] |=
-           (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE));
+       for (i = 0; i < ARRAY_SIZE(relEvents); ++i)
+               __set_bit(relEvents[i], inputdev->relbit);
 
-       inputdev->keybit[LONG(BTN_DIGI)] |=
-           (BIT(BTN_TOOL_PEN) |
-            BIT(BTN_TOOL_RUBBER) |
-            BIT(BTN_TOOL_PENCIL) |
-            BIT(BTN_TOOL_AIRBRUSH) |
-            BIT(BTN_TOOL_BRUSH) |
-            BIT(BTN_TOOL_MOUSE) |
-            BIT(BTN_TOOL_LENS) |
-            BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2));
+       __set_bit(MSC_SERIAL, inputdev->mscbit);
 
-       inputdev->mscbit[0] = BIT(MSC_SERIAL);
+       /* Set up key and button codes */
+       for (i = 0; i < ARRAY_SIZE(buttonEvents); ++i)
+               __set_bit(buttonEvents[i], inputdev->keybit);
 
-       /* Programming the tablet macro keys needs to be done with a for loop
-        * as the keycodes are discontiguous.
-        */
        for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i)
-               set_bit(macroKeyEvents[i], inputdev->keybit);
+               __set_bit(macroKeyEvents[i], inputdev->keybit);
 
        /*
         * Program the input device coordinate capacities. We do not yet
@@ -2134,25 +1824,11 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
                }
        }
 
-       /* Register the tablet as an Input Device
-        */
-       err = input_register_device(aiptek->inputdev);
-       if (err)
+       /* Murphy says that some day someone will have a tablet that fails the
+          above test. That's you, Frederic Rodrigo */
+       if (i == ARRAY_SIZE(speeds)) {
+               info("input: Aiptek tried all speeds, no sane response");
                goto fail2;
-
-       /* We now will look for the evdev device which is mapped to
-        * the tablet. The partial name is kept in the link list of
-        * input_handles associated with this input device.
-        * What identifies an evdev input_handler is that it begins
-        * with 'event', continues with a digit, and that in turn
-        * is mapped to input/eventN.
-        */
-       list_for_each_safe(node, next, &inputdev->h_list) {
-               inputhandle = to_handle(node);
-               if (strncmp(inputhandle->name, "event", 5) == 0) {
-                       strcpy(aiptek->features.inputPath, inputhandle->name);
-                       break;
-               }
        }
 
        /* Associate this driver's struct with the usb interface.
@@ -2161,18 +1837,27 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        /* Set up the sysfs files
         */
-       aiptek_add_files(&intf->dev);
+       err = sysfs_create_group(&intf->dev.kobj, &aiptek_attribute_group);
+       if (err) {
+               warn("aiptek: cannot create sysfs group err: %d", err);
+               goto fail3;
+        }
 
-       /* Make sure the evdev module is loaded. Assuming evdev IS a module :-)
+       /* Register the tablet as an Input Device
         */
-       if (request_module("evdev") != 0)
-               info("aiptek: error loading 'evdev' module");
-
+       err = input_register_device(aiptek->inputdev);
+       if (err) {
+               warn("aiptek: input_register_device returned err: %d", err);
+               goto fail4;
+        }
        return 0;
 
+ fail4:        sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group);
+ fail3: usb_free_urb(aiptek->urb);
  fail2:        usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
                        aiptek->data_dma);
- fail1:        input_free_device(inputdev);
+ fail1: usb_set_intfdata(intf, NULL);
+       input_free_device(inputdev);
        kfree(aiptek);
        return err;
 }
@@ -2192,7 +1877,7 @@ static void aiptek_disconnect(struct usb_interface *intf)
                 */
                usb_kill_urb(aiptek->urb);
                input_unregister_device(aiptek->inputdev);
-               aiptek_delete_files(&intf->dev);
+               sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group);
                usb_free_urb(aiptek->urb);
                usb_buffer_free(interface_to_usbdev(intf),
                                AIPTEK_PACKET_LENGTH,
index ef01a807ec0f9b6e0cd95eaafacc5030e0f2a308..6542edb6f76efe505629b8690dfa4e50b8267329 100644 (file)
@@ -11,7 +11,7 @@
  *  Copyright (c) 2000 Daniel Egger            <egger@suse.de>
  *  Copyright (c) 2001 Frederic Lepied         <flepied@mandrakesoft.com>
  *  Copyright (c) 2004 Panagiotis Issaris      <panagiotis.issaris@mech.kuleuven.ac.be>
- *  Copyright (c) 2002-2006 Ping Cheng         <pingc@wacom.com>
+ *  Copyright (c) 2002-2007 Ping Cheng         <pingc@wacom.com>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -62,8 +62,9 @@
  *                 - Minor data report fix
  *      v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
  *                - where wacom_sys.c deals with system specific code,
- *                - and wacom_wac.c deals with Wacom specific code
+ *                - and wacom_wac.c deals with Wacom specific code
  *                - Support Intuos3 4x6
+ *      v1.47 (pc) - Added support for Bamboo
  */
 
 /*
@@ -84,7 +85,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.46"
+#define DRIVER_VERSION "v1.47"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -123,6 +124,7 @@ extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wa
 extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern __u16 wacom_le16_to_cpu(unsigned char *data);
 extern __u16 wacom_be16_to_cpu(unsigned char *data);
 extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
index 83bddef6606770a536048c6a9250dbd084627c88..064e123c9b766170be132d2bb894b535d168b961 100644 (file)
@@ -138,6 +138,12 @@ static void wacom_close(struct input_dev *dev)
        usb_kill_urb(wacom->irq);
 }
 
+void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_1) | BIT(BTN_5);
+       input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+}
+
 void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
        input_dev->evbit[0] |= BIT(EV_MSC);
index 7661f03a2db2ab3cbb51e6d40e28db54db9ac32b..fc03ba256f4c54c540e200c23e7d0b25bccda9fb 100644 (file)
@@ -178,7 +178,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 
                        case 2: /* Mouse with wheel */
                                wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
-                               if (wacom->features->type == WACOM_G4) {
+                               if (wacom->features->type == WACOM_G4 ||
+                                               wacom->features->type == WACOM_MO) {
                                        rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
                                        wacom_report_rel(wcombo, REL_WHEEL, -rw);
                                } else
@@ -190,7 +191,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                                id = CURSOR_DEVICE_ID;
                                wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
                                wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
-                               if (wacom->features->type == WACOM_G4)
+                               if (wacom->features->type == WACOM_G4 ||
+                                               wacom->features->type == WACOM_MO)
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
                                else
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
@@ -226,7 +228,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        /* send pad data */
-       if (wacom->features->type == WACOM_G4) {
+       switch (wacom->features->type) {
+           case WACOM_G4:
                if (data[7] & 0xf8) {
                        wacom_input_sync(wcombo); /* sync last event */
                        wacom->id[1] = 1;
@@ -247,6 +250,33 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_abs(wcombo, ABS_MISC, 0);
                        wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
                }
+               break;
+           case WACOM_MO:
+               if ((data[7] & 0xf8) || (data[8] & 0x80)) {
+                       wacom_input_sync(wcombo); /* sync last event */
+                       wacom->id[1] = 1;
+                       wacom->serial[1] = (data[7] & 0xf8);
+                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
+                       wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
+                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x10));
+                       wacom_report_key(wcombo, BTN_5, (data[7] & 0x40));
+                       wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f));
+                       wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+                       wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+               } else if (wacom->id[1]) {
+                       wacom_input_sync(wcombo); /* sync last event */
+                       wacom->id[1] = 0;
+                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
+                       wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
+                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x10));
+                       wacom_report_key(wcombo, BTN_5, (data[7] & 0x40));
+                       wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f));
+                       wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+                       wacom_report_abs(wcombo, ABS_MISC, 0);
+                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+               }
+               break;
        }
        return 1;
 }
@@ -331,7 +361,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_key(wcombo, BTN_EXTRA, 0);
                        wacom_report_abs(wcombo, ABS_THROTTLE, 0);
                        wacom_report_abs(wcombo, ABS_RZ, 0);
-               } else {
+               } else {
                        wacom_report_abs(wcombo, ABS_PRESSURE, 0);
                        wacom_report_abs(wcombo, ABS_TILT_X, 0);
                        wacom_report_abs(wcombo, ABS_TILT_Y, 0);
@@ -423,9 +453,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                 return result-1;
 
        /* Only large I3 and I1 & I2 support Lense Cursor */
-       if((wacom->tool[idx] == BTN_TOOL_LENS)
+       if ((wacom->tool[idx] == BTN_TOOL_LENS)
                        && ((wacom->features->type == INTUOS3)
-                       || (wacom->features->type == INTUOS3S)))
+                       || (wacom->features->type == INTUOS3S)))
                return 0;
 
        /* Cintiq doesn't send data when RDY bit isn't set */
@@ -517,6 +547,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
                        break;
                case WACOM_G4:
                case GRAPHIRE:
+               case WACOM_MO:
                        return (wacom_graphire_irq(wacom_wac, wcombo));
                        break;
                case PTU:
@@ -538,6 +569,8 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
 void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
        switch (wacom_wac->features->type) {
+               case WACOM_MO:
+                       input_dev_mo(input_dev, wacom_wac);
                case WACOM_G4:
                        input_dev_g4(input_dev, wacom_wac);
                        /* fall through */
@@ -579,6 +612,7 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
        { "Wacom Volito2 2x3",   8,   3248,  2320,  511, 63, GRAPHIRE },
        { "Wacom PenPartner2",   8,   3250,  2320,  255, 63, GRAPHIRE },
+       { "Wacom Bamboo",        9,  14760,  9225,  511, 63, WACOM_MO },
        { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 31, INTUOS },
        { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 31, INTUOS },
        { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 31, INTUOS },
@@ -627,6 +661,7 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
index a5e12e8756de046e9bcf62ddeaaba165183246ad..a302e229bb8a7d005d65f62f6831245b2bbcd96a 100644 (file)
@@ -25,6 +25,7 @@ enum {
        INTUOS3,
        INTUOS3L,
        CINTIQ,
+       WACOM_MO,
        MAX_TYPE
 };
 
index e5cca9bd040632bcbe7d7064a63ca4394c077e3d..69371779806ac57182548230a9513e2754efd064 100644 (file)
@@ -177,6 +177,7 @@ config TOUCHSCREEN_USB_COMPOSITE
          - some other eTurboTouch
          - Gunze AHL61
          - DMC TSC-10/25
+         - IRTOUCHSYSTEMS/UNITOP
 
          Have a look at <http://linux.chapter7.ch/touchkit/> for
          a usage description and the required user-space stuff.
@@ -219,4 +220,9 @@ config TOUCHSCREEN_USB_DMC_TSC10
        bool "DMC TSC-10/25 device support" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_IRTOUCH
+       default y
+       bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
 endif
index e3f22852bd0978c422db77d050a9072a013a9549..b407028ffc59dcc514fa02d8c66f2aab9065a046 100644 (file)
@@ -9,6 +9,7 @@
  *  - eTurboTouch
  *  - Gunze AHL61
  *  - DMC TSC-10/25
+ *  - IRTOUCHSYSTEMS/UNITOP
  *
  * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -110,6 +111,7 @@ enum {
        DEVTYPE_ETURBO,
        DEVTYPE_GUNZE,
        DEVTYPE_DMC_TSC10,
+       DEVTYPE_IRTOUCH,
 };
 
 static struct usb_device_id usbtouch_devices[] = {
@@ -150,6 +152,11 @@ static struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+       {USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
+       {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
+#endif
+
        {}
 };
 
@@ -415,6 +422,21 @@ static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 #endif
 
 
+/*****************************************************************************
+ * IRTOUCH Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       dev->x = (pkt[3] << 8) | pkt[2];
+       dev->y = (pkt[5] << 8) | pkt[4];
+       dev->touch = (pkt[1] & 0x03) ? 1 : 0;
+
+       return 1;
+}
+#endif
+
+
 /*****************************************************************************
  * the different device descriptors
  */
@@ -504,6 +526,17 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .read_data      = dmc_tsc10_read_data,
        },
 #endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+       [DEVTYPE_IRTOUCH] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x0fff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x0fff,
+               .rept_size      = 8,
+               .read_data      = irtouch_read_data,
+       },
+#endif
 };
 
 
index 2db364898e15f434e852c304bbcb855e271de00b..d2f882e98e5e21c0c9c23b5d8c3e072883de052a 100644 (file)
@@ -109,9 +109,11 @@ struct tsdev {
        int open;
        int minor;
        char name[8];
+       struct input_handle handle;
        wait_queue_head_t wait;
        struct list_head client_list;
-       struct input_handle handle;
+       struct device dev;
+
        int x, y, pressure;
        struct ts_calibration cal;
 };
@@ -163,9 +165,13 @@ static int tsdev_open(struct inode *inode, struct file *file)
        if (!tsdev || !tsdev->exist)
                return -ENODEV;
 
+       get_device(&tsdev->dev);
+
        client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
+       if (!client) {
+               error = -ENOMEM;
+               goto err_put_tsdev;
+       }
 
        client->tsdev = tsdev;
        client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
@@ -173,19 +179,25 @@ static int tsdev_open(struct inode *inode, struct file *file)
 
        if (!tsdev->open++ && tsdev->exist) {
                error = input_open_device(&tsdev->handle);
-               if (error) {
-                       list_del(&client->node);
-                       kfree(client);
-                       return error;
-               }
+               if (error)
+                       goto err_free_client;
        }
 
        file->private_data = client;
        return 0;
+
+ err_free_client:
+       list_del(&client->node);
+       kfree(client);
+ err_put_tsdev:
+       put_device(&tsdev->dev);
+       return error;
 }
 
-static void tsdev_free(struct tsdev *tsdev)
+static void tsdev_free(struct device *dev)
 {
+       struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
+
        tsdev_table[tsdev->minor] = NULL;
        kfree(tsdev);
 }
@@ -200,12 +212,10 @@ static int tsdev_release(struct inode *inode, struct file *file)
        list_del(&client->node);
        kfree(client);
 
-       if (!--tsdev->open) {
-               if (tsdev->exist)
-                       input_close_device(&tsdev->handle);
-               else
-                       tsdev_free(tsdev);
-       }
+       if (!--tsdev->open && tsdev->exist)
+               input_close_device(&tsdev->handle);
+
+       put_device(&tsdev->dev);
 
        return 0;
 }
@@ -361,7 +371,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
                int x, y, tmp;
 
                do_gettimeofday(&time);
-               client->event[client->head].millisecs = time.tv_usec / 100;
+               client->event[client->head].millisecs = time.tv_usec / 1000;
                client->event[client->head].pressure = tsdev->pressure;
 
                x = tsdev->x;
@@ -388,8 +398,6 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
                         const struct input_device_id *id)
 {
        struct tsdev *tsdev;
-       struct class_device *cdev;
-       dev_t devt;
        int minor, delta;
        int error;
 
@@ -407,14 +415,13 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
        INIT_LIST_HEAD(&tsdev->client_list);
        init_waitqueue_head(&tsdev->wait);
 
-       sprintf(tsdev->name, "ts%d", minor);
-
        tsdev->exist = 1;
        tsdev->minor = minor;
        tsdev->handle.dev = dev;
        tsdev->handle.name = tsdev->name;
        tsdev->handle.handler = handler;
        tsdev->handle.private = tsdev;
+       snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
 
        /* Precompute the rough calibration matrix */
        delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
@@ -429,36 +436,30 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
        tsdev->cal.yscale = (yres << 8) / delta;
        tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
 
-       tsdev_table[minor] = tsdev;
-
-       devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
+       snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
+                "ts%d", minor);
+       tsdev->dev.class = &input_class;
+       tsdev->dev.parent = &dev->dev;
+       tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
+       tsdev->dev.release = tsdev_free;
+       device_initialize(&tsdev->dev);
 
-       cdev = class_device_create(&input_class, &dev->cdev, devt,
-                                  dev->cdev.dev, tsdev->name);
-       if (IS_ERR(cdev)) {
-               error = PTR_ERR(cdev);
-               goto err_free_tsdev;
-       }
+       tsdev_table[minor] = tsdev;
 
-       /* temporary symlink to keep userspace happy */
-       error = sysfs_create_link(&input_class.subsys.kobj,
-                                 &cdev->kobj, tsdev->name);
+       error = device_add(&tsdev->dev);
        if (error)
-               goto err_cdev_destroy;
+               goto err_free_tsdev;
 
        error = input_register_handle(&tsdev->handle);
        if (error)
-               goto err_remove_link;
+               goto err_delete_tsdev;
 
        return 0;
 
- err_remove_link:
-       sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
- err_cdev_destroy:
-       class_device_destroy(&input_class, devt);
+ err_delete_tsdev:
+       device_del(&tsdev->dev);
  err_free_tsdev:
-       tsdev_table[minor] = NULL;
-       kfree(tsdev);
+       put_device(&tsdev->dev);
        return error;
 }
 
@@ -468,10 +469,8 @@ static void tsdev_disconnect(struct input_handle *handle)
        struct tsdev_client *client;
 
        input_unregister_handle(handle);
+       device_del(&tsdev->dev);
 
-       sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
-       class_device_destroy(&input_class,
-                       MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
        tsdev->exist = 0;
 
        if (tsdev->open) {
@@ -479,8 +478,9 @@ static void tsdev_disconnect(struct input_handle *handle)
                list_for_each_entry(client, &tsdev->client_list, node)
                        kill_fasync(&client->fasync, SIGIO, POLL_HUP);
                wake_up_interruptible(&tsdev->wait);
-       } else
-               tsdev_free(tsdev);
+       }
+
+       put_device(&tsdev->dev);
 }
 
 static const struct input_device_id tsdev_ids[] = {
index 616eee9c04f10c01d6799855d19d81b315cc5be5..bd601efa7bd188b77a3ced5e24a4f7684684a76a 100644 (file)
@@ -34,6 +34,11 @@ config PHANTOM
          If you choose to build module, its name will be phantom. If unsure,
          say N here.
 
+config EEPROM_93CX6
+       tristate "EEPROM 93CX6 support"
+       ---help---
+         This is a driver for the EEPROM chipsets 93c46 and 93c66.
+         The driver supports both read as well as write commands.
 
          If unsure, say N.
 
@@ -187,5 +192,4 @@ config THINKPAD_ACPI_BAY
 
          If you are not sure, say Y here.
 
-
 endmenu
index 8abbf2f07a65d4d0d3633ba87fd6e4c69807b540..b5ce0e3dba861ea037e78a939ecdc60ab758c8c6 100644 (file)
@@ -14,3 +14,4 @@ obj-$(CONFIG_PHANTOM)         += phantom.o
 obj-$(CONFIG_SGI_IOC4)         += ioc4.o
 obj-$(CONFIG_SONY_LAPTOP)      += sony-laptop.o
 obj-$(CONFIG_THINKPAD_ACPI)    += thinkpad_acpi.o
+obj-$(CONFIG_EEPROM_93CX6)     += eeprom_93cx6.o
diff --git a/drivers/misc/eeprom_93cx6.c b/drivers/misc/eeprom_93cx6.c
new file mode 100644 (file)
index 0000000..ac515b0
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+       Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
+       <http://rt2x00.serialmonkey.com>
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the
+       Free Software Foundation, Inc.,
+       59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+       Module: eeprom_93cx6
+       Abstract: EEPROM reader routines for 93cx6 chipsets.
+       Supported chipsets: 93c46 & 93c66.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/eeprom_93cx6.h>
+
+MODULE_AUTHOR("http://rt2x00.serialmonkey.com");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
+MODULE_LICENSE("GPL");
+
+static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
+{
+       eeprom->reg_data_clock = 1;
+       eeprom->register_write(eeprom);
+
+       /*
+        * Add a short delay for the pulse to work.
+        * According to the specifications the "maximum minimum"
+        * time should be 450ns.
+        */
+       ndelay(450);
+}
+
+static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
+{
+       eeprom->reg_data_clock = 0;
+       eeprom->register_write(eeprom);
+
+       /*
+        * Add a short delay for the pulse to work.
+        * According to the specifications the minimal time
+        * should be 450ns so a 1us delay is sufficient.
+        */
+       udelay(1);
+}
+
+static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
+{
+       /*
+        * Clear all flags, and enable chip select.
+        */
+       eeprom->register_read(eeprom);
+       eeprom->reg_data_in = 0;
+       eeprom->reg_data_out = 0;
+       eeprom->reg_data_clock = 0;
+       eeprom->reg_chip_select = 1;
+       eeprom->register_write(eeprom);
+
+       /*
+        * kick a pulse.
+        */
+       eeprom_93cx6_pulse_high(eeprom);
+       eeprom_93cx6_pulse_low(eeprom);
+}
+
+static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
+{
+       /*
+        * Clear chip_select and data_in flags.
+        */
+       eeprom->register_read(eeprom);
+       eeprom->reg_data_in = 0;
+       eeprom->reg_chip_select = 0;
+       eeprom->register_write(eeprom);
+
+       /*
+        * kick a pulse.
+        */
+       eeprom_93cx6_pulse_high(eeprom);
+       eeprom_93cx6_pulse_low(eeprom);
+}
+
+static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
+       const u16 data, const u16 count)
+{
+       unsigned int i;
+
+       eeprom->register_read(eeprom);
+
+       /*
+        * Clear data flags.
+        */
+       eeprom->reg_data_in = 0;
+       eeprom->reg_data_out = 0;
+
+       /*
+        * Start writing all bits.
+        */
+       for (i = count; i > 0; i--) {
+               /*
+                * Check if this bit needs to be set.
+                */
+               eeprom->reg_data_in = !!(data & (1 << (i - 1)));
+
+               /*
+                * Write the bit to the eeprom register.
+                */
+               eeprom->register_write(eeprom);
+
+               /*
+                * Kick a pulse.
+                */
+               eeprom_93cx6_pulse_high(eeprom);
+               eeprom_93cx6_pulse_low(eeprom);
+       }
+
+       eeprom->reg_data_in = 0;
+       eeprom->register_write(eeprom);
+}
+
+static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
+       u16 *data, const u16 count)
+{
+       unsigned int i;
+       u16 buf = 0;
+
+       eeprom->register_read(eeprom);
+
+       /*
+        * Clear data flags.
+        */
+       eeprom->reg_data_in = 0;
+       eeprom->reg_data_out = 0;
+
+       /*
+        * Start reading all bits.
+        */
+       for (i = count; i > 0; i--) {
+               eeprom_93cx6_pulse_high(eeprom);
+
+               eeprom->register_read(eeprom);
+
+               /*
+                * Clear data_in flag.
+                */
+               eeprom->reg_data_in = 0;
+
+               /*
+                * Read if the bit has been set.
+                */
+               if (eeprom->reg_data_out)
+                       buf |= (1 << (i - 1));
+
+               eeprom_93cx6_pulse_low(eeprom);
+       }
+
+       *data = buf;
+}
+
+/**
+ * eeprom_93cx6_read - Read multiple words from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ *
+ * This function will read the eeprom data as host-endian word
+ * into the given data pointer.
+ */
+void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
+       u16 *data)
+{
+       u16 command;
+
+       /*
+        * Initialize the eeprom register
+        */
+       eeprom_93cx6_startup(eeprom);
+
+       /*
+        * Select the read opcode and the word to be read.
+        */
+       command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
+       eeprom_93cx6_write_bits(eeprom, command,
+               PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
+
+       /*
+        * Read the requested 16 bits.
+        */
+       eeprom_93cx6_read_bits(eeprom, data, 16);
+
+       /*
+        * Cleanup eeprom register.
+        */
+       eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_read);
+
+/**
+ * eeprom_93cx6_multiread - Read multiple words from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ * @words: Number of words that should be read.
+ *
+ * This function will read all requested words from the eeprom,
+ * this is done by calling eeprom_93cx6_read() multiple times.
+ * But with the additional change that while the eeprom_93cx6_read
+ * will return host ordered bytes, this method will return little
+ * endian words.
+ */
+void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
+       __le16 *data, const u16 words)
+{
+       unsigned int i;
+       u16 tmp;
+
+       for (i = 0; i < words; i++) {
+               tmp = 0;
+               eeprom_93cx6_read(eeprom, word + i, &tmp);
+               data[i] = cpu_to_le16(tmp);
+       }
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
+
index a804965e654259a3f136e02d0a4aa961b286eef2..58bbc3e6d0de1af6960bd727adfaed7b713b2edc 100644 (file)
@@ -107,11 +107,6 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu
 
 #define PFX                    DRV_NAME ": "
 
-#ifndef TRUE
-#define FALSE 0
-#define TRUE (!FALSE)
-#endif
-
 #define CP_DEF_MSG_ENABLE      (NETIF_MSG_DRV          | \
                                 NETIF_MSG_PROBE        | \
                                 NETIF_MSG_LINK)
@@ -661,7 +656,7 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
        if (status & (TxOK | TxErr | TxEmpty | SWInt))
                cp_tx(cp);
        if (status & LinkChg)
-               mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
+               mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
 
        spin_unlock(&cp->lock);
 
@@ -1188,7 +1183,7 @@ static int cp_open (struct net_device *dev)
                goto err_out_hw;
 
        netif_carrier_off(dev);
-       mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
+       mii_check_media(&cp->mii_if, netif_msg_link(cp), true);
        netif_start_queue(dev);
 
        return 0;
@@ -2050,7 +2045,7 @@ static int cp_resume (struct pci_dev *pdev)
 
        spin_lock_irqsave (&cp->lock, flags);
 
-       mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
+       mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
 
        spin_unlock_irqrestore (&cp->lock, flags);
 
index b49375abb5f4d2c3349da24ddd9706eccba9b8e9..5cc3d517e39b8edb76bda661b447738e3ebf9bcc 100644 (file)
@@ -3,10 +3,7 @@
 # Network device configuration
 #
 
-menu "Network device support"
-       depends on NET
-
-config NETDEVICES
+menuconfig NETDEVICES
        default y if UML
        bool "Network device support"
        ---help---
@@ -151,11 +148,9 @@ source "drivers/net/phy/Kconfig"
 #      Ethernet
 #
 
-menu "Ethernet (10 or 100Mbit)"
-       depends on !UML
-
-config NET_ETHERNET
+menuconfig NET_ETHERNET
        bool "Ethernet (10 or 100Mbit)"
+       depends on !UML
        ---help---
          Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
          type of Local Area Network (LAN) in universities and companies.
@@ -180,9 +175,10 @@ config NET_ETHERNET
          kernel: saying N will just cause the configurator to skip all
          the questions about Ethernet network cards. If unsure, say N.
 
+if NET_ETHERNET
+
 config MII
        tristate "Generic Media Independent Interface device support"
-       depends on NET_ETHERNET
        help
          Most ethernet controllers have MII transceiver either as an external
          or internal device.  It is safe to say Y or M here even if your
@@ -190,7 +186,7 @@ config MII
 
 config MACB
        tristate "Atmel MACB support"
-       depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
+       depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
        select MII
        help
          The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -203,7 +199,7 @@ source "drivers/net/arm/Kconfig"
 
 config MACE
        tristate "MACE (Power Mac ethernet) support"
-       depends on NET_ETHERNET && PPC_PMAC && PPC32
+       depends on PPC_PMAC && PPC32
        select CRC32
        help
          Power Macintoshes and clones with Ethernet built-in on the
@@ -226,7 +222,7 @@ config MACE_AAUI_PORT
 
 config BMAC
        tristate "BMAC (G3 ethernet) support"
-       depends on NET_ETHERNET && PPC_PMAC && PPC32
+       depends on PPC_PMAC && PPC32
        select CRC32
        help
          Say Y for support of BMAC Ethernet interfaces. These are used on G3
@@ -237,7 +233,7 @@ config BMAC
 
 config ARIADNE
        tristate "Ariadne support"
-       depends on NET_ETHERNET && ZORRO
+       depends on ZORRO
        help
          If you have a Village Tronic Ariadne Ethernet adapter, say Y.
          Otherwise, say N.
@@ -247,7 +243,7 @@ config ARIADNE
 
 config A2065
        tristate "A2065 support"
-       depends on NET_ETHERNET && ZORRO
+       depends on ZORRO
        select CRC32
        help
          If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
@@ -258,7 +254,7 @@ config A2065
 
 config HYDRA
        tristate "Hydra support"
-       depends on NET_ETHERNET && ZORRO
+       depends on ZORRO
        select CRC32
        help
          If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
@@ -268,7 +264,7 @@ config HYDRA
 
 config ZORRO8390
        tristate "Zorro NS8390-based Ethernet support"
-       depends on NET_ETHERNET && ZORRO
+       depends on ZORRO
        select CRC32
        help
          This driver is for Zorro Ethernet cards using an NS8390-compatible
@@ -281,7 +277,7 @@ config ZORRO8390
 
 config APNE
        tristate "PCMCIA NE2000 support"
-       depends on NET_ETHERNET && AMIGA_PCMCIA
+       depends on AMIGA_PCMCIA
        select CRC32
        help
          If you have a PCMCIA NE2000 compatible adapter, say Y.  Otherwise,
@@ -292,7 +288,7 @@ config APNE
 
 config APOLLO_ELPLUS
        tristate "Apollo 3c505 support"
-       depends on NET_ETHERNET && APOLLO
+       depends on APOLLO
        help
          Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
          If you don't have one made for Apollos, you can use one from a PC,
@@ -301,7 +297,7 @@ config APOLLO_ELPLUS
 
 config MAC8390
        bool "Macintosh NS 8390 based ethernet cards"
-       depends on NET_ETHERNET && MAC
+       depends on MAC
        select CRC32
        help
          If you want to include a driver to support Nubus or LC-PDS
@@ -311,7 +307,7 @@ config MAC8390
 
 config MAC89x0
        tristate "Macintosh CS89x0 based ethernet cards"
-       depends on NET_ETHERNET && MAC
+       depends on MAC
        ---help---
          Support for CS89x0 chipset based Ethernet cards.  If you have a
          Nubus or LC-PDS network (Ethernet) card of this type, say Y and
@@ -324,7 +320,7 @@ config MAC89x0
 
 config MACSONIC
        tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)"
-       depends on NET_ETHERNET && MAC
+       depends on MAC
        ---help---
          Support for NatSemi SONIC based Ethernet devices.  This includes
          the onboard Ethernet in many Quadras as well as some LC-PDS,
@@ -338,7 +334,7 @@ config MACSONIC
 
 config MACMACE
        bool "Macintosh (AV) onboard MACE ethernet"
-       depends on NET_ETHERNET && MAC
+       depends on MAC
        select CRC32
        help
          Support for the onboard AMD 79C940 MACE Ethernet controller used in
@@ -348,7 +344,7 @@ config MACMACE
 
 config MVME147_NET
        tristate "MVME147 (Lance) Ethernet support"
-       depends on NET_ETHERNET && MVME147
+       depends on MVME147
        select CRC32
        help
          Support for the on-board Ethernet interface on the Motorola MVME147
@@ -358,7 +354,7 @@ config MVME147_NET
 
 config MVME16x_NET
        tristate "MVME16x Ethernet support"
-       depends on NET_ETHERNET && MVME16x
+       depends on MVME16x
        help
          This is the driver for the Ethernet interface on the Motorola
          MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
@@ -367,7 +363,7 @@ config MVME16x_NET
 
 config BVME6000_NET
        tristate "BVME6000 Ethernet support"
-       depends on NET_ETHERNET && BVME6000
+       depends on BVME6000
        help
          This is the driver for the Ethernet interface on BVME4000 and
          BVME6000 VME boards.  Say Y here to include the driver for this chip
@@ -376,7 +372,7 @@ config BVME6000_NET
 
 config ATARILANCE
        tristate "Atari Lance support"
-       depends on NET_ETHERNET && ATARI
+       depends on ATARI
        help
          Say Y to include support for several Atari Ethernet adapters based
          on the AMD Lance chipset: RieblCard (with or without battery), or
@@ -384,7 +380,7 @@ config ATARILANCE
 
 config ATARI_BIONET
        tristate "BioNet-100 support"
-       depends on NET_ETHERNET && ATARI && ATARI_ACSI && BROKEN
+       depends on ATARI && ATARI_ACSI && BROKEN
        help
          Say Y to include support for BioData's BioNet-100 Ethernet adapter
          for the ACSI port. The driver works (has to work...) with a polled
@@ -392,7 +388,7 @@ config ATARI_BIONET
 
 config ATARI_PAMSNET
        tristate "PAMsNet support"
-       depends on NET_ETHERNET && ATARI && ATARI_ACSI && BROKEN
+       depends on ATARI && ATARI_ACSI && BROKEN
        help
          Say Y to include support for the PAMsNet Ethernet adapter for the
          ACSI port ("ACSI node"). The driver works (has to work...) with a
@@ -400,7 +396,7 @@ config ATARI_PAMSNET
 
 config SUN3LANCE
        tristate "Sun3/Sun3x on-board LANCE support"
-       depends on NET_ETHERNET && (SUN3 || SUN3X)
+       depends on SUN3 || SUN3X
        help
          Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
          featured an AMD Lance 10Mbit Ethernet controller on board; say Y
@@ -413,7 +409,7 @@ config SUN3LANCE
 
 config SUN3_82586
        bool "Sun3 on-board Intel 82586 support"
-       depends on NET_ETHERNET && SUN3
+       depends on SUN3
        help
          This driver enables support for the on-board Intel 82586 based
          Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards.  Note
@@ -422,7 +418,7 @@ config SUN3_82586
 
 config HPLANCE
        bool "HP on-board LANCE support"
-       depends on NET_ETHERNET && DIO
+       depends on DIO
        select CRC32
        help
          If you want to use the builtin "LANCE" Ethernet controller on an
@@ -430,21 +426,28 @@ config HPLANCE
 
 config LASI_82596
        tristate "Lasi ethernet"
-       depends on NET_ETHERNET && GSC
+       depends on GSC
        help
          Say Y here to support the builtin Intel 82596 ethernet controller
          found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
 
+config SNI_82596
+       tristate "SNI RM ethernet"
+       depends on NET_ETHERNET && SNI_RM
+       help
+         Say Y here to support the on-board Intel 82596 ethernet controller
+         built into SNI RM machines.
+
 config MIPS_JAZZ_SONIC
        tristate "MIPS JAZZ onboard SONIC Ethernet support"
-       depends on NET_ETHERNET && MACH_JAZZ
+       depends on MACH_JAZZ
        help
          This is the driver for the onboard card of MIPS Magnum 4000,
          Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
 
 config MIPS_AU1X00_ENET
        bool "MIPS AU1000 Ethernet support"
-       depends on NET_ETHERNET && SOC_AU1X00
+       depends on SOC_AU1X00
        select PHYLIB
        select CRC32
        help
@@ -453,11 +456,11 @@ config MIPS_AU1X00_ENET
 
 config NET_SB1250_MAC
        tristate "SB1250 Ethernet support"
-       depends on NET_ETHERNET && SIBYTE_SB1xxx_SOC
+       depends on SIBYTE_SB1xxx_SOC
 
 config SGI_IOC3_ETH
        bool "SGI IOC3 Ethernet"
-       depends on NET_ETHERNET && PCI && SGI_IP27
+       depends on PCI && SGI_IP27
        select CRC32
        select MII
        help
@@ -487,7 +490,7 @@ config SGI_IOC3_ETH_HW_TX_CSUM
 
 config MIPS_SIM_NET
        tristate "MIPS simulator Network device"
-       depends on NET_ETHERNET && MIPS_SIM
+       depends on MIPS_SIM
        help
          The MIPSNET device is a simple Ethernet network device which is
          emulated by the MIPS Simulator.
@@ -495,11 +498,11 @@ config MIPS_SIM_NET
 
 config SGI_O2MACE_ETH
        tristate "SGI O2 MACE Fast Ethernet support"
-       depends on NET_ETHERNET && SGI_IP32=y
+       depends on SGI_IP32=y
 
 config STNIC
        tristate "National DP83902AV  support"
-       depends on NET_ETHERNET && SUPERH
+       depends on SUPERH
        select CRC32
        help
          Support for cards based on the National Semiconductor DP83902AV
@@ -511,7 +514,7 @@ config STNIC
 
 config SUNLANCE
        tristate "Sun LANCE support"
-       depends on NET_ETHERNET && SBUS
+       depends on SBUS
        select CRC32
        help
          This driver supports the "le" interface present on all 32-bit Sparc
@@ -524,7 +527,7 @@ config SUNLANCE
 
 config HAPPYMEAL
        tristate "Sun Happy Meal 10/100baseT support"
-       depends on NET_ETHERNET && (SBUS || PCI)
+       depends on SBUS || PCI
        select CRC32
        help
          This driver supports the "hme" interface present on most Ultra
@@ -537,7 +540,7 @@ config HAPPYMEAL
 
 config SUNBMAC
        tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
-       depends on NET_ETHERNET && SBUS && EXPERIMENTAL
+       depends on SBUS && EXPERIMENTAL
        select CRC32
        help
          This driver supports the "be" interface available as an Sbus option.
@@ -548,7 +551,7 @@ config SUNBMAC
 
 config SUNQE
        tristate "Sun QuadEthernet support"
-       depends on NET_ETHERNET && SBUS
+       depends on SBUS
        select CRC32
        help
          This driver supports the "qe" 10baseT Ethernet device, available as
@@ -560,7 +563,7 @@ config SUNQE
 
 config SUNGEM
        tristate "Sun GEM support"
-       depends on NET_ETHERNET && PCI
+       depends on PCI
        select CRC32
        help
          Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
@@ -568,7 +571,7 @@ config SUNGEM
 
 config CASSINI
        tristate "Sun Cassini support"
-       depends on NET_ETHERNET && PCI
+       depends on PCI
        select CRC32
        help
          Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
@@ -576,7 +579,7 @@ config CASSINI
 
 config NET_VENDOR_3COM
        bool "3COM cards"
-       depends on NET_ETHERNET && (ISA || EISA || MCA || PCI)
+       depends on ISA || EISA || MCA || PCI
        help
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -736,7 +739,7 @@ config TYPHOON
 
 config LANCE
        tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
-       depends on NET_ETHERNET && ISA && ISA_DMA_API
+       depends on ISA && ISA_DMA_API
        help
          If you have a network (Ethernet) card of this type, say Y and read
          the Ethernet-HOWTO, available from
@@ -748,7 +751,7 @@ config LANCE
 
 config NET_VENDOR_SMC
        bool "Western Digital/SMC cards"
-       depends on NET_ETHERNET && (ISA || MCA || EISA || MAC)
+       depends on ISA || MCA || EISA || MAC
        help
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -818,11 +821,27 @@ config ULTRA32
          <file:Documentation/networking/net-modules.txt>. The module
          will be called smc-ultra32.
 
+config SMC9194
+       tristate "SMC 9194 support"
+       depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
+       select CRC32
+       ---help---
+         This is support for the SMC9xxx based Ethernet cards. Choose this
+         option if you have a DELL laptop with the docking station, or
+         another SMC9192/9194 based chipset.  Say Y if you want it compiled
+         into the kernel, and read the file
+         <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+         available from <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here and read
+         <file:Documentation/networking/net-modules.txt>. The module
+         will be called smc9194.
+
 config SMC91X
        tristate "SMC 91C9x/91C1xxx support"
        select CRC32
        select MII
-       depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN)
+       depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN
        help
          This is a driver for SMC's 91x series of Ethernet chipsets,
          including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -836,26 +855,10 @@ config SMC91X
          module, say M here and read <file:Documentation/kbuild/modules.txt>
          as well as <file:Documentation/networking/net-modules.txt>.
 
-config SMC9194
-       tristate "SMC 9194 support"
-       depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
-       select CRC32
-       ---help---
-         This is support for the SMC9xxx based Ethernet cards. Choose this
-         option if you have a DELL laptop with the docking station, or
-         another SMC9192/9194 based chipset.  Say Y if you want it compiled
-         into the kernel, and read the file
-         <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
-         available from <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/networking/net-modules.txt>. The module
-         will be called smc9194.
-
 config NET_NETX
        tristate "NetX Ethernet support"
        select MII
-       depends on NET_ETHERNET && ARCH_NETX
+       depends on ARCH_NETX
        help
          This is support for the Hilscher netX builtin Ethernet ports
 
@@ -865,7 +868,7 @@ config NET_NETX
 
 config DM9000
        tristate "DM9000 support"
-       depends on (ARM || MIPS) && NET_ETHERNET
+       depends on ARM || MIPS
        select CRC32
        select MII
        ---help---
@@ -879,7 +882,7 @@ config SMC911X
        tristate "SMSC LAN911[5678] support"
        select CRC32
        select MII
-       depends on NET_ETHERNET && ARCH_PXA
+       depends on ARCH_PXA
        help
          This is a driver for SMSC's LAN911x series of Ethernet chipsets
          including the new LAN9115, LAN9116, LAN9117, and LAN9118.
@@ -893,7 +896,7 @@ config SMC911X
 
 config NET_VENDOR_RACAL
        bool "Racal-Interlan (Micom) NI cards"
-       depends on NET_ETHERNET && ISA
+       depends on ISA
        help
          If you have a network (Ethernet) card belonging to this class, such
          as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
@@ -945,7 +948,7 @@ source "drivers/net/tulip/Kconfig"
 
 config AT1700
        tristate "AT1700/1720 support (EXPERIMENTAL)"
-       depends on NET_ETHERNET && (ISA || MCA_LEGACY) && EXPERIMENTAL
+       depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
        select CRC32
        ---help---
          If you have a network (Ethernet) card of this type, say Y and read
@@ -958,7 +961,7 @@ config AT1700
 
 config DEPCA
        tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
-       depends on NET_ETHERNET && (ISA || EISA || MCA)
+       depends on ISA || EISA || MCA
        select CRC32
        ---help---
          If you have a network (Ethernet) card of this type, say Y and read
@@ -972,7 +975,7 @@ config DEPCA
 
 config HP100
        tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
-       depends on NET_ETHERNET && (ISA || EISA || PCI)
+       depends on ISA || EISA || PCI
        help
          If you have a network (Ethernet) card of this type, say Y and read
          the Ethernet-HOWTO, available from
@@ -984,7 +987,7 @@ config HP100
 
 config NET_ISA
        bool "Other ISA cards"
-       depends on NET_ETHERNET && ISA
+       depends on ISA
        ---help---
          If your network (Ethernet) card hasn't been mentioned yet and its
          bus system (that's the way the cards talks to the other components
@@ -1147,7 +1150,7 @@ config SEEQ8005
 
 config NE2_MCA
        tristate "NE/2 (ne2000 MCA version) support"
-       depends on NET_ETHERNET && MCA_LEGACY
+       depends on MCA_LEGACY
        select CRC32
        help
          If you have a network (Ethernet) card of this type, say Y and read
@@ -1160,7 +1163,7 @@ config NE2_MCA
 
 config IBMLANA
        tristate "IBM LAN Adapter/A support"
-       depends on NET_ETHERNET && MCA && MCA_LEGACY
+       depends on MCA && MCA_LEGACY
        ---help---
          This is a Micro Channel Ethernet adapter.  You need to set
          CONFIG_MCA to use this driver.  It is both available as an in-kernel
@@ -1176,7 +1179,7 @@ config IBMLANA
 
 config IBMVETH
        tristate "IBM LAN Virtual Ethernet support"
-       depends on NET_ETHERNET && PPC_PSERIES
+       depends on PPC_PSERIES
        ---help---
          This driver supports virtual ethernet adapters on newer IBM iSeries
          and pSeries systems.
@@ -1257,7 +1260,7 @@ config IBM_EMAC_TAH
 
 config NET_PCI
        bool "EISA, VLB, PCI and on board controllers"
-       depends on NET_ETHERNET && (ISA || EISA || PCI)
+       depends on ISA || EISA || PCI
        help
          This is another class of network cards which attach directly to the
          bus. If you have one of those, say Y and read the Ethernet-HOWTO,
@@ -1313,6 +1316,7 @@ config AMD8111_ETH
          To compile this driver as a module, choose M here and read
          <file:Documentation/networking/net-modules.txt>. The module
          will be called amd8111e.
+
 config AMD8111E_NAPI
        bool "Enable NAPI support"
        depends on AMD8111_ETH
@@ -1778,7 +1782,7 @@ config SC92031
 
 config NET_POCKET
        bool "Pocket and portable adapters"
-       depends on NET_ETHERNET && PARPORT
+       depends on PARPORT
        ---help---
          Cute little network (Ethernet) devices which attach to the parallel
          port ("pocket adapters"), commonly used with laptops. If you have
@@ -1847,14 +1851,14 @@ config DE620
 
 config SGISEEQ
        tristate "SGI Seeq ethernet controller support"
-       depends on NET_ETHERNET && SGI_IP22
+       depends on SGI_IP22
        help
          Say Y here if you have an Seeq based Ethernet network card. This is
          used in many Silicon Graphics machines.
 
 config DECLANCE
        tristate "DEC LANCE ethernet controller support"
-       depends on NET_ETHERNET && MACH_DECSTATION
+       depends on MACH_DECSTATION
        select CRC32
        help
          This driver is for the series of Ethernet controllers produced by
@@ -1884,7 +1888,7 @@ config FEC2
 
 config NE_H8300
        tristate "NE2000 compatible support for H8/300"
-       depends on H8300 && NET_ETHERNET
+       depends on H8300
        help
          Say Y here if you want to use the NE2000 compatible
          controller on the Renesas H8/300 processor.
@@ -1892,7 +1896,7 @@ config NE_H8300
 source "drivers/net/fec_8xx/Kconfig"
 source "drivers/net/fs_enet/Kconfig"
 
-endmenu
+endif # NET_ETHERNET
 
 #
 #      Gigabit Ethernet
@@ -2948,8 +2952,6 @@ config NETCONSOLE
        If you want to log kernel messages over the network, enable this.
        See <file:Documentation/networking/netconsole.txt> for details.
 
-endif #NETDEVICES
-
 config NETPOLL
        def_bool NETCONSOLE
 
@@ -2961,4 +2963,4 @@ config NETPOLL_TRAP
 config NET_POLL_CONTROLLER
        def_bool NETPOLL
 
-endmenu
+endif # NETDEVICES
index a77affa4f6e66d33b707f0aeb71e6efaa23b6a46..eb62fb48e4b7d0a183df9bff696b25f30be59ab8 100644 (file)
@@ -157,6 +157,7 @@ obj-$(CONFIG_ELPLUS) += 3c505.o
 obj-$(CONFIG_AC3200) += ac3200.o 8390.o
 obj-$(CONFIG_APRICOT) += 82596.o
 obj-$(CONFIG_LASI_82596) += lasi_82596.o
+obj-$(CONFIG_SNI_82596) += sni_82596.o
 obj-$(CONFIG_MVME16x_NET) += 82596.o
 obj-$(CONFIG_BVME6000_NET) += 82596.o
 obj-$(CONFIG_SC92031) += sc92031.o
index 04382f979c996ef9834061c21ffe25399ad879e8..b78a4e5ceeb2825889439a7be1f7969767d7c311 100644 (file)
@@ -159,10 +159,6 @@ static struct pci_device_id acenic_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
 
-#ifndef SET_NETDEV_DEV
-#define SET_NETDEV_DEV(net, pdev)      do{} while(0)
-#endif
-
 #define ace_sync_irq(irq)      synchronize_irq(irq)
 
 #ifndef offset_in_page
index 678e4f48d36bf957b8e35630f3c428438fb37bd8..5bf2d33887aca4acf4f45dc3bdf893d2a335a4ba 100644 (file)
@@ -4,7 +4,7 @@
 #
 config ARM_AM79C961A
        bool "ARM EBSA110 AM79C961A support"
-       depends on NET_ETHERNET && ARM && ARCH_EBSA110
+       depends on ARM && ARCH_EBSA110
        select CRC32
        help
          If you wish to compile a kernel for the EBSA-110, then you should
@@ -12,21 +12,21 @@ config ARM_AM79C961A
 
 config ARM_ETHER1
        tristate "Acorn Ether1 support"
-       depends on NET_ETHERNET && ARM && ARCH_ACORN
+       depends on ARM && ARCH_ACORN
        help
          If you have an Acorn system with one of these (AKA25) network cards,
          you should say Y to this option if you wish to use it with Linux.
 
 config ARM_ETHER3
        tristate "Acorn/ANT Ether3 support"
-       depends on NET_ETHERNET && ARM && ARCH_ACORN
+       depends on ARM && ARCH_ACORN
        help
          If you have an Acorn system with one of these network cards, you
          should say Y to this option if you wish to use it with Linux.
 
 config ARM_ETHERH
        tristate "I-cubed EtherH/ANT EtherM support"
-       depends on NET_ETHERNET && ARM && ARCH_ACORN
+       depends on ARM && ARCH_ACORN
        select CRC32
        help
          If you have an Acorn system with one of these network cards, you
@@ -34,7 +34,7 @@ config ARM_ETHERH
 
 config ARM_AT91_ETHER
        tristate "AT91RM9200 Ethernet support"
-       depends on NET_ETHERNET && ARM && ARCH_AT91RM9200
+       depends on ARM && ARCH_AT91RM9200
        select MII
        help
          If you wish to compile a kernel for the AT91RM9200 and enable
@@ -42,7 +42,7 @@ config ARM_AT91_ETHER
 
 config EP93XX_ETH
        tristate "EP93xx Ethernet support"
-       depends on NET_ETHERNET && ARM && ARCH_EP93XX
+       depends on ARM && ARCH_EP93XX
        help
          This is a driver for the ethernet hardware included in EP93xx CPUs.
          Say Y if you are building a kernel for EP93xx based devices.
index 879a2fff474e007f62907e642d1ea9fdab2ec04b..96fb0ec905a7f176b691c811a0563991f1985c4f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/if_ether.h>
+#include <linux/if_vlan.h>
 #include <linux/etherdevice.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -68,8 +69,8 @@
          (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
 #define NEXT_TX(N)             (((N) + 1) & (B44_TX_RING_SIZE - 1))
 
-#define RX_PKT_BUF_SZ          (1536 + bp->rx_offset + 64)
-#define TX_PKT_BUF_SZ          (B44_MAX_MTU + ETH_HLEN + 8)
+#define RX_PKT_OFFSET          30
+#define RX_PKT_BUF_SZ          (1536 + RX_PKT_OFFSET + 64)
 
 /* minimum number of free TX descriptors required to wake up TX process */
 #define B44_TX_WAKEUP_THRESH           (B44_TX_RING_SIZE / 4)
@@ -599,8 +600,7 @@ static void b44_timer(unsigned long __opaque)
 
        spin_unlock_irq(&bp->lock);
 
-       bp->timer.expires = jiffies + HZ;
-       add_timer(&bp->timer);
+       mod_timer(&bp->timer, round_jiffies(jiffies + HZ));
 }
 
 static void b44_tx(struct b44 *bp)
@@ -653,7 +653,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
                src_map = &bp->rx_buffers[src_idx];
        dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
        map = &bp->rx_buffers[dest_idx];
-       skb = dev_alloc_skb(RX_PKT_BUF_SZ);
+       skb = netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ);
        if (skb == NULL)
                return -ENOMEM;
 
@@ -669,7 +669,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
                if (!dma_mapping_error(mapping))
                        pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
                dev_kfree_skb_any(skb);
-               skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA);
+               skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
                if (skb == NULL)
                        return -ENOMEM;
                mapping = pci_map_single(bp->pdev, skb->data,
@@ -684,11 +684,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
                }
        }
 
-       skb->dev = bp->dev;
-       skb_reserve(skb, bp->rx_offset);
+       rh = (struct rx_header *) skb->data;
+       skb_reserve(skb, RX_PKT_OFFSET);
 
-       rh = (struct rx_header *)
-               (skb->data - bp->rx_offset);
        rh->len = 0;
        rh->flags = 0;
 
@@ -698,13 +696,13 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
        if (src_map != NULL)
                src_map->skb = NULL;
 
-       ctrl  = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - bp->rx_offset));
+       ctrl  = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET));
        if (dest_idx == (B44_RX_RING_SIZE - 1))
                ctrl |= DESC_CTRL_EOT;
 
        dp = &bp->rx_ring[dest_idx];
        dp->ctrl = cpu_to_le32(ctrl);
-       dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
+       dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
 
        if (bp->flags & B44_FLAG_RX_RING_HACK)
                b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
@@ -783,7 +781,7 @@ static int b44_rx(struct b44 *bp, int budget)
                                            PCI_DMA_FROMDEVICE);
                rh = (struct rx_header *) skb->data;
                len = le16_to_cpu(rh->len);
-               if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
+               if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
                    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
                drop_it:
                        b44_recycle_rx(bp, cons, bp->rx_prod);
@@ -815,8 +813,8 @@ static int b44_rx(struct b44 *bp, int budget)
                        pci_unmap_single(bp->pdev, map,
                                         skb_size, PCI_DMA_FROMDEVICE);
                        /* Leave out rx_header */
-                       skb_put(skb, len+bp->rx_offset);
-                       skb_pull(skb,bp->rx_offset);
+                       skb_put(skb, len + RX_PKT_OFFSET);
+                       skb_pull(skb, RX_PKT_OFFSET);
                } else {
                        struct sk_buff *copy_skb;
 
@@ -828,7 +826,7 @@ static int b44_rx(struct b44 *bp, int budget)
                        skb_reserve(copy_skb, 2);
                        skb_put(copy_skb, len);
                        /* DMA sync done above, copy just the actual packet */
-                       skb_copy_from_linear_data_offset(skb, bp->rx_offset,
+                       skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET,
                                                         copy_skb->data, len);
                        skb = copy_skb;
                }
@@ -969,7 +967,6 @@ static void b44_tx_timeout(struct net_device *dev)
 static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct b44 *bp = netdev_priv(dev);
-       struct sk_buff *bounce_skb;
        int rc = NETDEV_TX_OK;
        dma_addr_t mapping;
        u32 len, entry, ctrl;
@@ -987,12 +984,13 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
        if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
+               struct sk_buff *bounce_skb;
+
                /* Chip can't handle DMA to/from >1GB, use bounce buffer */
                if (!dma_mapping_error(mapping))
                        pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
 
-               bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
-                                            GFP_ATOMIC|GFP_DMA);
+               bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb)
                        goto err_out;
 
@@ -1001,13 +999,12 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
                if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
                        if (!dma_mapping_error(mapping))
                                pci_unmap_single(bp->pdev, mapping,
-                                        len, PCI_DMA_TODEVICE);
+                                                len, PCI_DMA_TODEVICE);
                        dev_kfree_skb_any(bounce_skb);
                        goto err_out;
                }
 
-               skb_copy_from_linear_data(skb, skb_put(bounce_skb, len),
-                                         skb->len);
+               skb_copy_from_linear_data(skb, skb_put(bounce_skb, len), len);
                dev_kfree_skb_any(skb);
                skb = bounce_skb;
        }
@@ -1396,12 +1393,12 @@ static void b44_init_hw(struct b44 *bp, int reset_kind)
        bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
        if (reset_kind == B44_PARTIAL_RESET) {
                bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
-                                     (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+                                     (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)));
        } else {
                bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
                bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
                bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
-                                     (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+                                     (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)));
                bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
 
                bw32(bp, B44_DMARX_PTR, bp->rx_pending);
@@ -2093,11 +2090,6 @@ static int __devinit b44_get_invariants(struct b44 *bp)
 
        bp->phy_addr = eeprom[90] & 0x1f;
 
-       /* With this, plus the rx_header prepended to the data by the
-        * hardware, we'll land the ethernet header on a 2-byte boundary.
-        */
-       bp->rx_offset = 30;
-
        bp->imask = IMASK_DEF;
 
        bp->core_unit = ssb_core_unit(bp);
@@ -2348,11 +2340,11 @@ static int b44_resume(struct pci_dev *pdev)
        netif_device_attach(bp->dev);
        spin_unlock_irq(&bp->lock);
 
-       bp->timer.expires = jiffies + HZ;
-       add_timer(&bp->timer);
-
        b44_enable_ints(bp);
        netif_wake_queue(dev);
+
+       mod_timer(&bp->timer, jiffies + 1);
+
        return 0;
 }
 
index 18fc13336628fd5fa532ee822b9d0bcf378b4e7c..e537e63f292e6e948dfea4567cacfe99a0ef1a0b 100644 (file)
@@ -443,8 +443,6 @@ struct b44 {
 #define B44_FLAG_TX_RING_HACK  0x40000000
 #define B44_FLAG_WOL_ENABLE    0x80000000
 
-       u32                     rx_offset;
-
        u32                     msg_enable;
 
        struct timer_list       timer;
index 80c3d8f268a7091edce2bd01f05174b1fc065afc..ab72563b81ee569ce7f9a139203762dcc5598314 100644 (file)
@@ -71,27 +71,29 @@ enum {                              /* adapter flags */
        QUEUES_BOUND = (1 << 3),
 };
 
+struct fl_pg_chunk {
+       struct page *page;
+       void *va;
+       unsigned int offset;
+};
+
 struct rx_desc;
 struct rx_sw_desc;
 
-struct sge_fl_page {
-       struct skb_frag_struct frag;
-       unsigned char *va;
-};
-
-struct sge_fl {                        /* SGE per free-buffer list state */
-       unsigned int buf_size;  /* size of each Rx buffer */
-       unsigned int credits;   /* # of available Rx buffers */
-       unsigned int size;      /* capacity of free list */
-       unsigned int cidx;      /* consumer index */
-       unsigned int pidx;      /* producer index */
-       unsigned int gen;       /* free list generation */
-       unsigned int cntxt_id;  /* SGE context id for the free list */
-       struct sge_fl_page page;
-       struct rx_desc *desc;   /* address of HW Rx descriptor ring */
-       struct rx_sw_desc *sdesc;       /* address of SW Rx descriptor ring */
-       dma_addr_t phys_addr;   /* physical address of HW ring start */
-       unsigned long empty;    /* # of times queue ran out of buffers */
+struct sge_fl {                     /* SGE per free-buffer list state */
+       unsigned int buf_size;      /* size of each Rx buffer */
+       unsigned int credits;       /* # of available Rx buffers */
+       unsigned int size;          /* capacity of free list */
+       unsigned int cidx;          /* consumer index */
+       unsigned int pidx;          /* producer index */
+       unsigned int gen;           /* free list generation */
+       struct fl_pg_chunk pg_chunk;/* page chunk cache */
+       unsigned int use_pages;     /* whether FL uses pages or sk_buffs */
+       struct rx_desc *desc;       /* address of HW Rx descriptor ring */
+       struct rx_sw_desc *sdesc;   /* address of SW Rx descriptor ring */
+       dma_addr_t   phys_addr;     /* physical address of HW ring start */
+       unsigned int cntxt_id;      /* SGE context id for the free list */
+       unsigned long empty;        /* # of times queue ran out of buffers */
        unsigned long alloc_failed; /* # of times buffer allocation failed */
 };
 
index 8d1379633698737835b28e66bb0f9c2bd1e067b0..16378004507ad65c253b0b6df22c4c600897e00f 100644 (file)
@@ -101,6 +101,7 @@ enum {
        TCB_SIZE = 128,         /* TCB size */
        NMTUS = 16,             /* size of MTU table */
        NCCTRL_WIN = 32,        /* # of congestion control windows */
+       PROTO_SRAM_LINES = 128, /* size of TP sram */
 };
 
 #define MAX_RX_COALESCING_LEN 16224U
@@ -123,6 +124,30 @@ enum {                             /* adapter interrupt-maintained statistics */
        IRQ_NUM_STATS           /* keep last */
 };
 
+enum {
+       TP_VERSION_MAJOR        = 1,
+       TP_VERSION_MINOR        = 0,
+       TP_VERSION_MICRO        = 44
+};
+
+#define S_TP_VERSION_MAJOR             16
+#define M_TP_VERSION_MAJOR             0xFF
+#define V_TP_VERSION_MAJOR(x)          ((x) << S_TP_VERSION_MAJOR)
+#define G_TP_VERSION_MAJOR(x)          \
+           (((x) >> S_TP_VERSION_MAJOR) & M_TP_VERSION_MAJOR)
+
+#define S_TP_VERSION_MINOR             8
+#define M_TP_VERSION_MINOR             0xFF
+#define V_TP_VERSION_MINOR(x)          ((x) << S_TP_VERSION_MINOR)
+#define G_TP_VERSION_MINOR(x)          \
+           (((x) >> S_TP_VERSION_MINOR) & M_TP_VERSION_MINOR)
+
+#define S_TP_VERSION_MICRO             0
+#define M_TP_VERSION_MICRO             0xFF
+#define V_TP_VERSION_MICRO(x)          ((x) << S_TP_VERSION_MICRO)
+#define G_TP_VERSION_MICRO(x)          \
+           (((x) >> S_TP_VERSION_MICRO) & M_TP_VERSION_MICRO)
+
 enum {
        SGE_QSETS = 8,          /* # of SGE Tx/Rx/RspQ sets */
        SGE_RXQ_PER_SET = 2,    /* # of Rx queues per set */
@@ -654,6 +679,9 @@ const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
 int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
 int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
 int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_check_tpsram_version(struct adapter *adapter);
+int t3_check_tpsram(struct adapter *adapter, u8 *tp_ram, unsigned int size);
+int t3_set_proto_sram(struct adapter *adap, u8 *data);
 int t3_read_flash(struct adapter *adapter, unsigned int addr,
                  unsigned int nwords, u32 *data, int byte_oriented);
 int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
index d8a1f5452c51513092a2504548a6c8998d038a39..15defe4c4f05e947f765b2e5b3ab17904bb2722b 100644 (file)
@@ -2088,6 +2088,42 @@ static void cxgb_netpoll(struct net_device *dev)
 }
 #endif
 
+#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
+int update_tpsram(struct adapter *adap)
+{
+       const struct firmware *tpsram;
+       char buf[64];
+       struct device *dev = &adap->pdev->dev;
+       int ret;
+       char rev;
+       
+       rev = adap->params.rev == T3_REV_B2 ? 'b' : 'a';
+
+       snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
+                TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+
+       ret = request_firmware(&tpsram, buf, dev);
+       if (ret < 0) {
+               dev_err(dev, "could not load TP SRAM: unable to load %s\n",
+                       buf);
+               return ret;
+       }
+       
+       ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
+       if (ret)
+               goto release_tpsram;    
+
+       ret = t3_set_proto_sram(adap, tpsram->data);
+       if (ret)
+               dev_err(dev, "loading protocol SRAM failed\n");
+
+release_tpsram:
+       release_firmware(tpsram);
+       
+       return ret;
+}
+
+
 /*
  * Periodic accumulation of MAC statistics.
  */
@@ -2437,6 +2473,13 @@ static int __devinit init_one(struct pci_dev *pdev,
                goto out_free_dev;
        }
 
+       err = t3_check_tpsram_version(adapter);
+       if (err == -EINVAL)
+               err = update_tpsram(adapter);
+
+       if (err)
+               goto out_free_dev;
+               
        /*
         * The card is now ready to go.  If any errors occur during device
         * registration we do not fail the whole card but rather proceed only
index 020859c855d7c6836657ab133484f0d7d6aa4ef5..aa80313c922ef3913e5f85796c51921111505a45 100644 (file)
 
 #define A_TP_MOD_CHANNEL_WEIGHT 0x434
 
+#define A_TP_MOD_RATE_LIMIT 0x438
+
 #define A_TP_PIO_ADDR 0x440
 
 #define A_TP_PIO_DATA 0x444
 #define G_TXDROPCNTCH0RCVD(x) (((x) >> S_TXDROPCNTCH0RCVD) & \
                               M_TXDROPCNTCH0RCVD)
 
+#define A_TP_PROXY_FLOW_CNTL 0x4b0
+
+#define A_TP_EMBED_OP_FIELD0 0x4e8
+#define A_TP_EMBED_OP_FIELD1 0x4ec
+#define A_TP_EMBED_OP_FIELD2 0x4f0
+#define A_TP_EMBED_OP_FIELD3 0x4f4
+#define A_TP_EMBED_OP_FIELD4 0x4f8
+#define A_TP_EMBED_OP_FIELD5 0x4fc
+
 #define A_ULPRX_CTL 0x500
 
 #define S_ROUND_ROBIN    4
index a60ec4d4707c50c2919bf2f99cd5f5051f3d483a..a2cfd68ac757555e42b13309f019146f6a6f00e4 100644 (file)
 
 #define SGE_RX_SM_BUF_SIZE 1536
 
-/*
- * If USE_RX_PAGE is defined, the small freelist populated with (partial)
- * pages instead of skbs. Pages are carved up into RX_PAGE_SIZE chunks (must
- * be a multiple of the host page size).
- */
-#define USE_RX_PAGE
-#define RX_PAGE_SIZE 2048
-
-/*
- * skb freelist packets are copied into a new skb (and the freelist one is 
- * reused) if their len is <= 
- */
 #define SGE_RX_COPY_THRES  256
+#define SGE_RX_PULL_LEN    128
 
 /*
- * Minimum number of freelist entries before we start dropping TUNNEL frames.
+ * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks.
+ * It must be a divisor of PAGE_SIZE.  If set to 0 FL0 will use sk_buffs
+ * directly.
  */
+#define FL0_PG_CHUNK_SIZE  2048
+
 #define SGE_RX_DROP_THRES 16
 
 /*
@@ -100,12 +93,12 @@ struct tx_sw_desc {                /* SW state per Tx descriptor */
        struct sk_buff *skb;
 };
 
-struct rx_sw_desc {            /* SW state per Rx descriptor */
+struct rx_sw_desc {                /* SW state per Rx descriptor */
        union {
                struct sk_buff *skb;
-               struct sge_fl_page page;
-       } t;
-        DECLARE_PCI_UNMAP_ADDR(dma_addr);
+               struct fl_pg_chunk pg_chunk;
+       };
+       DECLARE_PCI_UNMAP_ADDR(dma_addr);
 };
 
 struct rsp_desc {              /* response queue descriptor */
@@ -351,27 +344,26 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
 
                pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
                                 q->buf_size, PCI_DMA_FROMDEVICE);
-
-               if (q->buf_size != RX_PAGE_SIZE) {
-                       kfree_skb(d->t.skb);
-                       d->t.skb = NULL;
+               if (q->use_pages) {
+                       put_page(d->pg_chunk.page);
+                       d->pg_chunk.page = NULL;
                } else {
-                       if (d->t.page.frag.page)
-                               put_page(d->t.page.frag.page);
-                       d->t.page.frag.page = NULL;
+                       kfree_skb(d->skb);
+                       d->skb = NULL;
                }
                if (++cidx == q->size)
                        cidx = 0;
        }
 
-       if (q->page.frag.page)
-               put_page(q->page.frag.page);
-       q->page.frag.page = NULL;
+       if (q->pg_chunk.page) {
+               __free_page(q->pg_chunk.page);
+               q->pg_chunk.page = NULL;
+       }
 }
 
 /**
  *     add_one_rx_buf - add a packet buffer to a free-buffer list
- *     @va: va of the buffer to add
+ *     @va:  buffer start VA
  *     @len: the buffer length
  *     @d: the HW Rx descriptor to write
  *     @sd: the SW Rx descriptor to write
@@ -381,7 +373,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
  *     Add a buffer of the given length to the supplied HW and SW Rx
  *     descriptors.
  */
-static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
+static inline void add_one_rx_buf(void *va, unsigned int len,
                                  struct rx_desc *d, struct rx_sw_desc *sd,
                                  unsigned int gen, struct pci_dev *pdev)
 {
@@ -397,6 +389,27 @@ static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
        d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
 }
 
+static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
+{
+       if (!q->pg_chunk.page) {
+               q->pg_chunk.page = alloc_page(gfp);
+               if (unlikely(!q->pg_chunk.page))
+                       return -ENOMEM;
+               q->pg_chunk.va = page_address(q->pg_chunk.page);
+               q->pg_chunk.offset = 0;
+       }
+       sd->pg_chunk = q->pg_chunk;
+
+       q->pg_chunk.offset += q->buf_size;
+       if (q->pg_chunk.offset == PAGE_SIZE)
+               q->pg_chunk.page = NULL;
+       else {
+               q->pg_chunk.va += q->buf_size;
+               get_page(q->pg_chunk.page);
+       }
+       return 0;
+}
+
 /**
  *     refill_fl - refill an SGE free-buffer list
  *     @adapter: the adapter
@@ -410,49 +423,29 @@ static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
  */
 static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
 {
+       void *buf_start;
        struct rx_sw_desc *sd = &q->sdesc[q->pidx];
        struct rx_desc *d = &q->desc[q->pidx];
-       struct sge_fl_page *p = &q->page;
 
        while (n--) {
-               unsigned char *va;
-
-               if (unlikely(q->buf_size != RX_PAGE_SIZE)) {
-                       struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
-
-                       if (!skb) {
-                               q->alloc_failed++;
+               if (q->use_pages) {
+                       if (unlikely(alloc_pg_chunk(q, sd, gfp))) {
+nomem:                         q->alloc_failed++;
                                break;
                        }
-                       va = skb->data;
-                       sd->t.skb = skb;
+                       buf_start = sd->pg_chunk.va;
                } else {
-                       if (!p->frag.page) {
-                               p->frag.page = alloc_pages(gfp, 0);
-                               if (unlikely(!p->frag.page)) {
-                                       q->alloc_failed++;
-                                       break;
-                               } else {
-                                       p->frag.size = RX_PAGE_SIZE;
-                                       p->frag.page_offset = 0;
-                                       p->va = page_address(p->frag.page);
-                               }
-                       }
+                       struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
 
-                       memcpy(&sd->t, p, sizeof(*p));
-                       va = p->va;
+                       if (!skb)
+                               goto nomem;
 
-                       p->frag.page_offset += RX_PAGE_SIZE;
-                       BUG_ON(p->frag.page_offset > PAGE_SIZE);
-                       p->va += RX_PAGE_SIZE;
-                       if (p->frag.page_offset == PAGE_SIZE)
-                               p->frag.page = NULL;
-                       else
-                               get_page(p->frag.page);
+                       sd->skb = skb;
+                       buf_start = skb->data;
                }
 
-               add_one_rx_buf(va, q->buf_size, d, sd, q->gen, adap->pdev);
-
+               add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
+                              adap->pdev);
                d++;
                sd++;
                if (++q->pidx == q->size) {
@@ -487,7 +480,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
        struct rx_desc *from = &q->desc[idx];
        struct rx_desc *to = &q->desc[q->pidx];
 
-       memcpy(&q->sdesc[q->pidx], &q->sdesc[idx], sizeof(struct rx_sw_desc));
+       q->sdesc[q->pidx] = q->sdesc[idx];
        to->addr_lo = from->addr_lo;    /* already big endian */
        to->addr_hi = from->addr_hi;    /* likewise */
        wmb();
@@ -649,6 +642,132 @@ static inline unsigned int flits_to_desc(unsigned int n)
        return flit_desc_map[n];
 }
 
+/**
+ *     get_packet - return the next ingress packet buffer from a free list
+ *     @adap: the adapter that received the packet
+ *     @fl: the SGE free list holding the packet
+ *     @len: the packet length including any SGE padding
+ *     @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ *     Get the next packet from a free list and complete setup of the
+ *     sk_buff.  If the packet is small we make a copy and recycle the
+ *     original buffer, otherwise we use the original buffer itself.  If a
+ *     positive drop threshold is supplied packets are dropped and their
+ *     buffers recycled if (a) the number of remaining buffers is under the
+ *     threshold and the packet is too big to copy, or (b) the packet should
+ *     be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+                                 unsigned int len, unsigned int drop_thres)
+{
+       struct sk_buff *skb = NULL;
+       struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+       prefetch(sd->skb->data);
+       fl->credits--;
+
+       if (len <= SGE_RX_COPY_THRES) {
+               skb = alloc_skb(len, GFP_ATOMIC);
+               if (likely(skb != NULL)) {
+                       __skb_put(skb, len);
+                       pci_dma_sync_single_for_cpu(adap->pdev,
+                                           pci_unmap_addr(sd, dma_addr), len,
+                                           PCI_DMA_FROMDEVICE);
+                       memcpy(skb->data, sd->skb->data, len);
+                       pci_dma_sync_single_for_device(adap->pdev,
+                                           pci_unmap_addr(sd, dma_addr), len,
+                                           PCI_DMA_FROMDEVICE);
+               } else if (!drop_thres)
+                       goto use_orig_buf;
+recycle:
+               recycle_rx_buf(adap, fl, fl->cidx);
+               return skb;
+       }
+
+       if (unlikely(fl->credits < drop_thres))
+               goto recycle;
+
+use_orig_buf:
+       pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+                        fl->buf_size, PCI_DMA_FROMDEVICE);
+       skb = sd->skb;
+       skb_put(skb, len);
+       __refill_fl(adap, fl);
+       return skb;
+}
+
+/**
+ *     get_packet_pg - return the next ingress packet buffer from a free list
+ *     @adap: the adapter that received the packet
+ *     @fl: the SGE free list holding the packet
+ *     @len: the packet length including any SGE padding
+ *     @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ *     Get the next packet from a free list populated with page chunks.
+ *     If the packet is small we make a copy and recycle the original buffer,
+ *     otherwise we attach the original buffer as a page fragment to a fresh
+ *     sk_buff.  If a positive drop threshold is supplied packets are dropped
+ *     and their buffers recycled if (a) the number of remaining buffers is
+ *     under the threshold and the packet is too big to copy, or (b) there's
+ *     no system memory.
+ *
+ *     Note: this function is similar to @get_packet but deals with Rx buffers
+ *     that are page chunks rather than sk_buffs.
+ */
+static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl,
+                                    unsigned int len, unsigned int drop_thres)
+{
+       struct sk_buff *skb = NULL;
+       struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+       if (len <= SGE_RX_COPY_THRES) {
+               skb = alloc_skb(len, GFP_ATOMIC);
+               if (likely(skb != NULL)) {
+                       __skb_put(skb, len);
+                       pci_dma_sync_single_for_cpu(adap->pdev,
+                                           pci_unmap_addr(sd, dma_addr), len,
+                                           PCI_DMA_FROMDEVICE);
+                       memcpy(skb->data, sd->pg_chunk.va, len);
+                       pci_dma_sync_single_for_device(adap->pdev,
+                                           pci_unmap_addr(sd, dma_addr), len,
+                                           PCI_DMA_FROMDEVICE);
+               } else if (!drop_thres)
+                       return NULL;
+recycle:
+               fl->credits--;
+               recycle_rx_buf(adap, fl, fl->cidx);
+               return skb;
+       }
+
+       if (unlikely(fl->credits <= drop_thres))
+               goto recycle;
+
+       skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
+       if (unlikely(!skb)) {
+               if (!drop_thres)
+                       return NULL;
+               goto recycle;
+       }
+
+       pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+                        fl->buf_size, PCI_DMA_FROMDEVICE);
+       __skb_put(skb, SGE_RX_PULL_LEN);
+       memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
+       skb_fill_page_desc(skb, 0, sd->pg_chunk.page,
+                          sd->pg_chunk.offset + SGE_RX_PULL_LEN,
+                          len - SGE_RX_PULL_LEN);
+       skb->len = len;
+       skb->data_len = len - SGE_RX_PULL_LEN;
+       skb->truesize += skb->data_len;
+
+       fl->credits--;
+       /*
+        * We do not refill FLs here, we let the caller do it to overlap a
+        * prefetch.
+        */
+       return skb;
+}
+
 /**
  *     get_imm_packet - return the next ingress packet buffer from a response
  *     @resp: the response descriptor containing the packet data
@@ -1715,85 +1834,6 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
                netif_rx(skb);
 }
 
-#define SKB_DATA_SIZE 128
-
-static void skb_data_init(struct sk_buff *skb, struct sge_fl_page *p,
-                         unsigned int len)
-{
-       skb->len = len;
-       if (len <= SKB_DATA_SIZE) {
-               skb_copy_to_linear_data(skb, p->va, len);
-               skb->tail += len;
-               put_page(p->frag.page);
-       } else {
-               skb_copy_to_linear_data(skb, p->va, SKB_DATA_SIZE);
-               skb_shinfo(skb)->frags[0].page = p->frag.page;
-               skb_shinfo(skb)->frags[0].page_offset =
-                   p->frag.page_offset + SKB_DATA_SIZE;
-               skb_shinfo(skb)->frags[0].size = len - SKB_DATA_SIZE;
-               skb_shinfo(skb)->nr_frags = 1;
-               skb->data_len = len - SKB_DATA_SIZE;
-               skb->tail += SKB_DATA_SIZE;
-               skb->truesize += skb->data_len;
-       }
-}
-
-/**
-*      get_packet - return the next ingress packet buffer from a free list
-*      @adap: the adapter that received the packet
-*      @fl: the SGE free list holding the packet
-*      @len: the packet length including any SGE padding
-*      @drop_thres: # of remaining buffers before we start dropping packets
-*
-*      Get the next packet from a free list and complete setup of the
-*      sk_buff.  If the packet is small we make a copy and recycle the
-*      original buffer, otherwise we use the original buffer itself.  If a
-*      positive drop threshold is supplied packets are dropped and their
-*      buffers recycled if (a) the number of remaining buffers is under the
-*      threshold and the packet is too big to copy, or (b) the packet should
-*      be copied but there is no memory for the copy.
-*/
-static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
-                                 unsigned int len, unsigned int drop_thres)
-{
-       struct sk_buff *skb = NULL;
-       struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
-
-       prefetch(sd->t.skb->data);
-
-       if (len <= SGE_RX_COPY_THRES) {
-               skb = alloc_skb(len, GFP_ATOMIC);
-               if (likely(skb != NULL)) {
-                       struct rx_desc *d = &fl->desc[fl->cidx];
-                       dma_addr_t mapping =
-                           (dma_addr_t)((u64) be32_to_cpu(d->addr_hi) << 32 |
-                                        be32_to_cpu(d->addr_lo));
-
-                       __skb_put(skb, len);
-                       pci_dma_sync_single_for_cpu(adap->pdev, mapping, len,
-                                                   PCI_DMA_FROMDEVICE);
-                       skb_copy_from_linear_data(sd->t.skb, skb->data, len);
-                       pci_dma_sync_single_for_device(adap->pdev, mapping, len,
-                                                      PCI_DMA_FROMDEVICE);
-               } else if (!drop_thres)
-                       goto use_orig_buf;
-recycle:
-               recycle_rx_buf(adap, fl, fl->cidx);
-               return skb;
-       }
-
-       if (unlikely(fl->credits < drop_thres))
-               goto recycle;
-
-use_orig_buf:
-       pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
-                        fl->buf_size, PCI_DMA_FROMDEVICE);
-       skb = sd->t.skb;
-       skb_put(skb, len);
-       __refill_fl(adap, fl);
-       return skb;
-}
-
 /**
  *     handle_rsp_cntrl_info - handles control information in a response
  *     @qs: the queue set corresponding to the response
@@ -1935,7 +1975,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
                } else if (flags & F_RSPD_IMM_DATA_VALID) {
                        skb = get_imm_packet(r);
                        if (unlikely(!skb)) {
-                             no_mem:
+no_mem:
                                q->next_holdoff = NOMEM_INTR_DELAY;
                                q->nomem++;
                                /* consume one credit since we tried */
@@ -1945,53 +1985,29 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
                        q->imm_data++;
                        ethpad = 0;
                } else if ((len = ntohl(r->len_cq)) != 0) {
-                       struct sge_fl *fl =
-                           (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+                       struct sge_fl *fl;
 
-                       if (fl->buf_size == RX_PAGE_SIZE) {
-                               struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
-                               struct sge_fl_page *p = &sd->t.page;
-
-                               prefetch(p->va);
-                               prefetch(p->va + L1_CACHE_BYTES);
+                       fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+                       if (fl->use_pages) {
+                               void *addr = fl->sdesc[fl->cidx].pg_chunk.va;
 
+                               prefetch(addr);
+#if L1_CACHE_BYTES < 128
+                               prefetch(addr + L1_CACHE_BYTES);
+#endif
                                __refill_fl(adap, fl);
 
-                               pci_unmap_single(adap->pdev,
-                                                pci_unmap_addr(sd, dma_addr),
-                                                fl->buf_size,
-                                                PCI_DMA_FROMDEVICE);
-
-                               if (eth) {
-                                       if (unlikely(fl->credits <
-                                                    SGE_RX_DROP_THRES))
-                                               goto eth_recycle;
-
-                                       skb = alloc_skb(SKB_DATA_SIZE,
-                                                       GFP_ATOMIC);
-                                       if (unlikely(!skb)) {
-eth_recycle:
-                                               q->rx_drops++;
-                                               recycle_rx_buf(adap, fl,
-                                                              fl->cidx);
-                                               goto eth_done;
-                                       }
-                               } else {
-                                       skb = alloc_skb(SKB_DATA_SIZE,
-                                                       GFP_ATOMIC);
-                                       if (unlikely(!skb))
-                                               goto no_mem;
-                               }
-
-                               skb_data_init(skb, p, G_RSPD_LEN(len));
-eth_done:
-                               fl->credits--;
-                               q->eth_pkts++;
-                       } else {
-                               fl->credits--;
+                               skb = get_packet_pg(adap, fl, G_RSPD_LEN(len),
+                                                eth ? SGE_RX_DROP_THRES : 0);
+                       } else
                                skb = get_packet(adap, fl, G_RSPD_LEN(len),
                                                 eth ? SGE_RX_DROP_THRES : 0);
-                       }
+                       if (unlikely(!skb)) {
+                               if (!eth)
+                                       goto no_mem;
+                               q->rx_drops++;
+                       } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT))
+                               __skb_pull(skb, 2);
 
                        if (++fl->cidx == fl->size)
                                fl->cidx = 0;
@@ -2016,20 +2032,15 @@ eth_done:
                        q->credits = 0;
                }
 
-               if (skb) {
-                       /* Preserve the RSS info in csum & priority */
-                       skb->csum = rss_hi;
-                       skb->priority = rss_lo;
-
+               if (likely(skb != NULL)) {
                        if (eth)
                                rx_eth(adap, q, skb, ethpad);
                        else {
-                               if (unlikely(r->rss_hdr.opcode ==
-                                            CPL_TRACE_PKT))
-                                       __skb_pull(skb, ethpad);
-
-                               ngathered = rx_offload(&adap->tdev, q,
-                                                      skb, offload_skbs,
+                               /* Preserve the RSS info in csum & priority */
+                               skb->csum = rss_hi;
+                               skb->priority = rss_lo;
+                               ngathered = rx_offload(&adap->tdev, q, skb,
+                                                      offload_skbs,
                                                       ngathered);
                        }
                }
@@ -2635,25 +2646,15 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
        q->txq[TXQ_ETH].stop_thres = nports *
            flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
 
-       if (!is_offload(adapter)) {
-#ifdef USE_RX_PAGE
-               q->fl[0].buf_size = RX_PAGE_SIZE;
+#if FL0_PG_CHUNK_SIZE > 0
+       q->fl[0].buf_size = FL0_PG_CHUNK_SIZE;
 #else
-               q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
-                   sizeof(struct cpl_rx_pkt);
+       q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data);
 #endif
-               q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
-                   sizeof(struct cpl_rx_pkt);
-       } else {
-#ifdef USE_RX_PAGE
-               q->fl[0].buf_size = RX_PAGE_SIZE;
-#else
-               q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
-                   sizeof(struct cpl_rx_data);
-#endif
-               q->fl[1].buf_size = (16 * 1024) -
-                   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
-       }
+       q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+       q->fl[1].buf_size = is_offload(adapter) ?
+               (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
+               MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt);
 
        spin_lock(&adapter->sge.reg_lock);
 
index fb485d0a43d8a768bcc5673c4a3d51b1f5a8f0f3..dd3149d94ba8ed7115e9bd5149d7a26afe5b09f9 100644 (file)
@@ -847,6 +847,64 @@ static int t3_write_flash(struct adapter *adapter, unsigned int addr,
        return 0;
 }
 
+/**
+ *     t3_check_tpsram_version - read the tp sram version
+ *     @adapter: the adapter
+ *
+ *     Reads the protocol sram version from serial eeprom.
+ */
+int t3_check_tpsram_version(struct adapter *adapter)
+{
+       int ret;
+       u32 vers;
+       unsigned int major, minor;
+
+       /* Get version loaded in SRAM */
+       t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
+       ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
+                             1, 1, 5, 1);
+       if (ret)
+               return ret;
+       
+       vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+
+       major = G_TP_VERSION_MAJOR(vers);
+       minor = G_TP_VERSION_MINOR(vers);
+
+       if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 
+               return 0;
+
+       return -EINVAL;
+}
+
+/**
+ *     t3_check_tpsram - check if provided protocol SRAM 
+ *                       is compatible with this driver
+ *     @adapter: the adapter
+ *     @tp_sram: the firmware image to write
+ *     @size: image size
+ *
+ *     Checks if an adapter's tp sram is compatible with the driver.
+ *     Returns 0 if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_tpsram(struct adapter *adapter, u8 *tp_sram, unsigned int size)
+{
+       u32 csum;
+       unsigned int i;
+       const u32 *p = (const u32 *)tp_sram;
+
+       /* Verify checksum */
+       for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+               csum += ntohl(p[i]);
+       if (csum != 0xffffffff) {
+               CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
+                      csum);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 enum fw_version_type {
        FW_VERSION_N3,
        FW_VERSION_T3
@@ -921,7 +979,7 @@ static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
 /*
  *     t3_load_fw - download firmware
  *     @adapter: the adapter
- *     @fw_data: the firrware image to write
+ *     @fw_data: the firmware image to write
  *     @size: image size
  *
  *     Write the supplied firmware image to the card's serial flash.
@@ -2362,7 +2420,7 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
                     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
        t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
                     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
-                    V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+                    V_TIMESTAMPSMODE(0) | V_SACKMODE(1) | V_SACKRX(1));
        t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
                     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
                     V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
@@ -2371,16 +2429,18 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
                         F_IPV6ENABLE | F_NICMODE);
        t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
        t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
-       t3_set_reg_field(adap, A_TP_PARA_REG6,
-                        adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
-                        0);
+       t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
+                        adap->params.rev > 0 ? F_ENABLEESND :
+                        F_T3A_ENABLEESND);
 
        t3_set_reg_field(adap, A_TP_PC_CONFIG,
-                        F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
-                        F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
-                        F_RXCONGESTIONMODE);
+                        F_ENABLEEPCMDAFULL,
+                        F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
+                        F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
        t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
-
+       t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
+       t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
+       
        if (adap->params.rev > 0) {
                tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
                t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
@@ -2390,9 +2450,10 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
        } else
                t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
 
-       t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
-       t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
-       t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+       t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
+       t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
+       t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
+       t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
 }
 
 /* Desired TP timer resolution in usec */
@@ -2468,6 +2529,7 @@ int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
                val |= F_RXCOALESCEENABLE;
                if (psh)
                        val |= F_RXCOALESCEPSHEN;
+               size = min(MAX_RX_COALESCING_LEN, size);
                t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
                             V_MAXRXDATA(MAX_RX_COALESCING_LEN));
        }
@@ -2496,11 +2558,11 @@ static void __devinit init_mtus(unsigned short mtus[])
         * it can accomodate max size TCP/IP headers when SACK and timestamps
         * are enabled and still have at least 8 bytes of payload.
         */
-       mtus[0] = 88;
-       mtus[1] = 256;
-       mtus[2] = 512;
-       mtus[3] = 576;
-       mtus[4] = 808;
+       mtus[1] = 88;
+       mtus[1] = 88;
+       mtus[2] = 256;
+       mtus[3] = 512;
+       mtus[4] = 576;
        mtus[5] = 1024;
        mtus[6] = 1280;
        mtus[7] = 1492;
@@ -2682,6 +2744,34 @@ static void ulp_config(struct adapter *adap, const struct tp_params *p)
        t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
 }
 
+/**
+ *     t3_set_proto_sram - set the contents of the protocol sram
+ *     @adapter: the adapter
+ *     @data: the protocol image
+ *
+ *     Write the contents of the protocol SRAM.
+ */
+int t3_set_proto_sram(struct adapter *adap, u8 *data)
+{
+       int i;
+       u32 *buf = (u32 *)data;
+
+       for (i = 0; i < PROTO_SRAM_LINES; i++) {
+               t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
+               t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
+               t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
+               t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
+               t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
+               
+               t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
+               if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
+                       return -EIO;
+       }
+       t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0);
+
+       return 0;
+}
+
 void t3_config_trace_filter(struct adapter *adapter,
                            const struct trace_params *tp, int filter_index,
                            int invert, int enable)
@@ -2802,7 +2892,7 @@ static void init_hw_for_avail_ports(struct adapter *adap, int nports)
                t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
                t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
                             F_PORT0ACTIVE | F_ENFORCEPKT);
-               t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+               t3_write_reg(adap, A_PM1_TX_CFG, 0xffffffff);
        } else {
                t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
                t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
@@ -3097,7 +3187,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
        else
                t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
 
-       t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+       t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
        init_hw_for_avail_ports(adapter, adapter->params.nports);
        t3_sge_init(adapter, &adapter->params.sge);
 
index b112317f033e1950d311490607e1cb7d16c43162..8eddd23a3a51c077cfd922870acc179d97e06c6a 100644 (file)
@@ -39,6 +39,6 @@
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 0
+#define FW_VERSION_MINOR 1
 #define FW_VERSION_MICRO 0
 #endif                         /* __CHELSIO_VERSION_H */
index c0f81b5a30fb4737b0b89839d9d3cb93ae62b591..abaf3ac949363bcbaad77af8d3caebf8ad384d74 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ehea"
-#define DRV_VERSION    "EHEA_0064"
+#define DRV_VERSION    "EHEA_0065"
 
 #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
        | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -136,10 +136,10 @@ void ehea_dump(void *adr, int len, char *msg);
        (0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
 
 #define EHEA_BMASK_SET(mask, value) \
-        ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
+       ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
 
 #define EHEA_BMASK_GET(mask, value) \
-        (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
+       (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
 
 /*
  * Generic ehea page
@@ -190,7 +190,7 @@ struct ehea_av;
  * Queue attributes passed to ehea_create_qp()
  */
 struct ehea_qp_init_attr {
-        /* input parameter */
+       /* input parameter */
        u32 qp_token;           /* queue token */
        u8 low_lat_rq1;
        u8 signalingtype;       /* cqe generation flag */
@@ -212,7 +212,7 @@ struct ehea_qp_init_attr {
        u64 recv_cq_handle;
        u64 aff_eq_handle;
 
-        /* output parameter */
+       /* output parameter */
        u32 qp_nr;
        u16 act_nr_send_wqes;
        u16 act_nr_rwqes_rq1;
@@ -279,12 +279,12 @@ struct ehea_qp {
  * Completion Queue attributes
  */
 struct ehea_cq_attr {
-        /* input parameter */
+       /* input parameter */
        u32 max_nr_of_cqes;
        u32 cq_token;
        u64 eq_handle;
 
-        /* output parameter */
+       /* output parameter */
        u32 act_nr_of_cqes;
        u32 nr_pages;
 };
index 1246757f2c22cd5a7807596f56e3aad9d306ad59..1af7ca499ec517232e7c83dc845f2f336c07430c 100644 (file)
@@ -211,34 +211,34 @@ static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
 }
 
 #define epa_store_eq(epa, offset, value)\
-        epa_store(epa, EQTEMM_OFFSET(offset), value)
+       epa_store(epa, EQTEMM_OFFSET(offset), value)
 #define epa_load_eq(epa, offset)\
-        epa_load(epa, EQTEMM_OFFSET(offset))
+       epa_load(epa, EQTEMM_OFFSET(offset))
 
 #define epa_store_cq(epa, offset, value)\
-        epa_store(epa, CQTEMM_OFFSET(offset), value)
+       epa_store(epa, CQTEMM_OFFSET(offset), value)
 #define epa_load_cq(epa, offset)\
-        epa_load(epa, CQTEMM_OFFSET(offset))
+       epa_load(epa, CQTEMM_OFFSET(offset))
 
 #define epa_store_qp(epa, offset, value)\
-        epa_store(epa, QPTEMM_OFFSET(offset), value)
+       epa_store(epa, QPTEMM_OFFSET(offset), value)
 #define epa_load_qp(epa, offset)\
-        epa_load(epa, QPTEMM_OFFSET(offset))
+       epa_load(epa, QPTEMM_OFFSET(offset))
 
 #define epa_store_qped(epa, offset, value)\
-        epa_store(epa, QPEDMM_OFFSET(offset), value)
+       epa_store(epa, QPEDMM_OFFSET(offset), value)
 #define epa_load_qped(epa, offset)\
-        epa_load(epa, QPEDMM_OFFSET(offset))
+       epa_load(epa, QPEDMM_OFFSET(offset))
 
 #define epa_store_mrmw(epa, offset, value)\
-        epa_store(epa, MRMWMM_OFFSET(offset), value)
+       epa_store(epa, MRMWMM_OFFSET(offset), value)
 #define epa_load_mrmw(epa, offset)\
-        epa_load(epa, MRMWMM_OFFSET(offset))
+       epa_load(epa, MRMWMM_OFFSET(offset))
 
 #define epa_store_base(epa, offset, value)\
-        epa_store(epa, HCAGR_OFFSET(offset), value)
+       epa_store(epa, HCAGR_OFFSET(offset), value)
 #define epa_load_base(epa, offset)\
-        epa_load(epa, HCAGR_OFFSET(offset))
+       epa_load(epa, HCAGR_OFFSET(offset))
 
 static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
 {
index 9e13433a268a7a40c360a17ed7904281a89e245b..bdb52419dbf5d8cc672ca30e597a5860a9d9cd69 100644 (file)
@@ -81,7 +81,7 @@ MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
 static int port_name_cnt = 0;
 
 static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
-                                        const struct of_device_id *id);
+                                       const struct of_device_id *id);
 
 static int __devexit ehea_remove(struct ibmebus_dev *dev);
 
@@ -236,7 +236,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
 
                rwqe = ehea_get_next_rwqe(qp, rq_nr);
                rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
-                           | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+                           | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
                rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
                rwqe->sg_list[0].vaddr = (u64)skb->data;
                rwqe->sg_list[0].len = packet_size;
@@ -427,7 +427,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
                                                break;
                                }
                                skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
-                                              cqe->num_bytes_transfered - 4);
+                                                cqe->num_bytes_transfered - 4);
                                ehea_fill_skb(port->netdev, skb, cqe);
                        } else if (rq == 2) {  /* RQ2 */
                                skb = get_skb_by_index(skb_arr_rq2,
@@ -618,7 +618,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
 
        for (i = 0; i < EHEA_MAX_PORTS; i++)
                if (adapter->port[i])
-                       if (adapter->port[i]->logical_port_id == logical_port)
+                       if (adapter->port[i]->logical_port_id == logical_port)
                                return adapter->port[i];
        return NULL;
 }
@@ -1695,6 +1695,7 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
 {
        if (skb->protocol == htons(ETH_P_IP)) {
                const struct iphdr *iph = ip_hdr(skb);
+
                /* IPv4 */
                swqe->tx_control |= EHEA_SWQE_CRC
                                 | EHEA_SWQE_IP_CHECKSUM
@@ -1705,13 +1706,12 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
                write_ip_start_end(swqe, skb);
 
                if (iph->protocol == IPPROTO_UDP) {
-                       if ((iph->frag_off & IP_MF) ||
-                           (iph->frag_off & IP_OFFSET))
+                       if ((iph->frag_off & IP_MF)
+                           || (iph->frag_off & IP_OFFSET))
                                /* IP fragment, so don't change cs */
                                swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
                        else
                                write_udp_offset_end(swqe, skb);
-
                } else if (iph->protocol == IPPROTO_TCP) {
                        write_tcp_offset_end(swqe, skb);
                }
@@ -1739,6 +1739,7 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
 
        if (skb->protocol == htons(ETH_P_IP)) {
                const struct iphdr *iph = ip_hdr(skb);
+
                /* IPv4 */
                write_ip_start_end(swqe, skb);
 
@@ -1751,8 +1752,8 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
                        write_tcp_offset_end(swqe, skb);
 
                } else if (iph->protocol == IPPROTO_UDP) {
-                       if ((iph->frag_off & IP_MF) ||
-                           (iph->frag_off & IP_OFFSET))
+                       if ((iph->frag_off & IP_MF)
+                           || (iph->frag_off & IP_OFFSET))
                                /* IP fragment, so don't change cs */
                                swqe->tx_control |= EHEA_SWQE_CRC
                                                 | EHEA_SWQE_IMM_DATA_PRESENT;
@@ -2407,7 +2408,7 @@ static void __devinit logical_port_release(struct device *dev)
 }
 
 static int ehea_driver_sysfs_add(struct device *dev,
-                                 struct device_driver *driver)
+                                struct device_driver *driver)
 {
        int ret;
 
@@ -2424,7 +2425,7 @@ static int ehea_driver_sysfs_add(struct device *dev,
 }
 
 static void ehea_driver_sysfs_remove(struct device *dev,
-                                     struct device_driver *driver)
+                                    struct device_driver *driver)
 {
        struct device_driver *drv = driver;
 
@@ -2453,7 +2454,7 @@ static struct device *ehea_register_port(struct ehea_port *port,
        }
 
        ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
-        if (ret) {
+       if (ret) {
                ehea_error("failed to register attributes, ret=%d", ret);
                goto out_unreg_of_dev;
        }
@@ -2601,6 +2602,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
 {
        struct device_node *lhea_dn;
        struct device_node *eth_dn = NULL;
+
        const u32 *dn_log_port_id;
        int i = 0;
 
@@ -2608,7 +2610,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
        while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
 
                dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
-                                                   NULL);
+                                                NULL);
                if (!dn_log_port_id) {
                        ehea_error("bad device node: eth_dn name=%s",
                                   eth_dn->full_name);
@@ -2648,7 +2650,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
        while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
 
                dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
-                                                   NULL);
+                                                NULL);
                if (dn_log_port_id)
                        if (*dn_log_port_id == logical_port_id)
                                return eth_dn;
@@ -2789,7 +2791,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
        adapter->ebus_dev = dev;
 
        adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
-                                           NULL);
+                                        NULL);
        if (adapter_handle)
                adapter->handle = *adapter_handle;
 
index f24a8862977ddda82589dc17c75fb4232f204dec..29eaa46948b0e0c07cf72acba70ef0608cf97b2c 100644 (file)
@@ -211,7 +211,7 @@ u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
        u64 hret;
        u64 adapter_handle = cq->adapter->handle;
 
-        /* deregister all previous registered pages */
+       /* deregister all previous registered pages */
        hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
        if (hret != H_SUCCESS)
                return hret;
@@ -362,7 +362,7 @@ int ehea_destroy_eq(struct ehea_eq *eq)
        if (hret != H_SUCCESS) {
                ehea_error("destroy EQ failed");
                return -EIO;
-        }
+       }
 
        return 0;
 }
@@ -507,44 +507,44 @@ out_freemem:
 
 u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
 {
-        u64 hret;
-        struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+       u64 hret;
+       struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
 
 
-        ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
-        hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
-        if (hret != H_SUCCESS)
-                return hret;
+       ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
+       hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
+       if (hret != H_SUCCESS)
+               return hret;
 
-        hw_queue_dtor(&qp->hw_squeue);
-        hw_queue_dtor(&qp->hw_rqueue1);
+       hw_queue_dtor(&qp->hw_squeue);
+       hw_queue_dtor(&qp->hw_rqueue1);
 
-        if (qp_attr->rq_count > 1)
-                hw_queue_dtor(&qp->hw_rqueue2);
-        if (qp_attr->rq_count > 2)
-                hw_queue_dtor(&qp->hw_rqueue3);
-        kfree(qp);
+       if (qp_attr->rq_count > 1)
+               hw_queue_dtor(&qp->hw_rqueue2);
+       if (qp_attr->rq_count > 2)
+               hw_queue_dtor(&qp->hw_rqueue3);
+       kfree(qp);
 
-        return hret;
+       return hret;
 }
 
 int ehea_destroy_qp(struct ehea_qp *qp)
 {
-        u64 hret;
-        if (!qp)
-                return 0;
+       u64 hret;
+       if (!qp)
+               return 0;
 
-        if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
-                ehea_error_data(qp->adapter, qp->fw_handle);
-                hret = ehea_destroy_qp_res(qp, FORCE_FREE);
-        }
+       if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+               ehea_error_data(qp->adapter, qp->fw_handle);
+               hret = ehea_destroy_qp_res(qp, FORCE_FREE);
+       }
 
-        if (hret != H_SUCCESS) {
-                ehea_error("destroy QP failed");
-                return -EIO;
-        }
+       if (hret != H_SUCCESS) {
+               ehea_error("destroy QP failed");
+               return -EIO;
+       }
 
-        return 0;
+       return 0;
 }
 
 int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
index a84c232395e3fdf72dc63c070341ad756d2aaa39..afb34ded26ee271c22e29b5e40d735eb71883e80 100644 (file)
@@ -1,6 +1,6 @@
 config FEC_8XX
        tristate "Motorola 8xx FEC driver"
-       depends on NET_ETHERNET && 8xx
+       depends on 8XX
        select MII
 
 config FEC_8XX_GENERIC_PHY
index 6aaee67dd4b78037d428f8d456fa5ef594e6786f..e27ee210b605ff0fa41da3197ce84a62a628183e 100644 (file)
@@ -1,6 +1,6 @@
 config FS_ENET
        tristate "Freescale Ethernet Driver"
-       depends on NET_ETHERNET && (CPM1 || CPM2)
+       depends on CPM1 || CPM2
        select MII
 
 config FS_ENET_HAS_SCC
index 1b854bf07b09fec79f6abfa5b58f70b6ef91d1be..d7a1a58de7669b3bfefbf062ccb0fd8d98ec60b9 100644 (file)
@@ -130,6 +130,9 @@ static int gfar_remove(struct platform_device *pdev);
 static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
+static void gfar_configure_serdes(struct net_device *dev);
+extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
+extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
 #ifdef CONFIG_GFAR_NAPI
 static int gfar_poll(struct net_device *dev, int *budget);
 #endif
@@ -451,6 +454,9 @@ static int init_phy(struct net_device *dev)
 
        phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface);
 
+       if (interface == PHY_INTERFACE_MODE_SGMII)
+               gfar_configure_serdes(dev);
+
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
                return PTR_ERR(phydev);
@@ -465,6 +471,27 @@ static int init_phy(struct net_device *dev)
        return 0;
 }
 
+static void gfar_configure_serdes(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar_mii __iomem *regs =
+                       (void __iomem *)&priv->regs->gfar_mii_regs;
+
+       /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+
+       /* Single clk mode, mii mode off(for aerdes communication) */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
+
+       /* Supported pause and full-duplex, no half-duplex */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+                       ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
+                       ADVERTISE_1000XPSE_ASYM);
+
+       /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+                       BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
+}
+
 static void init_registers(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
index 39e9e321fcbc1d2c2e4c0bd9fd294a7bccfea33c..d8e779c102faf3becd6c281cab68cee44f8ea9b6 100644 (file)
@@ -136,6 +136,12 @@ extern const char gfar_driver_version[];
 #define MIIMCFG_RESET           0x80000000
 #define MIIMIND_BUSY            0x00000001
 
+/* TBI register addresses */
+#define MII_TBICON             0x11
+
+/* TBICON register bit fields */
+#define TBICON_CLK_SELECT      0x0020
+
 /* MAC register bits */
 #define MACCFG1_SOFT_RESET     0x80000000
 #define MACCFG1_RESET_RX_MC    0x00080000
index bcc6b82f4a33b6a9385ef66197a556fdf3b82149..5dd34a1a7b899217eaabdb8b4abdb8985695684c 100644 (file)
 #include "gianfar.h"
 #include "gianfar_mii.h"
 
-/* Write value to the PHY at mii_id at register regnum,
- * on the bus, waiting until the write is done before returning.
- * All PHY configuration is done through the TSEC1 MIIM regs */
-int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+/*
+ * Write value to the PHY at mii_id at register regnum,
+ * on the bus attached to the local interface, which may be different from the
+ * generic mdio bus (tied to a single interface), waiting until the write is
+ * done before returning. This is helpful in programming interfaces like
+ * the TBI which control interfaces like onchip SERDES and are always tied to
+ * the local mdio pins, which may not be the same as system mdio bus, used for
+ * controlling the external PHYs, for example.
+ */
+int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id,
+                         int regnum, u16 value)
 {
-       struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
-
        /* Set the PHY address and the register address we want to write */
        gfar_write(&regs->miimadd, (mii_id << 8) | regnum);
 
@@ -63,12 +68,19 @@ int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
        return 0;
 }
 
-/* Read the bus for PHY at addr mii_id, register regnum, and
- * return the value.  Clears miimcom first.  All PHY
- * configuration has to be done through the TSEC1 MIIM regs */
-int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+/*
+ * Read the bus for PHY at addr mii_id, register regnum, and
+ * return the value.  Clears miimcom first.  All PHY operation
+ * done on the bus attached to the local interface,
+ * which may be different from the generic mdio bus
+ * This is helpful in programming interfaces like
+ * the TBI which, inturn, control interfaces like onchip SERDES
+ * and are always tied to the local mdio pins, which may not be the
+ * same as system mdio bus, used for controlling the external PHYs, for eg.
+ */
+int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum)
+
 {
-       struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
        u16 value;
 
        /* Set the PHY address and the register address we want to read */
@@ -88,6 +100,27 @@ int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        return value;
 }
 
+/* Write value to the PHY at mii_id at register regnum,
+ * on the bus, waiting until the write is done before returning.
+ * All PHY configuration is done through the TSEC1 MIIM regs */
+int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+       struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
+
+       /* Write to the local MII regs */
+       return(gfar_local_mdio_write(regs, mii_id, regnum, value));
+}
+
+/* Read the bus for PHY at addr mii_id, register regnum, and
+ * return the value.  Clears miimcom first.  All PHY
+ * configuration has to be done through the TSEC1 MIIM regs */
+int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
+
+       /* Read the local MII regs */
+       return(gfar_local_mdio_read(regs, mii_id, regnum));
+}
 
 /* Reset the MIIM registers, and wait for the bus to free */
 int gfar_mdio_reset(struct mii_bus *bus)
index 741780e14b2cc64f026a56dfcaf7c6e4085529ba..efbae4b8398e5b6cbdf8da59db85f83e18fd7212 100644 (file)
 #include <linux/dma-mapping.h>
 
 #include <asm/io.h>
-#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/pdc.h>
-#include <asm/cache.h>
 #include <asm/parisc-device.h>
 
 #define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
 
-/* DEBUG flags
- */
-
-#define DEB_INIT       0x0001
-#define DEB_PROBE      0x0002
-#define DEB_SERIOUS    0x0004
-#define DEB_ERRORS     0x0008
-#define DEB_MULTI      0x0010
-#define DEB_TDR                0x0020
-#define DEB_OPEN       0x0040
-#define DEB_RESET      0x0080
-#define DEB_ADDCMD     0x0100
-#define DEB_STATUS     0x0200
-#define DEB_STARTTX    0x0400
-#define DEB_RXADDR     0x0800
-#define DEB_TXADDR     0x1000
-#define DEB_RXFRAME    0x2000
-#define DEB_INTS       0x4000
-#define DEB_STRUCT     0x8000
-#define DEB_ANY                0xffff
-
-
-#define DEB(x,y)       if (i596_debug & (x)) { y; }
-
-
-#define  CHECK_WBACK(priv, addr,len) \
-       do { dma_cache_sync((priv)->dev, (void *)addr, len, DMA_TO_DEVICE); } while (0)
-
-#define  CHECK_INV(priv, addr,len) \
-       do { dma_cache_sync((priv)->dev, (void *)addr, len, DMA_FROM_DEVICE); } while(0)
-
-#define  CHECK_WBACK_INV(priv, addr,len) \
-       do { dma_cache_sync((priv)->dev, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
-
-
 #define PA_I82596_RESET                0       /* Offsets relative to LASI-LAN-Addr.*/
 #define PA_CPU_PORT_L_ACCESS   4
 #define PA_CHANNEL_ATTENTION   8
 
+#define OPT_SWAP_PORT  0x0001  /* Need to wordswp on the MPU port */
 
-/*
- * Define various macros for Channel Attention, word swapping etc., dependent
- * on architecture.  MVME and BVME are 680x0 based, otherwise it is Intel.
- */
+#define DMA_ALLOC                        dma_alloc_noncoherent
+#define DMA_FREE                         dma_free_noncoherent
+#define DMA_WBACK(ndev, addr, len) \
+       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
 
-#ifdef __BIG_ENDIAN
-#define WSWAPrfd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPrbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPiscp(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPscb(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPcmd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPtbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPchar(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define ISCP_BUSY      0x00010000
-#define MACH_IS_APRICOT        0
-#else
-#define WSWAPrfd(x)     ((struct i596_rfd *)(x))
-#define WSWAPrbd(x)     ((struct i596_rbd *)(x))
-#define WSWAPiscp(x)    ((struct i596_iscp *)(x))
-#define WSWAPscb(x)     ((struct i596_scb *)(x))
-#define WSWAPcmd(x)     ((struct i596_cmd *)(x))
-#define WSWAPtbd(x)     ((struct i596_tbd *)(x))
-#define WSWAPchar(x)    ((char *)(x))
-#define ISCP_BUSY      0x0001
-#define MACH_IS_APRICOT        1
-#endif
+#define DMA_INV(ndev, addr, len) \
+       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
 
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- * This only applies to VME boards.
- */
-#define PORT_RESET             0x00    /* reset 82596 */
-#define PORT_SELFTEST          0x01    /* selftest */
-#define PORT_ALTSCP            0x02    /* alternate SCB address */
-#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
+#define DMA_WBACK_INV(ndev, addr, len) \
+       do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
+
+#define SYSBUS      0x0000006c;
+
+/* big endian CPU, 82596 "big" endian mode */
+#define SWAP32(x)   (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define SWAP16(x)   (x)
 
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+#include "lib82596.c"
 
 MODULE_AUTHOR("Richard Hirst");
 MODULE_DESCRIPTION("i82596 driver");
@@ -180,255 +123,15 @@ MODULE_LICENSE("GPL");
 module_param(i596_debug, int, 0);
 MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
 
-/* Copy frames shorter than rx_copybreak, otherwise pass on up in
- * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
- */
-static int rx_copybreak = 100;
-
-#define MAX_DRIVERS    4       /* max count of drivers */
-
-#define PKT_BUF_SZ     1536
-#define MAX_MC_CNT     64
-
-#define I596_NULL ((u32)0xffffffff)
-
-#define CMD_EOL                0x8000  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
-
-#define CMD_FLEX       0x0008  /* Enable flexible memory model */
-
-enum commands {
-       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
-};
-
-#define STAT_C         0x8000  /* Set to 0 after execution */
-#define STAT_B         0x4000  /* Command being executed */
-#define STAT_OK                0x2000  /* Command executed ok */
-#define STAT_A         0x1000  /* Command aborted */
-
-#define         CUC_START      0x0100
-#define         CUC_RESUME     0x0200
-#define         CUC_SUSPEND    0x0300
-#define         CUC_ABORT      0x0400
-#define         RX_START       0x0010
-#define         RX_RESUME      0x0020
-#define         RX_SUSPEND     0x0030
-#define         RX_ABORT       0x0040
-
-#define TX_TIMEOUT     5
-
-#define OPT_SWAP_PORT  0x0001  /* Need to wordswp on the MPU port */
-
-
-struct i596_reg {
-       unsigned short porthi;
-       unsigned short portlo;
-       u32            ca;
-};
-
-#define EOF            0x8000
-#define SIZE_MASK      0x3fff
-
-struct i596_tbd {
-       unsigned short size;
-       unsigned short pad;
-       dma_addr_t     next;
-       dma_addr_t     data;
-       u32 cache_pad[5];               /* Total 32 bytes... */
-};
-
-/* The command structure has two 'next' pointers; v_next is the address of
- * the next command as seen by the CPU, b_next is the address of the next
- * command as seen by the 82596.  The b_next pointer, as used by the 82596
- * always references the status field of the next command, rather than the
- * v_next field, because the 82596 is unaware of v_next.  It may seem more
- * logical to put v_next at the end of the structure, but we cannot do that
- * because the 82596 expects other fields to be there, depending on command
- * type.
- */
-
-struct i596_cmd {
-       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
-       unsigned short status;
-       unsigned short command;
-       dma_addr_t     b_next;  /* Address from i596 viewpoint */
-};
-
-struct tx_cmd {
-       struct i596_cmd cmd;
-       dma_addr_t     tbd;
-       unsigned short size;
-       unsigned short pad;
-       struct sk_buff *skb;            /* So we can free it after tx */
-       dma_addr_t dma_addr;
-#ifdef __LP64__
-       u32 cache_pad[6];               /* Total 64 bytes... */
-#else
-       u32 cache_pad[1];               /* Total 32 bytes... */
-#endif
-};
-
-struct tdr_cmd {
-       struct i596_cmd cmd;
-       unsigned short status;
-       unsigned short pad;
-};
-
-struct mc_cmd {
-       struct i596_cmd cmd;
-       short mc_cnt;
-       char mc_addrs[MAX_MC_CNT*6];
-};
-
-struct sa_cmd {
-       struct i596_cmd cmd;
-       char eth_addr[8];
-};
-
-struct cf_cmd {
-       struct i596_cmd cmd;
-       char i596_config[16];
-};
-
-struct i596_rfd {
-       unsigned short stat;
-       unsigned short cmd;
-       dma_addr_t     b_next;  /* Address from i596 viewpoint */
-       dma_addr_t     rbd;
-       unsigned short count;
-       unsigned short size;
-       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
-       struct i596_rfd *v_prev;
-#ifndef __LP64__
-       u32 cache_pad[2];               /* Total 32 bytes... */
-#endif
-};
-
-struct i596_rbd {
-    /* hardware data */
-    unsigned short count;
-    unsigned short zero1;
-    dma_addr_t     b_next;
-    dma_addr_t     b_data;             /* Address from i596 viewpoint */
-    unsigned short size;
-    unsigned short zero2;
-    /* driver data */
-    struct sk_buff *skb;
-    struct i596_rbd *v_next;
-    dma_addr_t     b_addr;             /* This rbd addr from i596 view */
-    unsigned char *v_data;             /* Address from CPUs viewpoint */
-                                       /* Total 32 bytes... */
-#ifdef __LP64__
-    u32 cache_pad[4];
-#endif
-};
-
-/* These values as chosen so struct i596_private fits in one page... */
-
-#define TX_RING_SIZE 32
-#define RX_RING_SIZE 16
-
-struct i596_scb {
-       unsigned short status;
-       unsigned short command;
-       dma_addr_t    cmd;
-       dma_addr_t    rfd;
-       u32           crc_err;
-       u32           align_err;
-       u32           resource_err;
-       u32           over_err;
-       u32           rcvdt_err;
-       u32           short_err;
-       unsigned short t_on;
-       unsigned short t_off;
-};
-
-struct i596_iscp {
-       u32           stat;
-       dma_addr_t    scb;
-};
-
-struct i596_scp {
-       u32           sysbus;
-       u32            pad;
-       dma_addr_t    iscp;
-};
-
-struct i596_private {
-       volatile struct i596_scp scp            __attribute__((aligned(32)));
-       volatile struct i596_iscp iscp          __attribute__((aligned(32)));
-       volatile struct i596_scb scb            __attribute__((aligned(32)));
-       struct sa_cmd sa_cmd                    __attribute__((aligned(32)));
-       struct cf_cmd cf_cmd                    __attribute__((aligned(32)));
-       struct tdr_cmd tdr_cmd                  __attribute__((aligned(32)));
-       struct mc_cmd mc_cmd                    __attribute__((aligned(32)));
-       struct i596_rfd rfds[RX_RING_SIZE]      __attribute__((aligned(32)));
-       struct i596_rbd rbds[RX_RING_SIZE]      __attribute__((aligned(32)));
-       struct tx_cmd tx_cmds[TX_RING_SIZE]     __attribute__((aligned(32)));
-       struct i596_tbd tbds[TX_RING_SIZE]      __attribute__((aligned(32)));
-       u32    stat;
-       int last_restart;
-       struct i596_rfd *rfd_head;
-       struct i596_rbd *rbd_head;
-       struct i596_cmd *cmd_tail;
-       struct i596_cmd *cmd_head;
-       int cmd_backlog;
-       u32    last_cmd;
-       struct net_device_stats stats;
-       int next_tx_cmd;
-       int options;
-       spinlock_t lock;
-       dma_addr_t dma_addr;
-       struct device *dev;
-};
-
-static const char init_setup[] =
-{
-       0x8E,                   /* length, prefetch on */
-       0xC8,                   /* fifo to 8, monitor off */
-       0x80,                   /* don't save bad frames */
-       0x2E,                   /* No source address insertion, 8 byte preamble */
-       0x00,                   /* priority and backoff defaults */
-       0x60,                   /* interframe spacing */
-       0x00,                   /* slot time LSB */
-       0xf2,                   /* slot time and retries */
-       0x00,                   /* promiscuous mode */
-       0x00,                   /* collision detect */
-       0x40,                   /* minimum frame length */
-       0xff,
-       0x00,
-       0x7f /*  *multi IA */ };
-
-static int i596_open(struct net_device *dev);
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(unsigned char *buf, char *str);
-static void set_multicast_list(struct net_device *dev);
-
-static int rx_ring_size = RX_RING_SIZE;
-static int ticks_limit = 100;
-static int max_cmd_backlog = TX_RING_SIZE-1;
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev);
-#endif
-
-
-static inline void CA(struct net_device *dev)
+static inline void ca(struct net_device *dev)
 {
        gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
 }
 
 
-static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
 {
-       struct i596_private *lp = dev->priv;
+       struct i596_private *lp = netdev_priv(dev);
 
        u32 v = (u32) (c) | (u32) (x);
        u16 a, b;
@@ -446,1078 +149,15 @@ static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
        gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 }
 
-
-static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
-       CHECK_INV(lp, &(lp->iscp), sizeof(struct i596_iscp));
-       while (--delcnt && lp->iscp.stat) {
-               udelay(10);
-               CHECK_INV(lp, &(lp->iscp), sizeof(struct i596_iscp));
-       }
-       if (!delcnt) {
-               printk("%s: %s, iscp.stat %04x, didn't clear\n",
-                    dev->name, str, lp->iscp.stat);
-               return -1;
-       }
-       else
-               return 0;
-}
-
-
-static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
-       CHECK_INV(lp, &(lp->scb), sizeof(struct i596_scb));
-       while (--delcnt && lp->scb.command) {
-               udelay(10);
-               CHECK_INV(lp, &(lp->scb), sizeof(struct i596_scb));
-       }
-       if (!delcnt) {
-               printk("%s: %s, status %4.4x, cmd %4.4x.\n",
-                    dev->name, str, lp->scb.status, lp->scb.command);
-               return -1;
-       }
-       else
-               return 0;
-}
-
-
-static void i596_display_data(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       struct i596_cmd *cmd;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-
-       printk("lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
-              &lp->scp, lp->scp.sysbus, lp->scp.iscp);
-       printk("iscp at %p, iscp.stat = %08x, .scb = %08x\n",
-              &lp->iscp, lp->iscp.stat, lp->iscp.scb);
-       printk("scb at %p, scb.status = %04x, .command = %04x,"
-               " .cmd = %08x, .rfd = %08x\n",
-              &lp->scb, lp->scb.status, lp->scb.command,
-               lp->scb.cmd, lp->scb.rfd);
-       printk("   errors: crc %x, align %x, resource %x,"
-               " over %x, rcvdt %x, short %x\n",
-               lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
-               lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
-       cmd = lp->cmd_head;
-       while (cmd != NULL) {
-               printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %08x\n",
-                 cmd, cmd->status, cmd->command, cmd->b_next);
-               cmd = cmd->v_next;
-       }
-       rfd = lp->rfd_head;
-       printk("rfd_head = %p\n", rfd);
-       do {
-               printk("   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
-                        " count %04x\n",
-                       rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
-                       rfd->count);
-               rfd = rfd->v_next;
-       } while (rfd != lp->rfd_head);
-       rbd = lp->rbd_head;
-       printk("rbd_head = %p\n", rbd);
-       do {
-               printk("   %p .count %04x, b_next %08x, b_data %08x, size %04x\n",
-                       rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
-               rbd = rbd->v_next;
-       } while (rbd != lp->rbd_head);
-       CHECK_INV(lp, lp, sizeof(struct i596_private));
-}
-
-
-#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-static void i596_error(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
-       pcc2[0x28] = 1;
-       pcc2[0x2b] = 0x1d;
-       printk("%s: Error interrupt\n", dev->name);
-       i596_display_data(dev);
-}
-#endif
-
-#define virt_to_dma(lp,v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)(lp)))
-
-static inline void init_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       int i;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-
-       /* First build the Receive Buffer Descriptor List */
-
-       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
-               dma_addr_t dma_addr;
-               struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ + 4);
-
-               if (skb == NULL)
-                       panic("%s: alloc_skb() failed", __FILE__);
-               skb_reserve(skb, 2);
-               dma_addr = dma_map_single(lp->dev, skb->data,PKT_BUF_SZ,
-                                         DMA_FROM_DEVICE);
-               skb->dev = dev;
-               rbd->v_next = rbd+1;
-               rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1));
-               rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd));
-               rbd->skb = skb;
-               rbd->v_data = skb->data;
-               rbd->b_data = WSWAPchar(dma_addr);
-               rbd->size = PKT_BUF_SZ;
-       }
-       lp->rbd_head = lp->rbds;
-       rbd = lp->rbds + rx_ring_size - 1;
-       rbd->v_next = lp->rbds;
-       rbd->b_next = WSWAPrbd(virt_to_dma(lp,lp->rbds));
-
-       /* Now build the Receive Frame Descriptor List */
-
-       for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
-               rfd->rbd = I596_NULL;
-               rfd->v_next = rfd+1;
-               rfd->v_prev = rfd-1;
-               rfd->b_next = WSWAPrfd(virt_to_dma(lp,rfd+1));
-               rfd->cmd = CMD_FLEX;
-       }
-       lp->rfd_head = lp->rfds;
-       lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
-       rfd = lp->rfds;
-       rfd->rbd = WSWAPrbd(virt_to_dma(lp,lp->rbd_head));
-       rfd->v_prev = lp->rfds + rx_ring_size - 1;
-       rfd = lp->rfds + rx_ring_size - 1;
-       rfd->v_next = lp->rfds;
-       rfd->b_next = WSWAPrfd(virt_to_dma(lp,lp->rfds));
-       rfd->cmd = CMD_EOL|CMD_FLEX;
-
-       CHECK_WBACK_INV(lp, lp, sizeof(struct i596_private));
-}
-
-static inline void remove_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       struct i596_rbd *rbd;
-       int i;
-
-       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
-               if (rbd->skb == NULL)
-                       break;
-               dma_unmap_single(lp->dev,
-                                (dma_addr_t)WSWAPchar(rbd->b_data),
-                                PKT_BUF_SZ, DMA_FROM_DEVICE);
-               dev_kfree_skb(rbd->skb);
-       }
-}
-
-
-static void rebuild_rx_bufs(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       int i;
-
-       /* Ensure rx frame/buffer descriptors are tidy */
-
-       for (i = 0; i < rx_ring_size; i++) {
-               lp->rfds[i].rbd = I596_NULL;
-               lp->rfds[i].cmd = CMD_FLEX;
-       }
-       lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
-       lp->rfd_head = lp->rfds;
-       lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
-       lp->rbd_head = lp->rbds;
-       lp->rfds[0].rbd = WSWAPrbd(virt_to_dma(lp,lp->rbds));
-
-       CHECK_WBACK_INV(lp, lp, sizeof(struct i596_private));
-}
-
-
-static int init_i596_mem(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       unsigned long flags;
-
-       disable_irq(dev->irq);  /* disable IRQs from LAN */
-       DEB(DEB_INIT,
-               printk("RESET 82596 port: %lx (with IRQ %d disabled)\n",
-                      (dev->base_addr + PA_I82596_RESET),
-                      dev->irq));
-
-       gsc_writel(0, (dev->base_addr + PA_I82596_RESET)); /* Hard Reset */
-       udelay(100);                    /* Wait 100us - seems to help */
-
-       /* change the scp address */
-
-       lp->last_cmd = jiffies;
-
-
-       lp->scp.sysbus = 0x0000006c;
-       lp->scp.iscp = WSWAPiscp(virt_to_dma(lp,&(lp->iscp)));
-       lp->iscp.scb = WSWAPscb(virt_to_dma(lp,&(lp->scb)));
-       lp->iscp.stat = ISCP_BUSY;
-       lp->cmd_backlog = 0;
-
-       lp->cmd_head = NULL;
-        lp->scb.cmd = I596_NULL;
-
-       DEB(DEB_INIT, printk("%s: starting i82596.\n", dev->name));
-
-       CHECK_WBACK(lp, &(lp->scp), sizeof(struct i596_scp));
-       CHECK_WBACK(lp, &(lp->iscp), sizeof(struct i596_iscp));
-
-       MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));
-
-       CA(dev);
-
-       if (wait_istat(dev, lp, 1000, "initialization timed out"))
-               goto failed;
-       DEB(DEB_INIT, printk("%s: i82596 initialization successful\n", dev->name));
-
-       /* Ensure rx frame/buffer descriptors are tidy */
-       rebuild_rx_bufs(dev);
-
-       lp->scb.command = 0;
-       CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-
-       enable_irq(dev->irq);   /* enable IRQs from LAN */
-
-       DEB(DEB_INIT, printk("%s: queuing CmdConfigure\n", dev->name));
-       memcpy(lp->cf_cmd.i596_config, init_setup, sizeof(init_setup));
-       lp->cf_cmd.cmd.command = CmdConfigure;
-       CHECK_WBACK(lp, &(lp->cf_cmd), sizeof(struct cf_cmd));
-       i596_add_cmd(dev, &lp->cf_cmd.cmd);
-
-       DEB(DEB_INIT, printk("%s: queuing CmdSASetup\n", dev->name));
-       memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
-       lp->sa_cmd.cmd.command = CmdSASetup;
-       CHECK_WBACK(lp, &(lp->sa_cmd), sizeof(struct sa_cmd));
-       i596_add_cmd(dev, &lp->sa_cmd.cmd);
-
-       DEB(DEB_INIT, printk("%s: queuing CmdTDR\n", dev->name));
-       lp->tdr_cmd.cmd.command = CmdTDR;
-       CHECK_WBACK(lp, &(lp->tdr_cmd), sizeof(struct tdr_cmd));
-       i596_add_cmd(dev, &lp->tdr_cmd.cmd);
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       if (wait_cmd(dev, lp, 1000, "timed out waiting to issue RX_START")) {
-               spin_unlock_irqrestore (&lp->lock, flags);
-               goto failed;
-       }
-       DEB(DEB_INIT, printk("%s: Issuing RX_START\n", dev->name));
-       lp->scb.command = RX_START;
-       lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
-       CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-
-       CA(dev);
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       if (wait_cmd(dev, lp, 1000, "RX_START not processed"))
-               goto failed;
-       DEB(DEB_INIT, printk("%s: Receive unit started OK\n", dev->name));
-
-       return 0;
-
-failed:
-       printk("%s: Failed to initialise 82596\n", dev->name);
-       MPU_PORT(dev, PORT_RESET, 0);
-       return -1;
-}
-
-
-static inline int i596_rx(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       struct i596_rfd *rfd;
-       struct i596_rbd *rbd;
-       int frames = 0;
-
-       DEB(DEB_RXFRAME, printk("i596_rx(), rfd_head %p, rbd_head %p\n",
-                       lp->rfd_head, lp->rbd_head));
-
-
-       rfd = lp->rfd_head;             /* Ref next frame to check */
-
-       CHECK_INV(lp, rfd, sizeof(struct i596_rfd));
-       while ((rfd->stat) & STAT_C) {  /* Loop while complete frames */
-               if (rfd->rbd == I596_NULL)
-                       rbd = NULL;
-               else if (rfd->rbd == lp->rbd_head->b_addr) {
-                       rbd = lp->rbd_head;
-                       CHECK_INV(lp, rbd, sizeof(struct i596_rbd));
-               }
-               else {
-                       printk("%s: rbd chain broken!\n", dev->name);
-                       /* XXX Now what? */
-                       rbd = NULL;
-               }
-               DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
-                       rfd, rfd->rbd, rfd->stat));
-
-               if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
-                       /* a good frame */
-                       int pkt_len = rbd->count & 0x3fff;
-                       struct sk_buff *skb = rbd->skb;
-                       int rx_in_place = 0;
-
-                       DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
-                       frames++;
-
-                       /* Check if the packet is long enough to just accept
-                        * without copying to a properly sized skbuff.
-                        */
-
-                       if (pkt_len > rx_copybreak) {
-                               struct sk_buff *newskb;
-                               dma_addr_t dma_addr;
-
-                               dma_unmap_single(lp->dev,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
-                               /* Get fresh skbuff to replace filled one. */
-                               newskb = dev_alloc_skb(PKT_BUF_SZ + 4);
-                               if (newskb == NULL) {
-                                       skb = NULL;     /* drop pkt */
-                                       goto memory_squeeze;
-                               }
-                               skb_reserve(newskb, 2);
-
-                               /* Pass up the skb already on the Rx ring. */
-                               skb_put(skb, pkt_len);
-                               rx_in_place = 1;
-                               rbd->skb = newskb;
-                               newskb->dev = dev;
-                               dma_addr = dma_map_single(lp->dev, newskb->data, PKT_BUF_SZ, DMA_FROM_DEVICE);
-                               rbd->v_data = newskb->data;
-                               rbd->b_data = WSWAPchar(dma_addr);
-                               CHECK_WBACK_INV(lp, rbd, sizeof(struct i596_rbd));
-                       }
-                       else
-                               skb = dev_alloc_skb(pkt_len + 2);
-memory_squeeze:
-                       if (skb == NULL) {
-                               /* XXX tulip.c can defer packets here!! */
-                               printk("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
-                               lp->stats.rx_dropped++;
-                       }
-                       else {
-                               if (!rx_in_place) {
-                                       /* 16 byte align the data fields */
-                                       dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
-                                       skb_reserve(skb, 2);
-                                       memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
-                                       dma_sync_single_for_device(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
-                               }
-                               skb->len = pkt_len;
-                               skb->protocol=eth_type_trans(skb,dev);
-                               netif_rx(skb);
-                               dev->last_rx = jiffies;
-                               lp->stats.rx_packets++;
-                               lp->stats.rx_bytes+=pkt_len;
-                       }
-               }
-               else {
-                       DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n",
-                                       dev->name, rfd->stat));
-                       lp->stats.rx_errors++;
-                       if ((rfd->stat) & 0x0001)
-                               lp->stats.collisions++;
-                       if ((rfd->stat) & 0x0080)
-                               lp->stats.rx_length_errors++;
-                       if ((rfd->stat) & 0x0100)
-                               lp->stats.rx_over_errors++;
-                       if ((rfd->stat) & 0x0200)
-                               lp->stats.rx_fifo_errors++;
-                       if ((rfd->stat) & 0x0400)
-                               lp->stats.rx_frame_errors++;
-                       if ((rfd->stat) & 0x0800)
-                               lp->stats.rx_crc_errors++;
-                       if ((rfd->stat) & 0x1000)
-                               lp->stats.rx_length_errors++;
-               }
-
-               /* Clear the buffer descriptor count and EOF + F flags */
-
-               if (rbd != NULL && (rbd->count & 0x4000)) {
-                       rbd->count = 0;
-                       lp->rbd_head = rbd->v_next;
-                       CHECK_WBACK_INV(lp, rbd, sizeof(struct i596_rbd));
-               }
-
-               /* Tidy the frame descriptor, marking it as end of list */
-
-               rfd->rbd = I596_NULL;
-               rfd->stat = 0;
-               rfd->cmd = CMD_EOL|CMD_FLEX;
-               rfd->count = 0;
-
-               /* Remove end-of-list from old end descriptor */
-
-               rfd->v_prev->cmd = CMD_FLEX;
-
-               /* Update record of next frame descriptor to process */
-
-               lp->scb.rfd = rfd->b_next;
-               lp->rfd_head = rfd->v_next;
-               CHECK_WBACK_INV(lp, rfd->v_prev, sizeof(struct i596_rfd));
-               CHECK_WBACK_INV(lp, rfd, sizeof(struct i596_rfd));
-               rfd = lp->rfd_head;
-               CHECK_INV(lp, rfd, sizeof(struct i596_rfd));
-       }
-
-       DEB(DEB_RXFRAME, printk("frames %d\n", frames));
-
-       return 0;
-}
-
-
-static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
-{
-       struct i596_cmd *ptr;
-
-       while (lp->cmd_head != NULL) {
-               ptr = lp->cmd_head;
-               lp->cmd_head = ptr->v_next;
-               lp->cmd_backlog--;
-
-               switch ((ptr->command) & 0x7) {
-               case CmdTx:
-                       {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-                               struct sk_buff *skb = tx_cmd->skb;
-                               dma_unmap_single(lp->dev, tx_cmd->dma_addr, skb->len, DMA_TO_DEVICE);
-
-                               dev_kfree_skb(skb);
-
-                               lp->stats.tx_errors++;
-                               lp->stats.tx_aborted_errors++;
-
-                               ptr->v_next = NULL;
-                               ptr->b_next = I596_NULL;
-                               tx_cmd->cmd.command = 0;  /* Mark as free */
-                               break;
-                       }
-               default:
-                       ptr->v_next = NULL;
-                       ptr->b_next = I596_NULL;
-               }
-               CHECK_WBACK_INV(lp, ptr, sizeof(struct i596_cmd));
-       }
-
-       wait_cmd(dev, lp, 100, "i596_cleanup_cmd timed out");
-       lp->scb.cmd = I596_NULL;
-       CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-}
-
-
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
-{
-       unsigned long flags;
-
-       DEB(DEB_RESET, printk("i596_reset\n"));
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       wait_cmd(dev, lp, 100, "i596_reset timed out");
-
-       netif_stop_queue(dev);
-
-       /* FIXME: this command might cause an lpmc */
-       lp->scb.command = CUC_ABORT | RX_ABORT;
-       CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-       CA(dev);
-
-       /* wait for shutdown */
-       wait_cmd(dev, lp, 1000, "i596_reset 2 timed out");
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       i596_cleanup_cmd(dev,lp);
-       i596_rx(dev);
-
-       netif_start_queue(dev);
-       init_i596_mem(dev);
-}
-
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
-{
-       struct i596_private *lp = dev->priv;
-       unsigned long flags;
-
-       DEB(DEB_ADDCMD, printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
-
-       cmd->status = 0;
-       cmd->command |= (CMD_EOL | CMD_INTR);
-       cmd->v_next = NULL;
-       cmd->b_next = I596_NULL;
-       CHECK_WBACK(lp, cmd, sizeof(struct i596_cmd));
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       if (lp->cmd_head != NULL) {
-               lp->cmd_tail->v_next = cmd;
-               lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status));
-               CHECK_WBACK(lp, lp->cmd_tail, sizeof(struct i596_cmd));
-       } else {
-               lp->cmd_head = cmd;
-               wait_cmd(dev, lp, 100, "i596_add_cmd timed out");
-               lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&cmd->status));
-               lp->scb.command = CUC_START;
-               CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-               CA(dev);
-       }
-       lp->cmd_tail = cmd;
-       lp->cmd_backlog++;
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       if (lp->cmd_backlog > max_cmd_backlog) {
-               unsigned long tickssofar = jiffies - lp->last_cmd;
-
-               if (tickssofar < ticks_limit)
-                       return;
-
-               printk("%s: command unit timed out, status resetting.\n", dev->name);
-#if 1
-               i596_reset(dev, lp);
-#endif
-       }
-}
-
-#if 0
-/* this function makes a perfectly adequate probe...  but we have a
-   device list */
-static int i596_test(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       volatile int *tint;
-       u32 data;
-
-       tint = (volatile int *)(&(lp->scp));
-       data = virt_to_dma(lp,tint);
-
-       tint[1] = -1;
-       CHECK_WBACK(lp, tint, PAGE_SIZE);
-
-       MPU_PORT(dev, 1, data);
-
-       for(data = 1000000; data; data--) {
-               CHECK_INV(lp, tint, PAGE_SIZE);
-               if(tint[1] != -1)
-                       break;
-
-       }
-
-       printk("i596_test result %d\n", tint[1]);
-
-}
-#endif
-
-
-static int i596_open(struct net_device *dev)
-{
-       DEB(DEB_OPEN, printk("%s: i596_open() irq %d.\n", dev->name, dev->irq));
-
-       if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
-               printk("%s: IRQ %d not free\n", dev->name, dev->irq);
-               goto out;
-       }
-
-       init_rx_bufs(dev);
-
-       if (init_i596_mem(dev)) {
-               printk("%s: Failed to init memory\n", dev->name);
-               goto out_remove_rx_bufs;
-       }
-
-       netif_start_queue(dev);
-
-       return 0;
-
-out_remove_rx_bufs:
-       remove_rx_bufs(dev);
-       free_irq(dev->irq, dev);
-out:
-       return -EAGAIN;
-}
-
-static void i596_tx_timeout (struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-
-       /* Transmitter timeout, serious problems. */
-       DEB(DEB_ERRORS, printk("%s: transmit timed out, status resetting.\n",
-                       dev->name));
-
-       lp->stats.tx_errors++;
-
-       /* Try to restart the adaptor */
-       if (lp->last_restart == lp->stats.tx_packets) {
-               DEB(DEB_ERRORS, printk("Resetting board.\n"));
-               /* Shutdown and restart */
-               i596_reset (dev, lp);
-       } else {
-               /* Issue a channel attention signal */
-               DEB(DEB_ERRORS, printk("Kicking board.\n"));
-               lp->scb.command = CUC_START | RX_START;
-               CHECK_WBACK_INV(lp, &(lp->scb), sizeof(struct i596_scb));
-               CA (dev);
-               lp->last_restart = lp->stats.tx_packets;
-       }
-
-       dev->trans_start = jiffies;
-       netif_wake_queue (dev);
-}
-
-
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       struct tx_cmd *tx_cmd;
-       struct i596_tbd *tbd;
-       short length = skb->len;
-       dev->trans_start = jiffies;
-
-       DEB(DEB_STARTTX, printk("%s: i596_start_xmit(%x,%p) called\n", dev->name,
-                               skb->len, skb->data));
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
-               length = ETH_ZLEN;
-       }
-
-       netif_stop_queue(dev);
-
-       tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
-       tbd = lp->tbds + lp->next_tx_cmd;
-
-       if (tx_cmd->cmd.command) {
-               DEB(DEB_ERRORS, printk("%s: xmit ring full, dropping packet.\n",
-                               dev->name));
-               lp->stats.tx_dropped++;
-
-               dev_kfree_skb(skb);
-       } else {
-               if (++lp->next_tx_cmd == TX_RING_SIZE)
-                       lp->next_tx_cmd = 0;
-               tx_cmd->tbd = WSWAPtbd(virt_to_dma(lp,tbd));
-               tbd->next = I596_NULL;
-
-               tx_cmd->cmd.command = CMD_FLEX | CmdTx;
-               tx_cmd->skb = skb;
-
-               tx_cmd->pad = 0;
-               tx_cmd->size = 0;
-               tbd->pad = 0;
-               tbd->size = EOF | length;
-
-               tx_cmd->dma_addr = dma_map_single(lp->dev, skb->data, skb->len,
-                               DMA_TO_DEVICE);
-               tbd->data = WSWAPchar(tx_cmd->dma_addr);
-
-               DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
-               CHECK_WBACK_INV(lp, tx_cmd, sizeof(struct tx_cmd));
-               CHECK_WBACK_INV(lp, tbd, sizeof(struct i596_tbd));
-               i596_add_cmd(dev, &tx_cmd->cmd);
-
-               lp->stats.tx_packets++;
-               lp->stats.tx_bytes += length;
-       }
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-static void print_eth(unsigned char *add, char *str)
-{
-       int i;
-
-       printk("i596 0x%p, ", add);
-       for (i = 0; i < 6; i++)
-               printk(" %02X", add[i + 6]);
-       printk(" -->");
-       for (i = 0; i < 6; i++)
-               printk(" %02X", add[i]);
-       printk(" %02X%02X, %s\n", add[12], add[13], str);
-}
-
-
 #define LAN_PROM_ADDR  0xF0810000
 
-static int __devinit i82596_probe(struct net_device *dev,
-                                 struct device *gen_dev)
-{
-       int i;
-       struct i596_private *lp;
-       char eth_addr[6];
-       dma_addr_t dma_addr;
-
-       /* This lot is ensure things have been cache line aligned. */
-       BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
-       BUILD_BUG_ON(sizeof(struct i596_rbd) &  31);
-       BUILD_BUG_ON(sizeof(struct tx_cmd)   &  31);
-       BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
-#ifndef __LP64__
-       BUILD_BUG_ON(sizeof(struct i596_private) > 4096);
-#endif
-
-       if (!dev->base_addr || !dev->irq)
-               return -ENODEV;
-
-       if (pdc_lan_station_id(eth_addr, dev->base_addr)) {
-               for (i=0; i < 6; i++) {
-                       eth_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
-               }
-               printk(KERN_INFO "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
-       }
-
-       dev->mem_start = (unsigned long) dma_alloc_noncoherent(gen_dev,
-               sizeof(struct i596_private), &dma_addr, GFP_KERNEL);
-       if (!dev->mem_start) {
-               printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = eth_addr[i];
-
-       /* The 82596-specific entries in the device structure. */
-       dev->open = i596_open;
-       dev->stop = i596_close;
-       dev->hard_start_xmit = i596_start_xmit;
-       dev->get_stats = i596_get_stats;
-       dev->set_multicast_list = set_multicast_list;
-       dev->tx_timeout = i596_tx_timeout;
-       dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = i596_poll_controller;
-#endif
-
-       dev->priv = (void *)(dev->mem_start);
-
-       lp = dev->priv;
-       memset(lp, 0, sizeof(struct i596_private));
-
-       lp->scb.command = 0;
-       lp->scb.cmd = I596_NULL;
-       lp->scb.rfd = I596_NULL;
-       spin_lock_init(&lp->lock);
-       lp->dma_addr = dma_addr;
-       lp->dev = gen_dev;
-
-       CHECK_WBACK_INV(lp, dev->mem_start, sizeof(struct i596_private));
-
-       i = register_netdev(dev);
-       if (i) {
-               lp = dev->priv;
-               dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
-                                   (void *)dev->mem_start, lp->dma_addr);
-               return i;
-       };
-
-       DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
-       for (i = 0; i < 6; i++)
-               DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i]));
-       DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq));
-       DEB(DEB_INIT, printk(KERN_INFO "%s: lp at 0x%p (%d bytes), lp->scb at 0x%p\n",
-               dev->name, lp, (int)sizeof(struct i596_private), &lp->scb));
-
-       return 0;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       i596_interrupt(dev->irq, dev);
-       enable_irq(dev->irq);
-}
-#endif
-
-static irqreturn_t i596_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct i596_private *lp;
-       unsigned short status, ack_cmd = 0;
-
-       if (dev == NULL) {
-               printk("%s: irq %d for unknown device.\n", __FUNCTION__, irq);
-               return IRQ_NONE;
-       }
-
-       lp = dev->priv;
-
-       spin_lock (&lp->lock);
-
-       wait_cmd(dev, lp, 100, "i596 interrupt, timeout");
-       status = lp->scb.status;
-
-       DEB(DEB_INTS, printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",
-                       dev->name, irq, status));
-
-       ack_cmd = status & 0xf000;
-
-       if (!ack_cmd) {
-               DEB(DEB_ERRORS, printk("%s: interrupt with no events\n", dev->name));
-               spin_unlock (&lp->lock);
-               return IRQ_NONE;
-       }
-
-       if ((status & 0x8000) || (status & 0x2000)) {
-               struct i596_cmd *ptr;
-
-               if ((status & 0x8000))
-                       DEB(DEB_INTS, printk("%s: i596 interrupt completed command.\n", dev->name));
-               if ((status & 0x2000))
-                       DEB(DEB_INTS, printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
-
-               while (lp->cmd_head != NULL) {
-                       CHECK_INV(lp, lp->cmd_head, sizeof(struct i596_cmd));
-                       if (!(lp->cmd_head->status & STAT_C))
-                               break;
-
-                       ptr = lp->cmd_head;
-
-                       DEB(DEB_STATUS, printk("cmd_head->status = %04x, ->command = %04x\n",
-                                      lp->cmd_head->status, lp->cmd_head->command));
-                       lp->cmd_head = ptr->v_next;
-                       lp->cmd_backlog--;
-
-                       switch ((ptr->command) & 0x7) {
-                       case CmdTx:
-                           {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-                               struct sk_buff *skb = tx_cmd->skb;
-
-                               if ((ptr->status) & STAT_OK) {
-                                       DEB(DEB_TXADDR, print_eth(skb->data, "tx-done"));
-                               } else {
-                                       lp->stats.tx_errors++;
-                                       if ((ptr->status) & 0x0020)
-                                               lp->stats.collisions++;
-                                       if (!((ptr->status) & 0x0040))
-                                               lp->stats.tx_heartbeat_errors++;
-                                       if ((ptr->status) & 0x0400)
-                                               lp->stats.tx_carrier_errors++;
-                                       if ((ptr->status) & 0x0800)
-                                               lp->stats.collisions++;
-                                       if ((ptr->status) & 0x1000)
-                                               lp->stats.tx_aborted_errors++;
-                               }
-                               dma_unmap_single(lp->dev, tx_cmd->dma_addr, skb->len, DMA_TO_DEVICE);
-                               dev_kfree_skb_irq(skb);
-
-                               tx_cmd->cmd.command = 0; /* Mark free */
-                               break;
-                           }
-                       case CmdTDR:
-                           {
-                               unsigned short status = ((struct tdr_cmd *)ptr)->status;
-
-                               if (status & 0x8000) {
-                                       DEB(DEB_ANY, printk("%s: link ok.\n", dev->name));
-                               } else {
-                                       if (status & 0x4000)
-                                               printk("%s: Transceiver problem.\n", dev->name);
-                                       if (status & 0x2000)
-                                               printk("%s: Termination problem.\n", dev->name);
-                                       if (status & 0x1000)
-                                               printk("%s: Short circuit.\n", dev->name);
-
-                                       DEB(DEB_TDR, printk("%s: Time %d.\n", dev->name, status & 0x07ff));
-                               }
-                               break;
-                           }
-                       case CmdConfigure:
-                               /* Zap command so set_multicast_list() knows it is free */
-                               ptr->command = 0;
-                               break;
-                       }
-                       ptr->v_next = NULL;
-                       ptr->b_next = I596_NULL;
-                       CHECK_WBACK(lp, ptr, sizeof(struct i596_cmd));
-                       lp->last_cmd = jiffies;
-               }
-
-               /* This mess is arranging that only the last of any outstanding
-                * commands has the interrupt bit set.  Should probably really
-                * only add to the cmd queue when the CU is stopped.
-                */
-               ptr = lp->cmd_head;
-               while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
-                       struct i596_cmd *prev = ptr;
-
-                       ptr->command &= 0x1fff;
-                       ptr = ptr->v_next;
-                       CHECK_WBACK_INV(lp, prev, sizeof(struct i596_cmd));
-               }
-
-               if ((lp->cmd_head != NULL))
-                       ack_cmd |= CUC_START;
-               lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status));
-               CHECK_WBACK_INV(lp, &lp->scb, sizeof(struct i596_scb));
-       }
-       if ((status & 0x1000) || (status & 0x4000)) {
-               if ((status & 0x4000))
-                       DEB(DEB_INTS, printk("%s: i596 interrupt received a frame.\n", dev->name));
-               i596_rx(dev);
-               /* Only RX_START if stopped - RGH 07-07-96 */
-               if (status & 0x1000) {
-                       if (netif_running(dev)) {
-                               DEB(DEB_ERRORS, printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
-                               ack_cmd |= RX_START;
-                               lp->stats.rx_errors++;
-                               lp->stats.rx_fifo_errors++;
-                               rebuild_rx_bufs(dev);
-                       }
-               }
-       }
-       wait_cmd(dev, lp, 100, "i596 interrupt, timeout");
-       lp->scb.command = ack_cmd;
-       CHECK_WBACK(lp, &lp->scb, sizeof(struct i596_scb));
-
-       /* DANGER: I suspect that some kind of interrupt
-        acknowledgement aside from acking the 82596 might be needed
-        here...  but it's running acceptably without */
-
-       CA(dev);
-
-       wait_cmd(dev, lp, 100, "i596 interrupt, exit timeout");
-       DEB(DEB_INTS, printk("%s: exiting interrupt.\n", dev->name));
-
-       spin_unlock (&lp->lock);
-       return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       unsigned long flags;
-
-       netif_stop_queue(dev);
-
-       DEB(DEB_INIT, printk("%s: Shutting down ethercard, status was %4.4x.\n",
-                      dev->name, lp->scb.status));
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       wait_cmd(dev, lp, 100, "close1 timed out");
-       lp->scb.command = CUC_ABORT | RX_ABORT;
-       CHECK_WBACK(lp, &lp->scb, sizeof(struct i596_scb));
-
-       CA(dev);
-
-       wait_cmd(dev, lp, 100, "close2 timed out");
-       spin_unlock_irqrestore(&lp->lock, flags);
-       DEB(DEB_STRUCT,i596_display_data(dev));
-       i596_cleanup_cmd(dev,lp);
-
-       disable_irq(dev->irq);
-
-       free_irq(dev->irq, dev);
-       remove_rx_bufs(dev);
-
-       return 0;
-}
-
-static struct net_device_stats *
- i596_get_stats(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-
-       return &lp->stats;
-}
-
-/*
- *    Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       struct i596_private *lp = dev->priv;
-       int config = 0, cnt;
-
-       DEB(DEB_MULTI, printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
-               dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF",
-               dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
-
-       if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
-               lp->cf_cmd.i596_config[8] |= 0x01;
-               config = 1;
-       }
-       if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
-               lp->cf_cmd.i596_config[8] &= ~0x01;
-               config = 1;
-       }
-       if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
-               lp->cf_cmd.i596_config[11] &= ~0x20;
-               config = 1;
-       }
-       if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
-               lp->cf_cmd.i596_config[11] |= 0x20;
-               config = 1;
-       }
-       if (config) {
-               if (lp->cf_cmd.cmd.command)
-                       printk("%s: config change request already queued\n",
-                              dev->name);
-               else {
-                       lp->cf_cmd.cmd.command = CmdConfigure;
-                       CHECK_WBACK_INV(lp, &lp->cf_cmd, sizeof(struct cf_cmd));
-                       i596_add_cmd(dev, &lp->cf_cmd.cmd);
-               }
-       }
-
-       cnt = dev->mc_count;
-       if (cnt > MAX_MC_CNT)
-       {
-               cnt = MAX_MC_CNT;
-               printk("%s: Only %d multicast addresses supported",
-                       dev->name, cnt);
-       }
-
-       if (dev->mc_count > 0) {
-               struct dev_mc_list *dmi;
-               unsigned char *cp;
-               struct mc_cmd *cmd;
-
-               cmd = &lp->mc_cmd;
-               cmd->cmd.command = CmdMulticastList;
-               cmd->mc_cnt = dev->mc_count * 6;
-               cp = cmd->mc_addrs;
-               for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
-                       memcpy(cp, dmi->dmi_addr, 6);
-                       if (i596_debug > 1)
-                               DEB(DEB_MULTI, printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
-                                               dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
-               }
-               CHECK_WBACK_INV(lp, &lp->mc_cmd, sizeof(struct mc_cmd));
-               i596_add_cmd(dev, &cmd->cmd);
-       }
-}
-
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
-
-static int num_drivers;
-static struct net_device *netdevs[MAX_DRIVERS];
-
 static int __devinit
 lan_init_chip(struct parisc_device *dev)
 {
        struct  net_device *netdevice;
+       struct i596_private *lp;
        int     retval;
-
-       if (num_drivers >= MAX_DRIVERS) {
-               /* max count of possible i82596 drivers reached */
-               return -ENOMEM;
-       }
-
-       if (num_drivers == 0)
-               printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
+       int i;
 
        if (!dev->irq) {
                printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
@@ -1528,28 +168,45 @@ lan_init_chip(struct parisc_device *dev)
        printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa.start,
                        dev->irq);
 
-       netdevice = alloc_etherdev(0);
+       netdevice = alloc_etherdev(sizeof(struct i596_private));
        if (!netdevice)
                return -ENOMEM;
+       SET_NETDEV_DEV(netdevice, &dev->dev);
+       parisc_set_drvdata (dev, netdevice);
 
        netdevice->base_addr = dev->hpa.start;
        netdevice->irq = dev->irq;
 
-       retval = i82596_probe(netdevice, &dev->dev);
+       if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
+               for (i = 0; i < 6; i++) {
+                       netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+               }
+               printk(KERN_INFO
+                      "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
+       }
+
+       lp = netdev_priv(netdevice);
+       lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
+
+       retval = i82596_probe(netdevice);
        if (retval) {
                free_netdev(netdevice);
                return -ENODEV;
        }
-
-       if (dev->id.sversion == 0x72) {
-               ((struct i596_private *)netdevice->priv)->options = OPT_SWAP_PORT;
-       }
-
-       netdevs[num_drivers++] = netdevice;
-
        return retval;
 }
 
+static int __devexit lan_remove_chip (struct parisc_device *pdev)
+{
+       struct net_device *dev = parisc_get_drvdata(pdev);
+       struct i596_private *lp = netdev_priv(dev);
+
+       unregister_netdev (dev);
+       DMA_FREE(&pdev->dev, sizeof(struct i596_private),
+                (void *)lp->dma, lp->dma_addr);
+       free_netdev (dev);
+       return 0;
+}
 
 static struct parisc_device_id lan_tbl[] = {
        { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
@@ -1563,12 +220,12 @@ static struct parisc_driver lan_driver = {
        .name           = "lasi_82596",
        .id_table       = lan_tbl,
        .probe          = lan_init_chip,
+       .remove         = __devexit_p(lan_remove_chip),
 };
 
 static int __devinit lasi_82596_init(void)
 {
-       if (debug >= 0)
-               i596_debug = debug;
+       printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
        return register_parisc_driver(&lan_driver);
 }
 
@@ -1576,25 +233,6 @@ module_init(lasi_82596_init);
 
 static void __exit lasi_82596_exit(void)
 {
-       int i;
-
-       for (i=0; i<MAX_DRIVERS; i++) {
-               struct i596_private *lp;
-               struct net_device *netdevice;
-
-               netdevice = netdevs[i];
-               if (!netdevice)
-                       continue;
-
-               unregister_netdev(netdevice);
-
-               lp = netdevice->priv;
-               dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
-                                      (void *)netdevice->mem_start, lp->dma_addr);
-               free_netdev(netdevice);
-       }
-       num_drivers = 0;
-
        unregister_parisc_driver(&lan_driver);
 }
 
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
new file mode 100644 (file)
index 0000000..5884f5b
--- /dev/null
@@ -0,0 +1,1434 @@
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+   munged into HPPA boxen .
+
+   This driver is based upon 82596.c, original credits are below...
+   but there were too many hoops which HP wants jumped through to
+   keep this code in there in a sane manner.
+
+   3 primary sources of the mess --
+   1) hppa needs *lots* of cacheline flushing to keep this kind of
+   MMIO running.
+
+   2) The 82596 needs to see all of its pointers as their physical
+   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+   3) The implementation HP is using seems to be significantly pickier
+   about when and how the command and RX units are started.  some
+   command ordering was changed.
+
+   Examination of the mach driver leads one to believe that there
+   might be a saner way to pull this off...  anyone who feels like a
+   full rewrite can be my guest.
+
+   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+
+   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
+   03/02/2000  changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+   Based on Apricot.c
+   Written 1994 by Mark Evans.
+   This driver is for the Apricot 82596 bus-master interface
+
+   Modularised 12/94 Mark Evans
+
+
+   Modified to support the 82596 ethernet chips on 680x0 VME boards.
+   by Richard Hirst <richard@sleepie.demon.co.uk>
+   Renamed to be 82596.c
+
+   980825:  Changed to receive directly in to sk_buffs which are
+   allocated at open() time.  Eliminates copy on incoming frames
+   (small ones are still copied).  Shared data now held in a
+   non-cached page, so we can run on 68060 in copyback mode.
+
+   TBD:
+   * look at deferring rx frames rather than discarding (as per tulip)
+   * handle tx ring full as per tulip
+   * performace test to tune rx_copybreak
+
+   Most of my modifications relate to the braindead big-endian
+   implementation by Intel.  When the i596 is operating in
+   'big-endian' mode, it thinks a 32 bit value of 0x12345678
+   should be stored as 0x56781234.  This is a real pain, when
+   you have linked lists which are shared by the 680x0 and the
+   i596.
+
+   Driver skeleton
+   Written 1993 by Donald Becker.
+   Copyright 1993 United States Government as represented by the Director,
+   National Security Agency. This software may only be used and distributed
+   according to the terms of the GNU General Public License as modified by SRC,
+   incorporated herein by reference.
+
+   The author may be reached as becker@scyld.com, or C/O
+   Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT       0x0001
+#define DEB_PROBE      0x0002
+#define DEB_SERIOUS    0x0004
+#define DEB_ERRORS     0x0008
+#define DEB_MULTI      0x0010
+#define DEB_TDR                0x0020
+#define DEB_OPEN       0x0040
+#define DEB_RESET      0x0080
+#define DEB_ADDCMD     0x0100
+#define DEB_STATUS     0x0200
+#define DEB_STARTTX    0x0400
+#define DEB_RXADDR     0x0800
+#define DEB_TXADDR     0x1000
+#define DEB_RXFRAME    0x2000
+#define DEB_INTS       0x4000
+#define DEB_STRUCT     0x8000
+#define DEB_ANY                0xffff
+
+
+#define DEB(x, y)      if (i596_debug & (x)) { y; }
+
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET             0x00    /* reset 82596 */
+#define PORT_SELFTEST          0x01    /* selftest */
+#define PORT_ALTSCP            0x02    /* alternate SCB address */
+#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ     1536
+#define MAX_MC_CNT     64
+
+#define ISCP_BUSY      0x0001
+
+#define I596_NULL ((u32)0xffffffff)
+
+#define CMD_EOL                0x8000  /* The last command of the list, stop. */
+#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
+#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
+
+#define CMD_FLEX       0x0008  /* Enable flexible memory model */
+
+enum commands {
+       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C         0x8000  /* Set to 0 after execution */
+#define STAT_B         0x4000  /* Command being executed */
+#define STAT_OK                0x2000  /* Command executed ok */
+#define STAT_A         0x1000  /* Command aborted */
+
+#define         CUC_START      0x0100
+#define         CUC_RESUME     0x0200
+#define         CUC_SUSPEND    0x0300
+#define         CUC_ABORT      0x0400
+#define         RX_START       0x0010
+#define         RX_RESUME      0x0020
+#define         RX_SUSPEND     0x0030
+#define         RX_ABORT       0x0040
+
+#define TX_TIMEOUT     5
+
+
+struct i596_reg {
+       unsigned short porthi;
+       unsigned short portlo;
+       u32            ca;
+};
+
+#define EOF            0x8000
+#define SIZE_MASK      0x3fff
+
+struct i596_tbd {
+       unsigned short size;
+       unsigned short pad;
+       dma_addr_t     next;
+       dma_addr_t     data;
+       u32 cache_pad[5];               /* Total 32 bytes... */
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596.  The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next.  It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
+       unsigned short status;
+       unsigned short command;
+       dma_addr_t     b_next;  /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+       struct i596_cmd cmd;
+       dma_addr_t     tbd;
+       unsigned short size;
+       unsigned short pad;
+       struct sk_buff *skb;            /* So we can free it after tx */
+       dma_addr_t dma_addr;
+#ifdef __LP64__
+       u32 cache_pad[6];               /* Total 64 bytes... */
+#else
+       u32 cache_pad[1];               /* Total 32 bytes... */
+#endif
+};
+
+struct tdr_cmd {
+       struct i596_cmd cmd;
+       unsigned short status;
+       unsigned short pad;
+};
+
+struct mc_cmd {
+       struct i596_cmd cmd;
+       short mc_cnt;
+       char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+       struct i596_cmd cmd;
+       char eth_addr[8];
+};
+
+struct cf_cmd {
+       struct i596_cmd cmd;
+       char i596_config[16];
+};
+
+struct i596_rfd {
+       unsigned short stat;
+       unsigned short cmd;
+       dma_addr_t     b_next;  /* Address from i596 viewpoint */
+       dma_addr_t     rbd;
+       unsigned short count;
+       unsigned short size;
+       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
+       struct i596_rfd *v_prev;
+#ifndef __LP64__
+       u32 cache_pad[2];               /* Total 32 bytes... */
+#endif
+};
+
+struct i596_rbd {
+    /* hardware data */
+    unsigned short count;
+    unsigned short zero1;
+    dma_addr_t     b_next;
+    dma_addr_t     b_data;             /* Address from i596 viewpoint */
+    unsigned short size;
+    unsigned short zero2;
+    /* driver data */
+    struct sk_buff *skb;
+    struct i596_rbd *v_next;
+    dma_addr_t     b_addr;             /* This rbd addr from i596 view */
+    unsigned char *v_data;             /* Address from CPUs viewpoint */
+                                       /* Total 32 bytes... */
+#ifdef __LP64__
+    u32 cache_pad[4];
+#endif
+};
+
+/* These values as chosen so struct i596_dma fits in one page... */
+
+#define TX_RING_SIZE 32
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+       unsigned short status;
+       unsigned short command;
+       dma_addr_t    cmd;
+       dma_addr_t    rfd;
+       u32           crc_err;
+       u32           align_err;
+       u32           resource_err;
+       u32           over_err;
+       u32           rcvdt_err;
+       u32           short_err;
+       unsigned short t_on;
+       unsigned short t_off;
+};
+
+struct i596_iscp {
+       u32           stat;
+       dma_addr_t    scb;
+};
+
+struct i596_scp {
+       u32           sysbus;
+       u32           pad;
+       dma_addr_t    iscp;
+};
+
+struct i596_dma {
+       struct i596_scp scp                     __attribute__((aligned(32)));
+       volatile struct i596_iscp iscp          __attribute__((aligned(32)));
+       volatile struct i596_scb scb            __attribute__((aligned(32)));
+       struct sa_cmd sa_cmd                    __attribute__((aligned(32)));
+       struct cf_cmd cf_cmd                    __attribute__((aligned(32)));
+       struct tdr_cmd tdr_cmd                  __attribute__((aligned(32)));
+       struct mc_cmd mc_cmd                    __attribute__((aligned(32)));
+       struct i596_rfd rfds[RX_RING_SIZE]      __attribute__((aligned(32)));
+       struct i596_rbd rbds[RX_RING_SIZE]      __attribute__((aligned(32)));
+       struct tx_cmd tx_cmds[TX_RING_SIZE]     __attribute__((aligned(32)));
+       struct i596_tbd tbds[TX_RING_SIZE]      __attribute__((aligned(32)));
+};
+
+struct i596_private {
+       struct i596_dma *dma;
+       u32    stat;
+       int last_restart;
+       struct i596_rfd *rfd_head;
+       struct i596_rbd *rbd_head;
+       struct i596_cmd *cmd_tail;
+       struct i596_cmd *cmd_head;
+       int cmd_backlog;
+       u32    last_cmd;
+       struct net_device_stats stats;
+       int next_tx_cmd;
+       int options;
+       spinlock_t lock;       /* serialize access to chip */
+       dma_addr_t dma_addr;
+       void __iomem *mpu_port;
+       void __iomem *ca;
+};
+
+static const char init_setup[] =
+{
+       0x8E,           /* length, prefetch on */
+       0xC8,           /* fifo to 8, monitor off */
+       0x80,           /* don't save bad frames */
+       0x2E,           /* No source address insertion, 8 byte preamble */
+       0x00,           /* priority and backoff defaults */
+       0x60,           /* interframe spacing */
+       0x00,           /* slot time LSB */
+       0xf2,           /* slot time and retries */
+       0x00,           /* promiscuous mode */
+       0x00,           /* collision detect */
+       0x40,           /* minimum frame length */
+       0xff,
+       0x00,
+       0x7f /*  *multi IA */ };
+
+static int i596_open(struct net_device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static struct net_device_stats *i596_get_stats(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+static inline void ca(struct net_device *dev);
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 100;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev);
+#endif
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+       DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+       while (--delcnt && dma->iscp.stat) {
+               udelay(10);
+               DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+       }
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
+                    dev->name, str, SWAP16(dma->iscp.stat));
+               return -1;
+       } else
+               return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+       DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+       while (--delcnt && dma->scb.command) {
+               udelay(10);
+               DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+       }
+       if (!delcnt) {
+               printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+                      dev->name, str,
+                      SWAP16(dma->scb.status),
+                      SWAP16(dma->scb.command));
+               return -1;
+       } else
+               return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       struct i596_cmd *cmd;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
+              &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
+       printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
+              &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
+       printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
+               " .cmd = %08x, .rfd = %08x\n",
+              &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
+               SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
+       printk(KERN_DEBUG "   errors: crc %x, align %x, resource %x,"
+              " over %x, rcvdt %x, short %x\n",
+              SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
+              SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
+              SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
+       cmd = lp->cmd_head;
+       while (cmd != NULL) {
+               printk(KERN_DEBUG
+                      "cmd at %p, .status = %04x, .command = %04x,"
+                      " .b_next = %08x\n",
+                      cmd, SWAP16(cmd->status), SWAP16(cmd->command),
+                      SWAP32(cmd->b_next));
+               cmd = cmd->v_next;
+       }
+       rfd = lp->rfd_head;
+       printk(KERN_DEBUG "rfd_head = %p\n", rfd);
+       do {
+               printk(KERN_DEBUG
+                      "   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
+                      " count %04x\n",
+                      rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
+                      SWAP32(rfd->b_next), SWAP32(rfd->rbd),
+                      SWAP16(rfd->count));
+               rfd = rfd->v_next;
+       } while (rfd != lp->rfd_head);
+       rbd = lp->rbd_head;
+       printk(KERN_DEBUG "rbd_head = %p\n", rbd);
+       do {
+               printk(KERN_DEBUG
+                      "   %p .count %04x, b_next %08x, b_data %08x,"
+                      " size %04x\n",
+                       rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
+                      SWAP32(rbd->b_data), SWAP16(rbd->size));
+               rbd = rbd->v_next;
+       } while (rbd != lp->rbd_head);
+       DMA_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+#define virt_to_dma(lp, v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)((lp)->dma)))
+
+static inline int init_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       int i;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       /* First build the Receive Buffer Descriptor List */
+
+       for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
+               dma_addr_t dma_addr;
+               struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4);
+
+               if (skb == NULL)
+                       return -1;
+               skb_reserve(skb, 2);
+               dma_addr = dma_map_single(dev->dev.parent, skb->data,
+                                         PKT_BUF_SZ, DMA_FROM_DEVICE);
+               rbd->v_next = rbd+1;
+               rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
+               rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
+               rbd->skb = skb;
+               rbd->v_data = skb->data;
+               rbd->b_data = SWAP32(dma_addr);
+               rbd->size = SWAP16(PKT_BUF_SZ);
+       }
+       lp->rbd_head = dma->rbds;
+       rbd = dma->rbds + rx_ring_size - 1;
+       rbd->v_next = dma->rbds;
+       rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
+
+       /* Now build the Receive Frame Descriptor List */
+
+       for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
+               rfd->rbd = I596_NULL;
+               rfd->v_next = rfd+1;
+               rfd->v_prev = rfd-1;
+               rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
+               rfd->cmd = SWAP16(CMD_FLEX);
+       }
+       lp->rfd_head = dma->rfds;
+       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+       rfd = dma->rfds;
+       rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
+       rfd->v_prev = dma->rfds + rx_ring_size - 1;
+       rfd = dma->rfds + rx_ring_size - 1;
+       rfd->v_next = dma->rfds;
+       rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
+       rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+
+       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+       return 0;
+}
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_rbd *rbd;
+       int i;
+
+       for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
+               if (rbd->skb == NULL)
+                       break;
+               dma_unmap_single(dev->dev.parent,
+                                (dma_addr_t)SWAP32(rbd->b_data),
+                                PKT_BUF_SZ, DMA_FROM_DEVICE);
+               dev_kfree_skb(rbd->skb);
+       }
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       int i;
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+
+       for (i = 0; i < rx_ring_size; i++) {
+               dma->rfds[i].rbd = I596_NULL;
+               dma->rfds[i].cmd = SWAP16(CMD_FLEX);
+       }
+       dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
+       lp->rfd_head = dma->rfds;
+       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+       lp->rbd_head = dma->rbds;
+       dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
+
+       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       unsigned long flags;
+
+       mpu_port(dev, PORT_RESET, 0);
+       udelay(100);                    /* Wait 100us - seems to help */
+
+       /* change the scp address */
+
+       lp->last_cmd = jiffies;
+
+       dma->scp.sysbus = SYSBUS;
+       dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
+       dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
+       dma->iscp.stat = SWAP32(ISCP_BUSY);
+       lp->cmd_backlog = 0;
+
+       lp->cmd_head = NULL;
+       dma->scb.cmd = I596_NULL;
+
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
+
+       DMA_WBACK(dev, &(dma->scp), sizeof(struct i596_scp));
+       DMA_WBACK(dev, &(dma->iscp), sizeof(struct i596_iscp));
+       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+       mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
+       ca(dev);
+       if (wait_istat(dev, dma, 1000, "initialization timed out"))
+               goto failed;
+       DEB(DEB_INIT, printk(KERN_DEBUG
+                            "%s: i82596 initialization successful\n",
+                            dev->name));
+
+       if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
+               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+               goto failed;
+       }
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+       rebuild_rx_bufs(dev);
+
+       dma->scb.command = 0;
+       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+       DEB(DEB_INIT, printk(KERN_DEBUG
+                            "%s: queuing CmdConfigure\n", dev->name));
+       memcpy(dma->cf_cmd.i596_config, init_setup, 14);
+       dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+       DMA_WBACK(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
+       i596_add_cmd(dev, &dma->cf_cmd.cmd);
+
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
+       memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, 6);
+       dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
+       DMA_WBACK(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
+       i596_add_cmd(dev, &dma->sa_cmd.cmd);
+
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
+       dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
+       DMA_WBACK(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
+       i596_add_cmd(dev, &dma->tdr_cmd.cmd);
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
+               spin_unlock_irqrestore (&lp->lock, flags);
+               goto failed_free_irq;
+       }
+       DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
+       dma->scb.command = SWAP16(RX_START);
+       dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+       DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+       ca(dev);
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+       if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
+               goto failed_free_irq;
+       DEB(DEB_INIT, printk(KERN_DEBUG
+                            "%s: Receive unit started OK\n", dev->name));
+       return 0;
+
+failed_free_irq:
+       free_irq(dev->irq, dev);
+failed:
+       printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
+       mpu_port(dev, PORT_RESET, 0);
+       return -1;
+}
+
+
+static inline int i596_rx(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+       int frames = 0;
+
+       DEB(DEB_RXFRAME, printk(KERN_DEBUG
+                               "i596_rx(), rfd_head %p, rbd_head %p\n",
+                               lp->rfd_head, lp->rbd_head));
+
+
+       rfd = lp->rfd_head;             /* Ref next frame to check */
+
+       DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+       while (rfd->stat & SWAP16(STAT_C)) {    /* Loop while complete frames */
+               if (rfd->rbd == I596_NULL)
+                       rbd = NULL;
+               else if (rfd->rbd == lp->rbd_head->b_addr) {
+                       rbd = lp->rbd_head;
+                       DMA_INV(dev, rbd, sizeof(struct i596_rbd));
+               } else {
+                       printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
+                       /* XXX Now what? */
+                       rbd = NULL;
+               }
+               DEB(DEB_RXFRAME, printk(KERN_DEBUG
+                                     "  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
+                                     rfd, rfd->rbd, rfd->stat));
+
+               if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
+                       /* a good frame */
+                       int pkt_len = SWAP16(rbd->count) & 0x3fff;
+                       struct sk_buff *skb = rbd->skb;
+                       int rx_in_place = 0;
+
+                       DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
+                       frames++;
+
+                       /* Check if the packet is long enough to just accept
+                        * without copying to a properly sized skbuff.
+                        */
+
+                       if (pkt_len > rx_copybreak) {
+                               struct sk_buff *newskb;
+                               dma_addr_t dma_addr;
+
+                               dma_unmap_single(dev->dev.parent,
+                                                (dma_addr_t)SWAP32(rbd->b_data),
+                                                PKT_BUF_SZ, DMA_FROM_DEVICE);
+                               /* Get fresh skbuff to replace filled one. */
+                               newskb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4);
+                               if (newskb == NULL) {
+                                       skb = NULL;     /* drop pkt */
+                                       goto memory_squeeze;
+                               }
+                               skb_reserve(newskb, 2);
+
+                               /* Pass up the skb already on the Rx ring. */
+                               skb_put(skb, pkt_len);
+                               rx_in_place = 1;
+                               rbd->skb = newskb;
+                               dma_addr = dma_map_single(dev->dev.parent,
+                                                         newskb->data,
+                                                         PKT_BUF_SZ,
+                                                         DMA_FROM_DEVICE);
+                               rbd->v_data = newskb->data;
+                               rbd->b_data = SWAP32(dma_addr);
+                               DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+                       } else
+                               skb = netdev_alloc_skb(dev, pkt_len + 2);
+memory_squeeze:
+                       if (skb == NULL) {
+                               /* XXX tulip.c can defer packets here!! */
+                               printk(KERN_ERR
+                                      "%s: i596_rx Memory squeeze, dropping packet.\n",
+                                      dev->name);
+                               lp->stats.rx_dropped++;
+                       } else {
+                               if (!rx_in_place) {
+                                       /* 16 byte align the data fields */
+                                       dma_sync_single_for_cpu(dev->dev.parent,
+                                                               (dma_addr_t)SWAP32(rbd->b_data),
+                                                               PKT_BUF_SZ, DMA_FROM_DEVICE);
+                                       skb_reserve(skb, 2);
+                                       memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
+                                       dma_sync_single_for_device(dev->dev.parent,
+                                                                  (dma_addr_t)SWAP32(rbd->b_data),
+                                                                  PKT_BUF_SZ, DMA_FROM_DEVICE);
+                               }
+                               skb->len = pkt_len;
+                               skb->protocol = eth_type_trans(skb, dev);
+                               netif_rx(skb);
+                               dev->last_rx = jiffies;
+                               lp->stats.rx_packets++;
+                               lp->stats.rx_bytes += pkt_len;
+                       }
+               } else {
+                       DEB(DEB_ERRORS, printk(KERN_DEBUG
+                                              "%s: Error, rfd.stat = 0x%04x\n",
+                                              dev->name, rfd->stat));
+                       lp->stats.rx_errors++;
+                       if (rfd->stat & SWAP16(0x0100))
+                               lp->stats.collisions++;
+                       if (rfd->stat & SWAP16(0x8000))
+                               lp->stats.rx_length_errors++;
+                       if (rfd->stat & SWAP16(0x0001))
+                               lp->stats.rx_over_errors++;
+                       if (rfd->stat & SWAP16(0x0002))
+                               lp->stats.rx_fifo_errors++;
+                       if (rfd->stat & SWAP16(0x0004))
+                               lp->stats.rx_frame_errors++;
+                       if (rfd->stat & SWAP16(0x0008))
+                               lp->stats.rx_crc_errors++;
+                       if (rfd->stat & SWAP16(0x0010))
+                               lp->stats.rx_length_errors++;
+               }
+
+               /* Clear the buffer descriptor count and EOF + F flags */
+
+               if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
+                       rbd->count = 0;
+                       lp->rbd_head = rbd->v_next;
+                       DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+               }
+
+               /* Tidy the frame descriptor, marking it as end of list */
+
+               rfd->rbd = I596_NULL;
+               rfd->stat = 0;
+               rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+               rfd->count = 0;
+
+               /* Update record of next frame descriptor to process */
+
+               lp->dma->scb.rfd = rfd->b_next;
+               lp->rfd_head = rfd->v_next;
+               DMA_WBACK_INV(dev, rfd, sizeof(struct i596_rfd));
+
+               /* Remove end-of-list from old end descriptor */
+
+               rfd->v_prev->cmd = SWAP16(CMD_FLEX);
+               DMA_WBACK_INV(dev, rfd->v_prev, sizeof(struct i596_rfd));
+               rfd = lp->rfd_head;
+               DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+       }
+
+       DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
+
+       return 0;
+}
+
+
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+       struct i596_cmd *ptr;
+
+       while (lp->cmd_head != NULL) {
+               ptr = lp->cmd_head;
+               lp->cmd_head = ptr->v_next;
+               lp->cmd_backlog--;
+
+               switch (SWAP16(ptr->command) & 0x7) {
+               case CmdTx:
+                       {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+                               dma_unmap_single(dev->dev.parent,
+                                                tx_cmd->dma_addr,
+                                                skb->len, DMA_TO_DEVICE);
+
+                               dev_kfree_skb(skb);
+
+                               lp->stats.tx_errors++;
+                               lp->stats.tx_aborted_errors++;
+
+                               ptr->v_next = NULL;
+                               ptr->b_next = I596_NULL;
+                               tx_cmd->cmd.command = 0;  /* Mark as free */
+                               break;
+                       }
+               default:
+                       ptr->v_next = NULL;
+                       ptr->b_next = I596_NULL;
+               }
+               DMA_WBACK_INV(dev, ptr, sizeof(struct i596_cmd));
+       }
+
+       wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
+       lp->dma->scb.cmd = I596_NULL;
+       DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+}
+
+
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
+{
+       unsigned long flags;
+
+       DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
+
+       netif_stop_queue(dev);
+
+       /* FIXME: this command might cause an lpmc */
+       lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+       DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+       ca(dev);
+
+       /* wait for shutdown */
+       wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       i596_cleanup_cmd(dev, lp);
+       i596_rx(dev);
+
+       netif_start_queue(dev);
+       init_i596_mem(dev);
+}
+
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       unsigned long flags;
+
+       DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
+                              lp->cmd_head));
+
+       cmd->status = 0;
+       cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
+       cmd->v_next = NULL;
+       cmd->b_next = I596_NULL;
+       DMA_WBACK(dev, cmd, sizeof(struct i596_cmd));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (lp->cmd_head != NULL) {
+               lp->cmd_tail->v_next = cmd;
+               lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
+               DMA_WBACK(dev, lp->cmd_tail, sizeof(struct i596_cmd));
+       } else {
+               lp->cmd_head = cmd;
+               wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
+               dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
+               dma->scb.command = SWAP16(CUC_START);
+               DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+               ca(dev);
+       }
+       lp->cmd_tail = cmd;
+       lp->cmd_backlog++;
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       if (lp->cmd_backlog > max_cmd_backlog) {
+               unsigned long tickssofar = jiffies - lp->last_cmd;
+
+               if (tickssofar < ticks_limit)
+                       return;
+
+               printk(KERN_ERR
+                      "%s: command unit timed out, status resetting.\n",
+                      dev->name);
+#if 1
+               i596_reset(dev, lp);
+#endif
+       }
+}
+
+static int i596_open(struct net_device *dev)
+{
+       DEB(DEB_OPEN, printk(KERN_DEBUG
+                            "%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+       if (init_rx_bufs(dev)) {
+               printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
+               return -EAGAIN;
+       }
+       if (init_i596_mem(dev)) {
+               printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
+               goto out_remove_rx_bufs;
+       }
+       netif_start_queue(dev);
+
+       return 0;
+
+out_remove_rx_bufs:
+       remove_rx_bufs(dev);
+       return -EAGAIN;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       /* Transmitter timeout, serious problems. */
+       DEB(DEB_ERRORS, printk(KERN_DEBUG
+                              "%s: transmit timed out, status resetting.\n",
+                              dev->name));
+
+       lp->stats.tx_errors++;
+
+       /* Try to restart the adaptor */
+       if (lp->last_restart == lp->stats.tx_packets) {
+               DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
+               /* Shutdown and restart */
+               i596_reset (dev, lp);
+       } else {
+               /* Issue a channel attention signal */
+               DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
+               lp->dma->scb.command = SWAP16(CUC_START | RX_START);
+               DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+               ca (dev);
+               lp->last_restart = lp->stats.tx_packets;
+       }
+
+       dev->trans_start = jiffies;
+       netif_wake_queue (dev);
+}
+
+
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct tx_cmd *tx_cmd;
+       struct i596_tbd *tbd;
+       short length = skb->len;
+       dev->trans_start = jiffies;
+
+       DEB(DEB_STARTTX, printk(KERN_DEBUG
+                               "%s: i596_start_xmit(%x,%p) called\n",
+                               dev->name, skb->len, skb->data));
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return 0;
+               length = ETH_ZLEN;
+       }
+
+       netif_stop_queue(dev);
+
+       tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
+       tbd = lp->dma->tbds + lp->next_tx_cmd;
+
+       if (tx_cmd->cmd.command) {
+               DEB(DEB_ERRORS, printk(KERN_DEBUG
+                                      "%s: xmit ring full, dropping packet.\n",
+                                      dev->name));
+               lp->stats.tx_dropped++;
+
+               dev_kfree_skb(skb);
+       } else {
+               if (++lp->next_tx_cmd == TX_RING_SIZE)
+                       lp->next_tx_cmd = 0;
+               tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
+               tbd->next = I596_NULL;
+
+               tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
+               tx_cmd->skb = skb;
+
+               tx_cmd->pad = 0;
+               tx_cmd->size = 0;
+               tbd->pad = 0;
+               tbd->size = SWAP16(EOF | length);
+
+               tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
+                                                 skb->len, DMA_TO_DEVICE);
+               tbd->data = SWAP32(tx_cmd->dma_addr);
+
+               DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
+               DMA_WBACK_INV(dev, tx_cmd, sizeof(struct tx_cmd));
+               DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
+               i596_add_cmd(dev, &tx_cmd->cmd);
+
+               lp->stats.tx_packets++;
+               lp->stats.tx_bytes += length;
+       }
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+       int i;
+
+       printk(KERN_DEBUG "i596 0x%p, ", add);
+       for (i = 0; i < 6; i++)
+               printk(" %02X", add[i + 6]);
+       printk(" -->");
+       for (i = 0; i < 6; i++)
+               printk(" %02X", add[i]);
+       printk(" %02X%02X, %s\n", add[12], add[13], str);
+}
+
+static int __devinit i82596_probe(struct net_device *dev)
+{
+       int i;
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma;
+
+       /* This lot is ensure things have been cache line aligned. */
+       BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
+       BUILD_BUG_ON(sizeof(struct i596_rbd) &  31);
+       BUILD_BUG_ON(sizeof(struct tx_cmd)   &  31);
+       BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
+#ifndef __LP64__
+       BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
+#endif
+
+       if (!dev->base_addr || !dev->irq)
+               return -ENODEV;
+
+       dma = (struct i596_dma *) DMA_ALLOC(dev->dev.parent,
+               sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL);
+       if (!dma) {
+               printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
+               return -ENOMEM;
+       }
+
+       /* The 82596-specific entries in the device structure. */
+       dev->open = i596_open;
+       dev->stop = i596_close;
+       dev->hard_start_xmit = i596_start_xmit;
+       dev->get_stats = i596_get_stats;
+       dev->set_multicast_list = set_multicast_list;
+       dev->tx_timeout = i596_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = i596_poll_controller;
+#endif
+
+       memset(dma, 0, sizeof(struct i596_dma));
+       lp->dma = dma;
+
+       dma->scb.command = 0;
+       dma->scb.cmd = I596_NULL;
+       dma->scb.rfd = I596_NULL;
+       spin_lock_init(&lp->lock);
+
+       DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+
+       i = register_netdev(dev);
+       if (i) {
+               DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
+                                   (void *)dma, lp->dma_addr);
+               return i;
+       };
+
+       DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,",
+                             dev->name, dev->base_addr));
+       for (i = 0; i < 6; i++)
+               DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i]));
+       DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq));
+       DEB(DEB_INIT, printk(KERN_INFO
+                            "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
+                            dev->name, dma, (int)sizeof(struct i596_dma),
+                            &dma->scb));
+
+       return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       i596_interrupt(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct i596_private *lp;
+       struct i596_dma *dma;
+       unsigned short status, ack_cmd = 0;
+
+       if (dev == NULL) {
+               printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+                      __FUNCTION__, irq);
+               return IRQ_NONE;
+       }
+
+       lp = netdev_priv(dev);
+       dma = lp->dma;
+
+       spin_lock (&lp->lock);
+
+       wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+       status = SWAP16(dma->scb.status);
+
+       DEB(DEB_INTS, printk(KERN_DEBUG
+                            "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+                       dev->name, irq, status));
+
+       ack_cmd = status & 0xf000;
+
+       if (!ack_cmd) {
+               DEB(DEB_ERRORS, printk(KERN_DEBUG
+                                      "%s: interrupt with no events\n",
+                                      dev->name));
+               spin_unlock (&lp->lock);
+               return IRQ_NONE;
+       }
+
+       if ((status & 0x8000) || (status & 0x2000)) {
+               struct i596_cmd *ptr;
+
+               if ((status & 0x8000))
+                       DEB(DEB_INTS,
+                           printk(KERN_DEBUG
+                                  "%s: i596 interrupt completed command.\n",
+                                  dev->name));
+               if ((status & 0x2000))
+                       DEB(DEB_INTS,
+                           printk(KERN_DEBUG
+                                  "%s: i596 interrupt command unit inactive %x.\n",
+                                  dev->name, status & 0x0700));
+
+               while (lp->cmd_head != NULL) {
+                       DMA_INV(dev, lp->cmd_head, sizeof(struct i596_cmd));
+                       if (!(lp->cmd_head->status & SWAP16(STAT_C)))
+                               break;
+
+                       ptr = lp->cmd_head;
+
+                       DEB(DEB_STATUS,
+                           printk(KERN_DEBUG
+                                  "cmd_head->status = %04x, ->command = %04x\n",
+                                  SWAP16(lp->cmd_head->status),
+                                  SWAP16(lp->cmd_head->command)));
+                       lp->cmd_head = ptr->v_next;
+                       lp->cmd_backlog--;
+
+                       switch (SWAP16(ptr->command) & 0x7) {
+                       case CmdTx:
+                           {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+
+                               if (ptr->status & SWAP16(STAT_OK)) {
+                                       DEB(DEB_TXADDR,
+                                           print_eth(skb->data, "tx-done"));
+                               } else {
+                                       lp->stats.tx_errors++;
+                                       if (ptr->status & SWAP16(0x0020))
+                                               lp->stats.collisions++;
+                                       if (!(ptr->status & SWAP16(0x0040)))
+                                               lp->stats.tx_heartbeat_errors++;
+                                       if (ptr->status & SWAP16(0x0400))
+                                               lp->stats.tx_carrier_errors++;
+                                       if (ptr->status & SWAP16(0x0800))
+                                               lp->stats.collisions++;
+                                       if (ptr->status & SWAP16(0x1000))
+                                               lp->stats.tx_aborted_errors++;
+                               }
+                               dma_unmap_single(dev->dev.parent,
+                                                tx_cmd->dma_addr,
+                                                skb->len, DMA_TO_DEVICE);
+                               dev_kfree_skb_irq(skb);
+
+                               tx_cmd->cmd.command = 0; /* Mark free */
+                               break;
+                           }
+                       case CmdTDR:
+                           {
+                               unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
+
+                               if (status & 0x8000) {
+                                       DEB(DEB_ANY,
+                                           printk(KERN_DEBUG "%s: link ok.\n",
+                                                  dev->name));
+                               } else {
+                                       if (status & 0x4000)
+                                               printk(KERN_ERR
+                                                      "%s: Transceiver problem.\n",
+                                                      dev->name);
+                                       if (status & 0x2000)
+                                               printk(KERN_ERR
+                                                      "%s: Termination problem.\n",
+                                                      dev->name);
+                                       if (status & 0x1000)
+                                               printk(KERN_ERR
+                                                      "%s: Short circuit.\n",
+                                                      dev->name);
+
+                                       DEB(DEB_TDR,
+                                           printk(KERN_DEBUG "%s: Time %d.\n",
+                                                  dev->name, status & 0x07ff));
+                               }
+                               break;
+                           }
+                       case CmdConfigure:
+                               /*
+                                * Zap command so set_multicast_list() know
+                                * it is free
+                                */
+                               ptr->command = 0;
+                               break;
+                       }
+                       ptr->v_next = NULL;
+                       ptr->b_next = I596_NULL;
+                       DMA_WBACK(dev, ptr, sizeof(struct i596_cmd));
+                       lp->last_cmd = jiffies;
+               }
+
+               /* This mess is arranging that only the last of any outstanding
+                * commands has the interrupt bit set.  Should probably really
+                * only add to the cmd queue when the CU is stopped.
+                */
+               ptr = lp->cmd_head;
+               while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
+                       struct i596_cmd *prev = ptr;
+
+                       ptr->command &= SWAP16(0x1fff);
+                       ptr = ptr->v_next;
+                       DMA_WBACK_INV(dev, prev, sizeof(struct i596_cmd));
+               }
+
+               if (lp->cmd_head != NULL)
+                       ack_cmd |= CUC_START;
+               dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
+               DMA_WBACK_INV(dev, &dma->scb, sizeof(struct i596_scb));
+       }
+       if ((status & 0x1000) || (status & 0x4000)) {
+               if ((status & 0x4000))
+                       DEB(DEB_INTS,
+                           printk(KERN_DEBUG
+                                  "%s: i596 interrupt received a frame.\n",
+                                  dev->name));
+               i596_rx(dev);
+               /* Only RX_START if stopped - RGH 07-07-96 */
+               if (status & 0x1000) {
+                       if (netif_running(dev)) {
+                               DEB(DEB_ERRORS,
+                                   printk(KERN_DEBUG
+                                          "%s: i596 interrupt receive unit inactive, status 0x%x\n",
+                                          dev->name, status));
+                               ack_cmd |= RX_START;
+                               lp->stats.rx_errors++;
+                               lp->stats.rx_fifo_errors++;
+                               rebuild_rx_bufs(dev);
+                       }
+               }
+       }
+       wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+       dma->scb.command = SWAP16(ack_cmd);
+       DMA_WBACK(dev, &dma->scb, sizeof(struct i596_scb));
+
+       /* DANGER: I suspect that some kind of interrupt
+        acknowledgement aside from acking the 82596 might be needed
+        here...  but it's running acceptably without */
+
+       ca(dev);
+
+       wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
+       DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
+
+       spin_unlock (&lp->lock);
+       return IRQ_HANDLED;
+}
+
+static int i596_close(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       unsigned long flags;
+
+       netif_stop_queue(dev);
+
+       DEB(DEB_INIT,
+           printk(KERN_DEBUG
+                  "%s: Shutting down ethercard, status was %4.4x.\n",
+                  dev->name, SWAP16(lp->dma->scb.status)));
+
+       spin_lock_irqsave(&lp->lock, flags);
+
+       wait_cmd(dev, lp->dma, 100, "close1 timed out");
+       lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+       DMA_WBACK(dev, &lp->dma->scb, sizeof(struct i596_scb));
+
+       ca(dev);
+
+       wait_cmd(dev, lp->dma, 100, "close2 timed out");
+       spin_unlock_irqrestore(&lp->lock, flags);
+       DEB(DEB_STRUCT, i596_display_data(dev));
+       i596_cleanup_cmd(dev, lp);
+
+       free_irq(dev->irq, dev);
+       remove_rx_bufs(dev);
+
+       return 0;
+}
+
+static struct net_device_stats *i596_get_stats(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       return &lp->stats;
+}
+
+/*
+ *    Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+       struct i596_dma *dma = lp->dma;
+       int config = 0, cnt;
+
+       DEB(DEB_MULTI,
+           printk(KERN_DEBUG
+                  "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
+                  dev->name, dev->mc_count,
+                  dev->flags & IFF_PROMISC ? "ON" : "OFF",
+                  dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+       if ((dev->flags & IFF_PROMISC) &&
+           !(dma->cf_cmd.i596_config[8] & 0x01)) {
+               dma->cf_cmd.i596_config[8] |= 0x01;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_PROMISC) &&
+           (dma->cf_cmd.i596_config[8] & 0x01)) {
+               dma->cf_cmd.i596_config[8] &= ~0x01;
+               config = 1;
+       }
+       if ((dev->flags & IFF_ALLMULTI) &&
+           (dma->cf_cmd.i596_config[11] & 0x20)) {
+               dma->cf_cmd.i596_config[11] &= ~0x20;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_ALLMULTI) &&
+           !(dma->cf_cmd.i596_config[11] & 0x20)) {
+               dma->cf_cmd.i596_config[11] |= 0x20;
+               config = 1;
+       }
+       if (config) {
+               if (dma->cf_cmd.cmd.command)
+                       printk(KERN_INFO
+                              "%s: config change request already queued\n",
+                              dev->name);
+               else {
+                       dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+                       DMA_WBACK_INV(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
+                       i596_add_cmd(dev, &dma->cf_cmd.cmd);
+               }
+       }
+
+       cnt = dev->mc_count;
+       if (cnt > MAX_MC_CNT) {
+               cnt = MAX_MC_CNT;
+               printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
+                       dev->name, cnt);
+       }
+
+       if (dev->mc_count > 0) {
+               struct dev_mc_list *dmi;
+               unsigned char *cp;
+               struct mc_cmd *cmd;
+
+               cmd = &dma->mc_cmd;
+               cmd->cmd.command = SWAP16(CmdMulticastList);
+               cmd->mc_cnt = SWAP16(dev->mc_count * 6);
+               cp = cmd->mc_addrs;
+               for (dmi = dev->mc_list;
+                    cnt && dmi != NULL;
+                    dmi = dmi->next, cnt--, cp += 6) {
+                       memcpy(cp, dmi->dmi_addr, 6);
+                       if (i596_debug > 1)
+                               DEB(DEB_MULTI,
+                                   printk(KERN_DEBUG
+                                          "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                          dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]));
+               }
+               DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
+               i596_add_cmd(dev, &cmd->cmd);
+       }
+}
index 7f8b7d55b6e110ba5dbc49d0917e9e3fbb592ad4..492cfaaaa75cbf3b687214df37462f268118ce7e 100644 (file)
@@ -113,8 +113,7 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
        struct mlx4_cmd_mailbox *mailbox;
        int ret = 0;
 
-       if (cur_state < 0 || cur_state >= MLX4_QP_NUM_STATE ||
-           new_state < 0 || cur_state >= MLX4_QP_NUM_STATE ||
+       if (cur_state >= MLX4_QP_NUM_STATE || cur_state >= MLX4_QP_NUM_STATE ||
            !op[cur_state][new_state])
                return -EINVAL;
 
index 75102d30730f0cdecf3942485211cfbcfe5eb59f..05e0577a0e103b55a2c8431595ebc2cb679a4675 100644 (file)
@@ -724,7 +724,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
        __u32 mac_cfg0;
        u32 port = physical_port[adapter->portnum];
 
-       if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+       if (port > NETXEN_NIU_MAX_GBE_PORTS)
                return -EINVAL;
        mac_cfg0 = 0;
        netxen_gb_soft_reset(mac_cfg0);
@@ -757,7 +757,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
        __u32 reg;
        u32 port = physical_port[adapter->portnum];
 
-       if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+       if (port > NETXEN_NIU_MAX_GBE_PORTS)
                return -EINVAL;
 
        /* save previous contents */
@@ -894,7 +894,7 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
        __u32 reg;
        u32 port = physical_port[adapter->portnum];
 
-       if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+       if (port > NETXEN_NIU_MAX_XG_PORTS)
                return -EINVAL;
 
        if (netxen_nic_hw_read_wx(adapter,
index 8d38425e46c3cba389aaee76bada0765be257c3e..0b3066a6fe405217250c2a97e67fdbadc926cbdc 100644 (file)
@@ -755,7 +755,7 @@ static int pasemi_mac_open(struct net_device *dev)
        flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
 
        pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
-                              PAS_IOB_DMA_RXCH_CFG_CNTTH(1));
+                              PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
 
        pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
                               PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
index 808fae1577e0d8feea3be1ab3e263e599c870ed9..50dff1b81d3408b5724f297083c7284488453fb8 100644 (file)
@@ -521,6 +521,7 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
 
 static int axnet_open(struct net_device *dev)
 {
+    int ret;
     axnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
     
@@ -529,9 +530,11 @@ static int axnet_open(struct net_device *dev)
     if (!pcmcia_dev_present(link))
        return -ENODEV;
 
-    link->open++;
+    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
+    if (ret)
+           return ret;
 
-    request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
+    link->open++;
 
     info->link_status = 0x00;
     init_timer(&info->watchdog);
index 3f93d4933235cba3f39c0776760e4077d63a53df..85d5f2ca4bb55d6e14e0e2ffc0684975d7b0e500 100644 (file)
@@ -109,7 +109,7 @@ static const struct ethtool_ops netdev_ethtool_ops;
     card type
  */
 typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, 
-              XXX10304
+              XXX10304, NEC, KME
 } cardtype_t;
 
 /*
@@ -374,6 +374,18 @@ static int fmvj18x_config(struct pcmcia_device *link)
                link->io.NumPorts2 = 8;
            }
            break;
+       case MANFID_NEC:
+           cardtype = NEC; /* MultiFunction Card */
+           link->conf.ConfigBase = 0x800;
+           link->conf.ConfigIndex = 0x47;
+           link->io.NumPorts2 = 8;
+           break;
+       case MANFID_KME:
+           cardtype = KME; /* MultiFunction Card */
+           link->conf.ConfigBase = 0x800;
+           link->conf.ConfigIndex = 0x47;
+           link->io.NumPorts2 = 8;
+           break;
        case MANFID_CONTEC:
            cardtype = CONTEC;
            break;
@@ -450,6 +462,8 @@ static int fmvj18x_config(struct pcmcia_device *link)
     case TDK:
     case LA501:
     case CONTEC:
+    case NEC:
+    case KME:
        tuple.DesiredTuple = CISTPL_FUNCE;
        tuple.TupleOffset = 0;
        CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
@@ -469,6 +483,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
                card_name = "TDK LAK-CD021";
            } else if( cardtype == LA501 ) {
                card_name = "LA501";
+           } else if( cardtype == NEC ) {
+               card_name = "PK-UG-J001";
+           } else if( cardtype == KME ) {
+               card_name = "Panasonic";
            } else {
                card_name = "C-NET(PC)C";
            }
@@ -678,8 +696,11 @@ static struct pcmcia_device_id fmvj18x_ids[] = {
        PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
        PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
        PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
        PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
index d88e9b2e93cf919a66edff259be28b5e2214c402..f2613c29b00883d519fbb9dbd39146d940217658 100644 (file)
@@ -960,6 +960,7 @@ static void mii_phy_probe(struct net_device *dev)
 
 static int pcnet_open(struct net_device *dev)
 {
+    int ret;
     pcnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
 
@@ -968,10 +969,12 @@ static int pcnet_open(struct net_device *dev)
     if (!pcmcia_dev_present(link))
        return -ENODEV;
 
-    link->open++;
-
     set_misc_reg(dev);
-    request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
+    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
+    if (ret)
+           return ret;
+
+    link->open++;
 
     info->phy_id = info->eth_phy;
     info->link_status = 0x00;
@@ -1552,6 +1555,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
        PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
        PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
        PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
        PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
        PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
index 09b6f259eb9225efbedec3d12523f48736c13a79..dd09011c7ee5d9656aec4891860c3ee3a6537b74 100644 (file)
@@ -55,6 +55,11 @@ config BROADCOM_PHY
        ---help---
          Currently supports the BCM5411, BCM5421 and BCM5461 PHYs.
 
+config ICPLUS_PHY
+       tristate "Drivers for ICPlus PHYs"
+       ---help---
+         Currently supports the IP175C PHY.
+
 config FIXED_PHY
        tristate "Drivers for PHY emulation on fixed speed/link"
        ---help---
index bcd1efbd2a181a9799e25047bd97df578f7afbec..8885650647ffa8e8a6b80db85815a6272eadad4f 100644 (file)
@@ -11,4 +11,5 @@ obj-$(CONFIG_QSEMI_PHY)               += qsemi.o
 obj-$(CONFIG_SMSC_PHY)         += smsc.o
 obj-$(CONFIG_VITESSE_PHY)      += vitesse.o
 obj-$(CONFIG_BROADCOM_PHY)     += broadcom.o
+obj-$(CONFIG_ICPLUS_PHY)       += icplus.o
 obj-$(CONFIG_FIXED_PHY)                += fixed.o
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
new file mode 100644 (file)
index 0000000..af3f1f2
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Driver for ICPlus PHYs
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("ICPlus IP175C PHY driver");
+MODULE_AUTHOR("Michael Barkowski");
+MODULE_LICENSE("GPL");
+
+static int ip175c_config_init(struct phy_device *phydev)
+{
+       int err, i;
+       static int full_reset_performed = 0;
+
+       if (full_reset_performed == 0) {
+
+               /* master reset */
+               err = phydev->bus->write(phydev->bus, 30, 0, 0x175c);
+               if (err < 0)
+                       return err;
+
+               /* ensure no bus delays overlap reset period */
+               err = phydev->bus->read(phydev->bus, 30, 0);
+
+               /* data sheet specifies reset period is 2 msec */
+               mdelay(2);
+
+               /* enable IP175C mode */
+               err = phydev->bus->write(phydev->bus, 29, 31, 0x175c);
+               if (err < 0)
+                       return err;
+
+               /* Set MII0 speed and duplex (in PHY mode) */
+               err = phydev->bus->write(phydev->bus, 29, 22, 0x420);
+               if (err < 0)
+                       return err;
+
+               /* reset switch ports */
+               for (i = 0; i < 5; i++) {
+                       err = phydev->bus->write(phydev->bus, i,
+                                                MII_BMCR, BMCR_RESET);
+                       if (err < 0)
+                               return err;
+               }
+
+               for (i = 0; i < 5; i++)
+                       err = phydev->bus->read(phydev->bus, i, MII_BMCR);
+
+               mdelay(2);
+
+               full_reset_performed = 1;
+       }
+
+       if (phydev->addr != 4) {
+               phydev->state = PHY_RUNNING;
+               phydev->speed = SPEED_100;
+               phydev->duplex = DUPLEX_FULL;
+               phydev->link = 1;
+               netif_carrier_on(phydev->attached_dev);
+       }
+
+       return 0;
+}
+
+static int ip175c_read_status(struct phy_device *phydev)
+{
+       if (phydev->addr == 4) /* WAN port */
+               genphy_read_status(phydev);
+       else
+               /* Don't need to read status for switch ports */
+               phydev->irq = PHY_IGNORE_INTERRUPT;
+
+       return 0;
+}
+
+static int ip175c_config_aneg(struct phy_device *phydev)
+{
+       if (phydev->addr == 4) /* WAN port */
+               genphy_config_aneg(phydev);
+
+       return 0;
+}
+
+static struct phy_driver ip175c_driver = {
+       .phy_id         = 0x02430d80,
+       .name           = "ICPlus IP175C",
+       .phy_id_mask    = 0x0ffffff0,
+       .features       = PHY_BASIC_FEATURES,
+       .config_init    = &ip175c_config_init,
+       .config_aneg    = &ip175c_config_aneg,
+       .read_status    = &ip175c_read_status,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init ip175c_init(void)
+{
+       return phy_driver_register(&ip175c_driver);
+}
+
+static void __exit ip175c_exit(void)
+{
+       phy_driver_unregister(&ip175c_driver);
+}
+
+module_init(ip175c_init);
+module_exit(ip175c_exit);
index b87f8d2a888bb409af90e36a99662c2310ad54d3..fbe1104e9a07aa158c601170bcb63bb16140b1b5 100644 (file)
@@ -60,6 +60,7 @@
 #define MII_M1111_PHY_EXT_SR           0x1b
 #define MII_M1111_HWCFG_MODE_MASK      0xf
 #define MII_M1111_HWCFG_MODE_RGMII     0xb
+#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK      0x4
 
 MODULE_DESCRIPTION("Marvell PHY driver");
 MODULE_AUTHOR("Andy Fleming");
@@ -169,6 +170,21 @@ static int m88e1111_config_init(struct phy_device *phydev)
                        return err;
        }
 
+       if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+               int temp;
+
+               temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+               if (temp < 0)
+                       return temp;
+
+               temp &= ~(MII_M1111_HWCFG_MODE_MASK);
+               temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
+
+               err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+               if (err < 0)
+                       return err;
+       }
+
        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
        if (err < 0)
                return err;
index 585be044ebbbdac47d88b0bb76eeb7e932ea027a..8be8be451ada960037f8521776066b1b33c12a22 100755 (executable)
@@ -2433,37 +2433,22 @@ static int ql_get_seg_count(struct ql3_adapter *qdev,
        return -1;
 }
 
-static void ql_hw_csum_setup(struct sk_buff *skb,
+static void ql_hw_csum_setup(const struct sk_buff *skb,
                             struct ob_mac_iocb_req *mac_iocb_ptr)
 {
-       struct ethhdr *eth;
-       struct iphdr *ip = NULL;
-       u8 offset = ETH_HLEN;
+       const struct iphdr *ip = ip_hdr(skb);
 
-       eth = (struct ethhdr *)(skb->data);
+       mac_iocb_ptr->ip_hdr_off = skb_network_offset(skb);
+       mac_iocb_ptr->ip_hdr_len = ip->ihl;
 
-       if (eth->h_proto == __constant_htons(ETH_P_IP)) {
-               ip = (struct iphdr *)&skb->data[ETH_HLEN];
-       } else if (eth->h_proto == htons(ETH_P_8021Q) &&
-                  ((struct vlan_ethhdr *)skb->data)->
-                  h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
-               ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
-               offset = VLAN_ETH_HLEN;
-       }
-
-       if (ip) {
-               if (ip->protocol == IPPROTO_TCP) {
-                       mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC | 
+       if (ip->protocol == IPPROTO_TCP) {
+               mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC |
                        OB_3032MAC_IOCB_REQ_IC;
-                       mac_iocb_ptr->ip_hdr_off = offset;
-                       mac_iocb_ptr->ip_hdr_len = ip->ihl;
-               } else if (ip->protocol == IPPROTO_UDP) {
-                       mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC | 
+       } else {
+               mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC |
                        OB_3032MAC_IOCB_REQ_IC;
-                       mac_iocb_ptr->ip_hdr_off = offset;
-                       mac_iocb_ptr->ip_hdr_len = ip->ihl;
-               }
        }
+
 }
 
 /*
index 5ec7752caa4806c7a2adb10d898c11e04a39583f..982a9010c7a925e0b2e29b14cbe156d670c57d2b 100644 (file)
@@ -1,53 +1,11 @@
 /*
-=========================================================================
- r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x.
- --------------------------------------------------------------------
-
- History:
- Feb  4 2002   - created initially by ShuChen <shuchen@realtek.com.tw>.
- May 20 2002   - Add link status force-mode and TBI mode support.
-       2004    - Massive updates. See kernel SCM system for details.
-=========================================================================
-  1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
-        Command: 'insmod r8169 media = SET_MEDIA'
-        Ex:      'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
-
-        SET_MEDIA can be:
-               _10_Half        = 0x01
-               _10_Full        = 0x02
-               _100_Half       = 0x04
-               _100_Full       = 0x08
-               _1000_Full      = 0x10
-
-  2. Support TBI mode.
-=========================================================================
-VERSION 1.1    <2002/10/4>
-
-       The bit4:0 of MII register 4 is called "selector field", and have to be
-       00001b to indicate support of IEEE std 802.3 during NWay process of
-       exchanging Link Code Word (FLP).
-
-VERSION 1.2    <2002/11/30>
-
-       - Large style cleanup
-       - Use ether_crc in stock kernel (linux/crc32.h)
-       - Copy mc_filter setup code from 8139cp
-         (includes an optimization, and avoids set_bit use)
-
-VERSION 1.6LK  <2004/04/14>
-
-       - Merge of Realtek's version 1.6
-       - Conversion to DMA API
-       - Suspend/resume
-       - Endianness
-       - Misc Rx/Tx bugs
-
-VERSION 2.2LK  <2005/01/25>
-
-       - RX csum, TX csum/SG, TSO
-       - VLAN
-       - baby (< 7200) Jumbo frames support
-       - Merge of Realtek's version 2.2 (new phy)
+ * r8169.c: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ * See MAINTAINERS file for support contact information.
  */
 
 #include <linux/module.h>
@@ -108,11 +66,6 @@ VERSION 2.2LK       <2005/01/25>
 #define rtl8169_rx_quota(count, quota) count
 #endif
 
-/* media options */
-#define MAX_UNITS 8
-static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static int num_media = 0;
-
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static const int max_interrupt_work = 20;
 
@@ -126,7 +79,7 @@ static const int multicast_filter_limit = 32;
 #define RX_FIFO_THRESH 7       /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
 #define RX_DMA_BURST   6       /* Maximum PCI burst, '6' is 1024 */
 #define TX_DMA_BURST   6       /* Maximum PCI burst, '6' is 1024 */
-#define EarlyTxThld    0x3F    /* 0x3F means NO early transmit */
+#define EarlyTxThld    0x3F    /* 0x3F means NO early transmit */
 #define RxPacketMaxSize        0x3FE8  /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
 #define SafeMtu                0x1c20  /* ... actually life sucks beyond ~7k */
 #define InterFrameGap  0x03    /* 3 means InterFrameGap = the shortest one */
@@ -151,16 +104,17 @@ static const int multicast_filter_limit = 32;
 #define RTL_R32(reg)           ((unsigned long) readl (ioaddr + (reg)))
 
 enum mac_version {
-       RTL_GIGA_MAC_VER_01 = 0x00,
-       RTL_GIGA_MAC_VER_02 = 0x01,
-       RTL_GIGA_MAC_VER_03 = 0x02,
-       RTL_GIGA_MAC_VER_04 = 0x03,
-       RTL_GIGA_MAC_VER_05 = 0x04,
-       RTL_GIGA_MAC_VER_11 = 0x0b,
-       RTL_GIGA_MAC_VER_12 = 0x0c,
-       RTL_GIGA_MAC_VER_13 = 0x0d,
-       RTL_GIGA_MAC_VER_14 = 0x0e,
-       RTL_GIGA_MAC_VER_15 = 0x0f
+       RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+       RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+       RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+       RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+       RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+       RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+       RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+       RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be 8168Bf
+       RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb 8101Ec
+       RTL_GIGA_MAC_VER_14 = 0x0e, // 8101
+       RTL_GIGA_MAC_VER_15 = 0x0f  // 8101
 };
 
 enum phy_version {
@@ -180,11 +134,12 @@ static const struct {
        u8 mac_version;
        u32 RxConfigMask;       /* Clears the bits supported by this chip */
 } rtl_chip_info[] = {
-       _R("RTL8169",           RTL_GIGA_MAC_VER_01, 0xff7e1880),
-       _R("RTL8169s/8110s",    RTL_GIGA_MAC_VER_02, 0xff7e1880),
-       _R("RTL8169s/8110s",    RTL_GIGA_MAC_VER_03, 0xff7e1880),
-       _R("RTL8169sb/8110sb",  RTL_GIGA_MAC_VER_04, 0xff7e1880),
-       _R("RTL8169sc/8110sc",  RTL_GIGA_MAC_VER_05, 0xff7e1880),
+       _R("RTL8169",           RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+       _R("RTL8169s",          RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+       _R("RTL8110s",          RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+       _R("RTL8169sb/8110sb",  RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+       _R("RTL8169sc/8110sc",  RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+       _R("RTL8169sc/8110sc",  RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
        _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
        _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
        _R("RTL8101e",          RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
@@ -199,20 +154,15 @@ enum cfg_version {
        RTL_CFG_2
 };
 
-static const struct {
-       unsigned int region;
-       unsigned int align;
-} rtl_cfg_info[] = {
-       [RTL_CFG_0] = { 1, NET_IP_ALIGN },
-       [RTL_CFG_1] = { 2, NET_IP_ALIGN },
-       [RTL_CFG_2] = { 2, 8 }
-};
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
 
 static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8129), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8136), 0, 0, RTL_CFG_2 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8167), 0, 0, RTL_CFG_0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8168), 0, 0, RTL_CFG_2 },
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8168), 0, 0, RTL_CFG_1 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(0x1259,                    0xc107), 0, 0, RTL_CFG_0 },
@@ -230,62 +180,63 @@ static struct {
        u32 msg_enable;
 } debug = { -1 };
 
-enum RTL8169_registers {
-       MAC0 = 0,               /* Ethernet hardware address. */
-       MAR0 = 8,               /* Multicast filter. */
-       CounterAddrLow = 0x10,
-       CounterAddrHigh = 0x14,
-       TxDescStartAddrLow = 0x20,
-       TxDescStartAddrHigh = 0x24,
-       TxHDescStartAddrLow = 0x28,
-       TxHDescStartAddrHigh = 0x2c,
-       FLASH = 0x30,
-       ERSR = 0x36,
-       ChipCmd = 0x37,
-       TxPoll = 0x38,
-       IntrMask = 0x3C,
-       IntrStatus = 0x3E,
-       TxConfig = 0x40,
-       RxConfig = 0x44,
-       RxMissed = 0x4C,
-       Cfg9346 = 0x50,
-       Config0 = 0x51,
-       Config1 = 0x52,
-       Config2 = 0x53,
-       Config3 = 0x54,
-       Config4 = 0x55,
-       Config5 = 0x56,
-       MultiIntr = 0x5C,
-       PHYAR = 0x60,
-       TBICSR = 0x64,
-       TBI_ANAR = 0x68,
-       TBI_LPAR = 0x6A,
-       PHYstatus = 0x6C,
-       RxMaxSize = 0xDA,
-       CPlusCmd = 0xE0,
-       IntrMitigate = 0xE2,
-       RxDescAddrLow = 0xE4,
-       RxDescAddrHigh = 0xE8,
-       EarlyTxThres = 0xEC,
-       FuncEvent = 0xF0,
-       FuncEventMask = 0xF4,
-       FuncPresetState = 0xF8,
-       FuncForceEvent = 0xFC,
+enum rtl_registers {
+       MAC0            = 0,    /* Ethernet hardware address. */
+       MAC4            = 4,
+       MAR0            = 8,    /* Multicast filter. */
+       CounterAddrLow          = 0x10,
+       CounterAddrHigh         = 0x14,
+       TxDescStartAddrLow      = 0x20,
+       TxDescStartAddrHigh     = 0x24,
+       TxHDescStartAddrLow     = 0x28,
+       TxHDescStartAddrHigh    = 0x2c,
+       FLASH           = 0x30,
+       ERSR            = 0x36,
+       ChipCmd         = 0x37,
+       TxPoll          = 0x38,
+       IntrMask        = 0x3c,
+       IntrStatus      = 0x3e,
+       TxConfig        = 0x40,
+       RxConfig        = 0x44,
+       RxMissed        = 0x4c,
+       Cfg9346         = 0x50,
+       Config0         = 0x51,
+       Config1         = 0x52,
+       Config2         = 0x53,
+       Config3         = 0x54,
+       Config4         = 0x55,
+       Config5         = 0x56,
+       MultiIntr       = 0x5c,
+       PHYAR           = 0x60,
+       TBICSR          = 0x64,
+       TBI_ANAR        = 0x68,
+       TBI_LPAR        = 0x6a,
+       PHYstatus       = 0x6c,
+       RxMaxSize       = 0xda,
+       CPlusCmd        = 0xe0,
+       IntrMitigate    = 0xe2,
+       RxDescAddrLow   = 0xe4,
+       RxDescAddrHigh  = 0xe8,
+       EarlyTxThres    = 0xec,
+       FuncEvent       = 0xf0,
+       FuncEventMask   = 0xf4,
+       FuncPresetState = 0xf8,
+       FuncForceEvent  = 0xfc,
 };
 
-enum RTL8169_register_content {
+enum rtl_register_content {
        /* InterruptStatusBits */
-       SYSErr = 0x8000,
-       PCSTimeout = 0x4000,
-       SWInt = 0x0100,
-       TxDescUnavail = 0x80,
-       RxFIFOOver = 0x40,
-       LinkChg = 0x20,
-       RxOverflow = 0x10,
-       TxErr = 0x08,
-       TxOK = 0x04,
-       RxErr = 0x02,
-       RxOK = 0x01,
+       SYSErr          = 0x8000,
+       PCSTimeout      = 0x4000,
+       SWInt           = 0x0100,
+       TxDescUnavail   = 0x0080,
+       RxFIFOOver      = 0x0040,
+       LinkChg         = 0x0020,
+       RxOverflow      = 0x0010,
+       TxErr           = 0x0008,
+       TxOK            = 0x0004,
+       RxErr           = 0x0002,
+       RxOK            = 0x0001,
 
        /* RxStatusDesc */
        RxFOVF  = (1 << 23),
@@ -295,26 +246,31 @@ enum RTL8169_register_content {
        RxCRC   = (1 << 19),
 
        /* ChipCmdBits */
-       CmdReset = 0x10,
-       CmdRxEnb = 0x08,
-       CmdTxEnb = 0x04,
-       RxBufEmpty = 0x01,
+       CmdReset        = 0x10,
+       CmdRxEnb        = 0x08,
+       CmdTxEnb        = 0x04,
+       RxBufEmpty      = 0x01,
+
+       /* TXPoll register p.5 */
+       HPQ             = 0x80,         /* Poll cmd on the high prio queue */
+       NPQ             = 0x40,         /* Poll cmd on the low prio queue */
+       FSWInt          = 0x01,         /* Forced software interrupt */
 
        /* Cfg9346Bits */
-       Cfg9346_Lock = 0x00,
-       Cfg9346_Unlock = 0xC0,
+       Cfg9346_Lock    = 0x00,
+       Cfg9346_Unlock  = 0xc0,
 
        /* rx_mode_bits */
-       AcceptErr = 0x20,
-       AcceptRunt = 0x10,
-       AcceptBroadcast = 0x08,
-       AcceptMulticast = 0x04,
-       AcceptMyPhys = 0x02,
-       AcceptAllPhys = 0x01,
+       AcceptErr       = 0x20,
+       AcceptRunt      = 0x10,
+       AcceptBroadcast = 0x08,
+       AcceptMulticast = 0x04,
+       AcceptMyPhys    = 0x02,
+       AcceptAllPhys   = 0x01,
 
        /* RxConfigBits */
-       RxCfgFIFOShift = 13,
-       RxCfgDMAShift = 8,
+       RxCfgFIFOShift  = 13,
+       RxCfgDMAShift   =  8,
 
        /* TxConfigBits */
        TxInterFrameGapShift = 24,
@@ -323,6 +279,10 @@ enum RTL8169_register_content {
        /* Config1 register p.24 */
        PMEnable        = (1 << 0),     /* Power Management Enable */
 
+       /* Config2 register p. 25 */
+       PCI_Clock_66MHz = 0x01,
+       PCI_Clock_33MHz = 0x00,
+
        /* Config3 register p.25 */
        MagicPacket     = (1 << 5),     /* Wake up when receives a Magic Packet */
        LinkUp          = (1 << 4),     /* Wake up when the cable connection is re-established */
@@ -343,36 +303,34 @@ enum RTL8169_register_content {
        TBINwComplete   = 0x01000000,
 
        /* CPlusCmd p.31 */
+       PktCntrDisable  = (1 << 7),     // 8168
        RxVlan          = (1 << 6),
        RxChkSum        = (1 << 5),
        PCIDAC          = (1 << 4),
        PCIMulRW        = (1 << 3),
+       INTT_0          = 0x0000,       // 8168
+       INTT_1          = 0x0001,       // 8168
+       INTT_2          = 0x0002,       // 8168
+       INTT_3          = 0x0003,       // 8168
 
        /* rtl8169_PHYstatus */
-       TBI_Enable = 0x80,
-       TxFlowCtrl = 0x40,
-       RxFlowCtrl = 0x20,
-       _1000bpsF = 0x10,
-       _100bps = 0x08,
-       _10bps = 0x04,
-       LinkStatus = 0x02,
-       FullDup = 0x01,
-
-       /* _MediaType */
-       _10_Half = 0x01,
-       _10_Full = 0x02,
-       _100_Half = 0x04,
-       _100_Full = 0x08,
-       _1000_Full = 0x10,
+       TBI_Enable      = 0x80,
+       TxFlowCtrl      = 0x40,
+       RxFlowCtrl      = 0x20,
+       _1000bpsF       = 0x10,
+       _100bps         = 0x08,
+       _10bps          = 0x04,
+       LinkStatus      = 0x02,
+       FullDup         = 0x01,
 
        /* _TBICSRBit */
-       TBILinkOK = 0x02000000,
+       TBILinkOK       = 0x02000000,
 
        /* DumpCounterCommand */
-       CounterDump = 0x8,
+       CounterDump     = 0x8,
 };
 
-enum _DescStatusBit {
+enum desc_status_bit {
        DescOwn         = (1 << 31), /* Descriptor is owned by NIC */
        RingEnd         = (1 << 30), /* End of descriptor ring */
        FirstFrag       = (1 << 29), /* First segment of a packet */
@@ -405,15 +363,15 @@ enum _DescStatusBit {
 #define RsvdMask       0x3fffc000
 
 struct TxDesc {
-       u32 opts1;
-       u32 opts2;
-       u64 addr;
+       __le32 opts1;
+       __le32 opts2;
+       __le64 addr;
 };
 
 struct RxDesc {
-       u32 opts1;
-       u32 opts2;
-       u64 addr;
+       __le32 opts1;
+       __le32 opts2;
+       __le64 addr;
 };
 
 struct ring_info {
@@ -446,6 +404,8 @@ struct rtl8169_private {
        unsigned rx_buf_sz;
        struct timer_list timer;
        u16 cp_cmd;
+       u16 intr_event;
+       u16 napi_event;
        u16 intr_mask;
        int phy_auto_nego_reg;
        int phy_1000_ctrl_reg;
@@ -455,6 +415,7 @@ struct rtl8169_private {
        int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
        void (*get_settings)(struct net_device *, struct ethtool_cmd *);
        void (*phy_reset_enable)(void __iomem *);
+       void (*hw_start)(struct net_device *);
        unsigned int (*phy_reset_pending)(void __iomem *);
        unsigned int (*link_ok)(void __iomem *);
        struct delayed_work task;
@@ -463,8 +424,6 @@ struct rtl8169_private {
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
-module_param_array(media, int, &num_media, 0);
-MODULE_PARM_DESC(media, "force phy operation. Deprecated by ethtool (8).");
 module_param(rx_copybreak, int, 0);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 module_param(use_dac, int, 0);
@@ -478,9 +437,9 @@ static int rtl8169_open(struct net_device *dev);
 static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance);
 static int rtl8169_init_ring(struct net_device *dev);
-static void rtl8169_hw_start(struct net_device *dev);
+static void rtl_hw_start(struct net_device *dev);
 static int rtl8169_close(struct net_device *dev);
-static void rtl8169_set_rx_mode(struct net_device *dev);
+static void rtl_set_rx_mode(struct net_device *dev);
 static void rtl8169_tx_timeout(struct net_device *dev);
 static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
 static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
@@ -493,35 +452,37 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp);
 static int rtl8169_poll(struct net_device *dev, int *budget);
 #endif
 
-static const u16 rtl8169_intr_mask =
-       SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
-static const u16 rtl8169_napi_event =
-       RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
 static const unsigned int rtl8169_rx_config =
        (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
-static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
+static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
 {
        int i;
 
-       RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+       RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0xFF) << 16 | value);
 
        for (i = 20; i > 0; i--) {
-               /* Check if the RTL8169 has completed writing to the specified MII register */
+               /*
+                * Check if the RTL8169 has completed writing to the specified
+                * MII register.
+                */
                if (!(RTL_R32(PHYAR) & 0x80000000))
                        break;
                udelay(25);
        }
 }
 
-static int mdio_read(void __iomem *ioaddr, int RegAddr)
+static int mdio_read(void __iomem *ioaddr, int reg_addr)
 {
        int i, value = -1;
 
-       RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+       RTL_W32(PHYAR, 0x0 | (reg_addr & 0xFF) << 16);
 
        for (i = 20; i > 0; i--) {
-               /* Check if the RTL8169 has completed retrieving data from the specified MII register */
+               /*
+                * Check if the RTL8169 has completed retrieving data from
+                * the specified MII register.
+                */
                if (RTL_R32(PHYAR) & 0x80000000) {
                        value = (int) (RTL_R32(PHYAR) & 0xFFFF);
                        break;
@@ -579,7 +540,8 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
 }
 
 static void rtl8169_check_link_status(struct net_device *dev,
-                                     struct rtl8169_private *tp, void __iomem *ioaddr)
+                                     struct rtl8169_private *tp,
+                                     void __iomem *ioaddr)
 {
        unsigned long flags;
 
@@ -596,38 +558,6 @@ static void rtl8169_check_link_status(struct net_device *dev,
        spin_unlock_irqrestore(&tp->lock, flags);
 }
 
-static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
-{
-       struct {
-               u16 speed;
-               u8 duplex;
-               u8 autoneg;
-               u8 media;
-       } link_settings[] = {
-               { SPEED_10,     DUPLEX_HALF, AUTONEG_DISABLE,   _10_Half },
-               { SPEED_10,     DUPLEX_FULL, AUTONEG_DISABLE,   _10_Full },
-               { SPEED_100,    DUPLEX_HALF, AUTONEG_DISABLE,   _100_Half },
-               { SPEED_100,    DUPLEX_FULL, AUTONEG_DISABLE,   _100_Full },
-               { SPEED_1000,   DUPLEX_FULL, AUTONEG_DISABLE,   _1000_Full },
-               /* Make TBI happy */
-               { SPEED_1000,   DUPLEX_FULL, AUTONEG_ENABLE,    0xff }
-       }, *p;
-       unsigned char option;
-
-       option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
-
-       if ((option != 0xff) && !idx && netif_msg_drv(&debug))
-               printk(KERN_WARNING PFX "media option is deprecated.\n");
-
-       for (p = link_settings; p->media != 0xff; p++) {
-               if (p->media == option)
-                       break;
-       }
-       *autoneg = p->autoneg;
-       *speed = p->speed;
-       *duplex = p->duplex;
-}
-
 static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -667,7 +597,7 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       int i;
+       unsigned int i;
        static struct {
                u32 opt;
                u16 reg;
@@ -893,8 +823,7 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
        int ret;
 
        if (tp->vlgrp && (opts2 & RxVlanTag)) {
-               rtl8169_rx_hwaccel_skb(skb, tp->vlgrp,
-                                      swab16(opts2 & 0xffff));
+               rtl8169_rx_hwaccel_skb(skb, tp->vlgrp, swab16(opts2 & 0xffff));
                ret = 0;
        } else
                ret = -1;
@@ -1115,7 +1044,6 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
        }
 }
 
-
 static const struct ethtool_ops rtl8169_ethtool_ops = {
        .get_drvinfo            = rtl8169_get_drvinfo,
        .get_regs_len           = rtl8169_get_regs_len,
@@ -1141,8 +1069,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
        .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
-static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum,
-                                      int bitval)
+static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg,
+                                      int bitnum, int bitval)
 {
        int val;
 
@@ -1152,8 +1080,20 @@ static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum
        mdio_write(ioaddr, reg, val & 0xffff);
 }
 
-static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr)
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+                                   void __iomem *ioaddr)
 {
+       /*
+        * The driver currently handles the 8168Bf and the 8168Be identically
+        * but they can be identified more specifically through the test below
+        * if needed:
+        *
+        * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+        *
+        * Same thing for the 8101Eb and the 8101Ec:
+        *
+        * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
+        */
        const struct {
                u32 mask;
                int mac_version;
@@ -1163,6 +1103,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *io
                { 0x34000000,   RTL_GIGA_MAC_VER_13 },
                { 0x30800000,   RTL_GIGA_MAC_VER_14 },
                { 0x30000000,   RTL_GIGA_MAC_VER_11 },
+               { 0x98000000,   RTL_GIGA_MAC_VER_06 },
                { 0x18000000,   RTL_GIGA_MAC_VER_05 },
                { 0x10000000,   RTL_GIGA_MAC_VER_04 },
                { 0x04000000,   RTL_GIGA_MAC_VER_03 },
@@ -1171,7 +1112,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *io
        }, *p = mac_info;
        u32 reg;
 
-       reg = RTL_R32(TxConfig) & 0x7c800000;
+       reg = RTL_R32(TxConfig) & 0xfc800000;
        while ((reg & p->mask) != p->mask)
                p++;
        tp->mac_version = p->mac_version;
@@ -1182,7 +1123,8 @@ static void rtl8169_print_mac_version(struct rtl8169_private *tp)
        dprintk("mac_version = 0x%02x\n", tp->mac_version);
 }
 
-static void rtl8169_get_phy_version(struct rtl8169_private *tp, void __iomem *ioaddr)
+static void rtl8169_get_phy_version(struct rtl8169_private *tp,
+                                   void __iomem *ioaddr)
 {
        const struct {
                u16 mask;
@@ -1259,7 +1201,7 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
                  0xbf00 }      //w 0 15 0 bf00
                }
        }, *p = phy_magic;
-       int i;
+       unsigned int i;
 
        rtl8169_print_mac_version(tp);
        rtl8169_print_phy_version(tp);
@@ -1393,7 +1335,7 @@ static void rtl8169_phy_reset(struct net_device *dev,
                              struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       int i;
+       unsigned int i;
 
        tp->phy_reset_enable(ioaddr);
        for (i = 0; i < 100; i++) {
@@ -1408,21 +1350,16 @@ static void rtl8169_phy_reset(struct net_device *dev,
 static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       static int board_idx = -1;
-       u8 autoneg, duplex;
-       u16 speed;
-
-       board_idx++;
 
        rtl8169_hw_phy_config(dev);
 
        dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
        RTL_W8(0x82, 0x01);
 
-       if (tp->mac_version < RTL_GIGA_MAC_VER_03) {
-               dprintk("Set PCI Latency=0x40\n");
-               pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
-       }
+       pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+               pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
 
        if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
                dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
@@ -1431,16 +1368,52 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
                mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
        }
 
-       rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
-
        rtl8169_phy_reset(dev, tp);
 
-       rtl8169_set_speed(dev, autoneg, speed, duplex);
+       /*
+        * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+        * only 8101. Don't panic.
+        */
+       rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
 
        if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
                printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
 }
 
+static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       u32 high;
+       u32 low;
+
+       low  = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
+       high = addr[4] | (addr[5] << 8);
+
+       spin_lock_irq(&tp->lock);
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+       RTL_W32(MAC0, low);
+       RTL_W32(MAC4, high);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       spin_unlock_irq(&tp->lock);
+}
+
+static int rtl_set_mac_address(struct net_device *dev, void *p)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       rtl_rar_set(tp, dev->dev_addr);
+
+       return 0;
+}
+
 static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -1467,15 +1440,49 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EOPNOTSUPP;
 }
 
+static const struct rtl_cfg_info {
+       void (*hw_start)(struct net_device *);
+       unsigned int region;
+       unsigned int align;
+       u16 intr_event;
+       u16 napi_event;
+} rtl_cfg_infos [] = {
+       [RTL_CFG_0] = {
+               .hw_start       = rtl_hw_start_8169,
+               .region         = 1,
+               .align          = 0,
+               .intr_event     = SYSErr | LinkChg | RxOverflow |
+                                 RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+       },
+       [RTL_CFG_1] = {
+               .hw_start       = rtl_hw_start_8168,
+               .region         = 2,
+               .align          = 8,
+               .intr_event     = SYSErr | LinkChg | RxOverflow |
+                                 TxErr | TxOK | RxOK | RxErr,
+               .napi_event     = TxErr | TxOK | RxOK | RxOverflow
+       },
+       [RTL_CFG_2] = {
+               .hw_start       = rtl_hw_start_8101,
+               .region         = 2,
+               .align          = 8,
+               .intr_event     = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+                                 RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+       }
+};
+
 static int __devinit
 rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       const unsigned int region = rtl_cfg_info[ent->driver_data].region;
+       const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
+       const unsigned int region = cfg->region;
        struct rtl8169_private *tp;
        struct net_device *dev;
        void __iomem *ioaddr;
-       unsigned int pm_cap;
-       int i, rc;
+       unsigned int i;
+       int rc;
 
        if (netif_msg_drv(&debug)) {
                printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
@@ -1508,20 +1515,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc < 0)
                goto err_out_disable_2;
 
-       /* save power state before pci_enable_device overwrites it */
-       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pm_cap) {
-               u16 pwr_command, acpi_idle_state;
-
-               pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
-               acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
-       } else {
-               if (netif_msg_probe(tp)) {
-                       dev_err(&pdev->dev,
-                               "PowerManagement capability not found.\n");
-               }
-       }
-
        /* make sure PCI base addr 1 is MMIO */
        if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
                if (netif_msg_probe(tp)) {
@@ -1585,7 +1578,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        RTL_W8(ChipCmd, CmdReset);
 
        /* Check that the chip has finished the reset. */
-       for (i = 100; i > 0; i--) {
+       for (i = 0; i < 100; i++) {
                if ((RTL_R8(ChipCmd) & CmdReset) == 0)
                        break;
                msleep_interruptible(1);
@@ -1647,11 +1640,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
        dev->stop = rtl8169_close;
        dev->tx_timeout = rtl8169_tx_timeout;
-       dev->set_multicast_list = rtl8169_set_rx_mode;
+       dev->set_multicast_list = rtl_set_rx_mode;
        dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
        dev->irq = pdev->irq;
        dev->base_addr = (unsigned long) ioaddr;
        dev->change_mtu = rtl8169_change_mtu;
+       dev->set_mac_address = rtl_set_mac_address;
 
 #ifdef CONFIG_R8169_NAPI
        dev->poll = rtl8169_poll;
@@ -1670,7 +1664,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->intr_mask = 0xffff;
        tp->pci_dev = pdev;
        tp->mmio_addr = ioaddr;
-       tp->align = rtl_cfg_info[ent->driver_data].align;
+       tp->align = cfg->align;
+       tp->hw_start = cfg->hw_start;
+       tp->intr_event = cfg->intr_event;
+       tp->napi_event = cfg->napi_event;
 
        init_timer(&tp->timer);
        tp->timer.data = (unsigned long) dev;
@@ -1685,15 +1682,17 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_drvdata(pdev, dev);
 
        if (netif_msg_probe(tp)) {
+               u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff;
+
                printk(KERN_INFO "%s: %s at 0x%lx, "
                       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-                      "IRQ %d\n",
+                      "XID %08x IRQ %d\n",
                       dev->name,
                       rtl_chip_info[tp->chipset].name,
                       dev->base_addr,
                       dev->dev_addr[0], dev->dev_addr[1],
                       dev->dev_addr[2], dev->dev_addr[3],
-                      dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+                      dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq);
        }
 
        rtl8169_init_phy(dev, tp);
@@ -1714,15 +1713,11 @@ err_out_free_dev_1:
        goto out;
 }
 
-static void __devexit
-rtl8169_remove_one(struct pci_dev *pdev)
+static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rtl8169_private *tp = netdev_priv(dev);
 
-       assert(dev != NULL);
-       assert(tp != NULL);
-
        flush_scheduled_work();
 
        unregister_netdev(dev);
@@ -1774,7 +1769,7 @@ static int rtl8169_open(struct net_device *dev)
        if (retval < 0)
                goto err_release_ring_2;
 
-       rtl8169_hw_start(dev);
+       rtl_hw_start(dev);
 
        rtl8169_request_timer(dev);
 
@@ -1805,7 +1800,7 @@ static void rtl8169_hw_reset(void __iomem *ioaddr)
        RTL_R8(ChipCmd);
 }
 
-static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp)
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
        u32 cfg = rtl8169_rx_config;
@@ -1818,45 +1813,90 @@ static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp)
                (InterFrameGap << TxInterFrameGapShift));
 }
 
-static void rtl8169_hw_start(struct net_device *dev)
+static void rtl_hw_start(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       struct pci_dev *pdev = tp->pci_dev;
-       u16 cmd;
-       u32 i;
+       unsigned int i;
 
        /* Soft reset the chip. */
        RTL_W8(ChipCmd, CmdReset);
 
        /* Check that the chip has finished the reset. */
-       for (i = 100; i > 0; i--) {
+       for (i = 0; i < 100; i++) {
                if ((RTL_R8(ChipCmd) & CmdReset) == 0)
                        break;
                msleep_interruptible(1);
        }
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
-               RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
-               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
-       }
+       tp->hw_start(dev);
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
-               pci_write_config_word(pdev, 0x68, 0x00);
-               pci_write_config_word(pdev, 0x69, 0x08);
-       }
+       netif_start_queue(dev);
+}
 
-       /* Undocumented stuff. */
-       if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
-               /* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */
-               if ((RTL_R8(Config2) & 0x07) & 0x01)
-                       RTL_W32(0x7c, 0x0007ffff);
 
-               RTL_W32(0x7c, 0x0007ff00);
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+                                        void __iomem *ioaddr)
+{
+       /*
+        * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+        * register to be written before TxDescAddrLow to work.
+        * Switching from MMIO to I/O access fixes the issue as well.
+        */
+       RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
+       RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
+       RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
+       RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
+}
+
+static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
+{
+       u16 cmd;
+
+       cmd = RTL_R16(CPlusCmd);
+       RTL_W16(CPlusCmd, cmd);
+       return cmd;
+}
+
+static void rtl_set_rx_max_size(void __iomem *ioaddr)
+{
+       /* Low hurts. Let's disable the filtering. */
+       RTL_W16(RxMaxSize, 16383);
+}
+
+static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
+{
+       struct {
+               u32 mac_version;
+               u32 clk;
+               u32 val;
+       } cfg2_info [] = {
+               { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+               { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+               { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+               { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+       }, *p = cfg2_info;
+       unsigned int i;
+       u32 clk;
 
-               pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-               cmd = cmd & 0xef;
-               pci_write_config_word(pdev, PCI_COMMAND, cmd);
+       clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+       for (i = 0; i < ARRAY_SIZE(cfg2_info); i++) {
+               if ((p->mac_version == mac_version) && (p->clk == clk)) {
+                       RTL_W32(0x7c, p->val);
+                       break;
+               }
+       }
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+
+       if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+               RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
        }
 
        RTL_W8(Cfg9346, Cfg9346_Unlock);
@@ -1868,19 +1908,11 @@ static void rtl8169_hw_start(struct net_device *dev)
 
        RTL_W8(EarlyTxThres, EarlyTxThld);
 
-       /* Low hurts. Let's disable the filtering. */
-       RTL_W16(RxMaxSize, 16383);
-
-       if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_04))
-               rtl8169_set_rx_tx_config_registers(tp);
+       rtl_set_rx_max_size(ioaddr);
 
-       cmd = RTL_R16(CPlusCmd);
-       RTL_W16(CPlusCmd, cmd);
+       rtl_set_rx_tx_config_registers(tp);
 
-       tp->cp_cmd |= cmd | PCIMulRW;
+       tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
 
        if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
@@ -1891,29 +1923,15 @@ static void rtl8169_hw_start(struct net_device *dev)
 
        RTL_W16(CPlusCmd, tp->cp_cmd);
 
+       rtl8169_set_magic_reg(ioaddr, tp->mac_version);
+
        /*
         * Undocumented corner. Supposedly:
         * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
         */
        RTL_W16(IntrMitigate, 0x0000);
 
-       /*
-        * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
-        * register to be written before TxDescAddrLow to work.
-        * Switching from MMIO to I/O access fixes the issue as well.
-        */
-       RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32));
-       RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
-       RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32));
-       RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
-
-       if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
-           (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
-           (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
-           (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
-               RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
-               rtl8169_set_rx_tx_config_registers(tp);
-       }
+       rtl_set_rx_tx_desc_registers(tp, ioaddr);
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
@@ -1922,15 +1940,107 @@ static void rtl8169_hw_start(struct net_device *dev)
 
        RTL_W32(RxMissed, 0);
 
-       rtl8169_set_rx_mode(dev);
+       rtl_set_rx_mode(dev);
 
        /* no early-rx interrupts */
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       RTL_W16(IntrMask, rtl8169_intr_mask);
+       RTL_W16(IntrMask, tp->intr_event);
 
-       netif_start_queue(dev);
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+       u8 ctl;
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       rtl_set_rx_max_size(ioaddr);
+
+       rtl_set_rx_tx_config_registers(tp);
+
+       tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+       RTL_W16(CPlusCmd, tp->cp_cmd);
+
+       /* Tx performance tweak. */
+       pci_read_config_byte(pdev, 0x69, &ctl);
+       ctl = (ctl & ~0x70) | 0x50;
+       pci_write_config_byte(pdev, 0x69, ctl);
+
+       RTL_W16(IntrMitigate, 0x5151);
+
+       /* Work around for RxFIFO overflow. */
+       if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+               tp->intr_event |= RxFIFOOver | PCSTimeout;
+               tp->intr_event &= ~RxOverflow;
+       }
+
+       rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       RTL_R8(IntrMask);
+
+       RTL_W32(RxMissed, 0);
+
+       rtl_set_rx_mode(dev);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+       RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+       RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+
+       if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
+               pci_write_config_word(pdev, 0x68, 0x00);
+               pci_write_config_word(pdev, 0x69, 0x08);
+       }
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       rtl_set_rx_max_size(ioaddr);
+
+       tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+       RTL_W16(CPlusCmd, tp->cp_cmd);
+
+       RTL_W16(IntrMitigate, 0x0000);
+
+       rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+       rtl_set_rx_tx_config_registers(tp);
+
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       RTL_R8(IntrMask);
+
+       RTL_W32(RxMissed, 0);
+
+       rtl_set_rx_mode(dev);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+       RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+       RTL_W16(IntrMask, tp->intr_event);
 }
 
 static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
@@ -1956,7 +2066,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
 
        netif_poll_enable(dev);
 
-       rtl8169_hw_start(dev);
+       rtl_hw_start(dev);
 
        rtl8169_request_timer(dev);
 
@@ -1997,38 +2107,38 @@ static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
        rtl8169_mark_to_asic(desc, rx_buf_sz);
 }
 
-static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
-                               struct RxDesc *desc, int rx_buf_sz,
-                               unsigned int align)
+static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev,
+                                           struct net_device *dev,
+                                           struct RxDesc *desc, int rx_buf_sz,
+                                           unsigned int align)
 {
        struct sk_buff *skb;
        dma_addr_t mapping;
-       int ret = 0;
+       unsigned int pad;
 
-       skb = dev_alloc_skb(rx_buf_sz + align);
+       pad = align ? align : NET_IP_ALIGN;
+
+       skb = netdev_alloc_skb(dev, rx_buf_sz + pad);
        if (!skb)
                goto err_out;
 
-       skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
-       *sk_buff = skb;
+       skb_reserve(skb, align ? ((pad - 1) & (unsigned long)skb->data) : pad);
 
        mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
                                 PCI_DMA_FROMDEVICE);
 
        rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
-
 out:
-       return ret;
+       return skb;
 
 err_out:
-       ret = -ENOMEM;
        rtl8169_make_unusable_by_asic(desc);
        goto out;
 }
 
 static void rtl8169_rx_clear(struct rtl8169_private *tp)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < NUM_RX_DESC; i++) {
                if (tp->Rx_skbuff[i]) {
@@ -2043,16 +2153,22 @@ static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
 {
        u32 cur;
 
-       for (cur = start; end - cur > 0; cur++) {
-               int ret, i = cur % NUM_RX_DESC;
+       for (cur = start; end - cur != 0; cur++) {
+               struct sk_buff *skb;
+               unsigned int i = cur % NUM_RX_DESC;
+
+               WARN_ON((s32)(end - cur) < 0);
 
                if (tp->Rx_skbuff[i])
                        continue;
 
-               ret = rtl8169_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
-                       tp->RxDescArray + i, tp->rx_buf_sz, tp->align);
-               if (ret < 0)
+               skb = rtl8169_alloc_rx_skb(tp->pci_dev, dev,
+                                          tp->RxDescArray + i,
+                                          tp->rx_buf_sz, tp->align);
+               if (!skb)
                        break;
+
+               tp->Rx_skbuff[i] = skb;
        }
        return cur - start;
 }
@@ -2164,14 +2280,9 @@ static void rtl8169_reinit_task(struct work_struct *work)
 
        ret = rtl8169_open(dev);
        if (unlikely(ret < 0)) {
-               if (net_ratelimit()) {
-                       struct rtl8169_private *tp = netdev_priv(dev);
-
-                       if (netif_msg_drv(tp)) {
-                               printk(PFX KERN_ERR
-                                      "%s: reinit failure (status = %d)."
-                                      " Rescheduling.\n", dev->name, ret);
-                       }
+               if (net_ratelimit() && netif_msg_drv(tp)) {
+                       printk(PFX KERN_ERR "%s: reinit failure (status = %d)."
+                              " Rescheduling.\n", dev->name, ret);
                }
                rtl8169_schedule_work(dev, rtl8169_reinit_task);
        }
@@ -2198,16 +2309,12 @@ static void rtl8169_reset_task(struct work_struct *work)
 
        if (tp->dirty_rx == tp->cur_rx) {
                rtl8169_init_ring_indexes(tp);
-               rtl8169_hw_start(dev);
+               rtl_hw_start(dev);
                netif_wake_queue(dev);
        } else {
-               if (net_ratelimit()) {
-                       struct rtl8169_private *tp = netdev_priv(dev);
-
-                       if (netif_msg_intr(tp)) {
-                               printk(PFX KERN_EMERG
-                                      "%s: Rx buffers shortage\n", dev->name);
-                       }
+               if (net_ratelimit() && netif_msg_intr(tp)) {
+                       printk(PFX KERN_EMERG "%s: Rx buffers shortage\n",
+                              dev->name);
                }
                rtl8169_schedule_work(dev, rtl8169_reset_task);
        }
@@ -2344,7 +2451,7 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        smp_wmb();
 
-       RTL_W8(TxPoll, 0x40);   /* set polling bit */
+       RTL_W8(TxPoll, NPQ);    /* set polling bit */
 
        if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
                netif_stop_queue(dev);
@@ -2414,16 +2521,12 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
        rtl8169_schedule_work(dev, rtl8169_reinit_task);
 }
 
-static void
-rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
-                    void __iomem *ioaddr)
+static void rtl8169_tx_interrupt(struct net_device *dev,
+                                struct rtl8169_private *tp,
+                                void __iomem *ioaddr)
 {
        unsigned int dirty_tx, tx_left;
 
-       assert(dev != NULL);
-       assert(tp != NULL);
-       assert(ioaddr != NULL);
-
        dirty_tx = tp->dirty_tx;
        smp_rmb();
        tx_left = tp->cur_tx - dirty_tx;
@@ -2480,38 +2583,37 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
                skb->ip_summed = CHECKSUM_NONE;
 }
 
-static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
-                                     struct RxDesc *desc, int rx_buf_sz,
-                                     unsigned int align)
+static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
+                                      struct rtl8169_private *tp, int pkt_size,
+                                      dma_addr_t addr)
 {
-       int ret = -1;
+       struct sk_buff *skb;
+       bool done = false;
 
-       if (pkt_size < rx_copybreak) {
-               struct sk_buff *skb;
+       if (pkt_size >= rx_copybreak)
+               goto out;
 
-               skb = dev_alloc_skb(pkt_size + align);
-               if (skb) {
-                       skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
-                       eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
-                       *sk_buff = skb;
-                       rtl8169_mark_to_asic(desc, rx_buf_sz);
-                       ret = 0;
-               }
-       }
-       return ret;
+       skb = netdev_alloc_skb(tp->dev, pkt_size + NET_IP_ALIGN);
+       if (!skb)
+               goto out;
+
+       pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size,
+                                   PCI_DMA_FROMDEVICE);
+       skb_reserve(skb, NET_IP_ALIGN);
+       skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size);
+       *sk_buff = skb;
+       done = true;
+out:
+       return done;
 }
 
-static int
-rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
-                    void __iomem *ioaddr)
+static int rtl8169_rx_interrupt(struct net_device *dev,
+                               struct rtl8169_private *tp,
+                               void __iomem *ioaddr)
 {
        unsigned int cur_rx, rx_left;
        unsigned int delta, count;
 
-       assert(dev != NULL);
-       assert(tp != NULL);
-       assert(ioaddr != NULL);
-
        cur_rx = tp->cur_rx;
        rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
        rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
@@ -2544,9 +2646,9 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
                        rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
                } else {
                        struct sk_buff *skb = tp->Rx_skbuff[entry];
+                       dma_addr_t addr = le64_to_cpu(desc->addr);
                        int pkt_size = (status & 0x00001FFF) - 4;
-                       void (*pci_action)(struct pci_dev *, dma_addr_t,
-                               size_t, int) = pci_dma_sync_single_for_device;
+                       struct pci_dev *pdev = tp->pci_dev;
 
                        /*
                         * The driver does not support incoming fragmented
@@ -2562,19 +2664,16 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 
                        rtl8169_rx_csum(skb, desc);
 
-                       pci_dma_sync_single_for_cpu(tp->pci_dev,
-                               le64_to_cpu(desc->addr), tp->rx_buf_sz,
-                               PCI_DMA_FROMDEVICE);
-
-                       if (rtl8169_try_rx_copy(&skb, pkt_size, desc,
-                                               tp->rx_buf_sz, tp->align)) {
-                               pci_action = pci_unmap_single;
+                       if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) {
+                               pci_dma_sync_single_for_device(pdev, addr,
+                                       pkt_size, PCI_DMA_FROMDEVICE);
+                               rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+                       } else {
+                               pci_unmap_single(pdev, addr, pkt_size,
+                                                PCI_DMA_FROMDEVICE);
                                tp->Rx_skbuff[entry] = NULL;
                        }
 
-                       pci_action(tp->pci_dev, le64_to_cpu(desc->addr),
-                                  tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
                        skb_put(skb, pkt_size);
                        skb->protocol = eth_type_trans(skb, dev);
 
@@ -2585,6 +2684,13 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
                        tp->stats.rx_bytes += pkt_size;
                        tp->stats.rx_packets++;
                }
+
+               /* Work around for AMD plateform. */
+               if ((desc->opts2 & 0xfffe000) &&
+                   (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
+                       desc->opts2 = 0;
+                       cur_rx++;
+               }
        }
 
        count = cur_rx - tp->cur_rx;
@@ -2608,11 +2714,9 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
        return count;
 }
 
-/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
-static irqreturn_t
-rtl8169_interrupt(int irq, void *dev_instance)
+static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
 {
-       struct net_device *dev = (struct net_device *) dev_instance;
+       struct net_device *dev = dev_instance;
        struct rtl8169_private *tp = netdev_priv(dev);
        int boguscnt = max_interrupt_work;
        void __iomem *ioaddr = tp->mmio_addr;
@@ -2637,9 +2741,17 @@ rtl8169_interrupt(int irq, void *dev_instance)
                RTL_W16(IntrStatus,
                        (status & RxFIFOOver) ? (status | RxOverflow) : status);
 
-               if (!(status & rtl8169_intr_mask))
+               if (!(status & tp->intr_event))
                        break;
 
+                /* Work around for rx fifo overflow */
+                if (unlikely(status & RxFIFOOver) &&
+                   (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+                       netif_stop_queue(dev);
+                       rtl8169_tx_timeout(dev);
+                       break;
+               }
+
                if (unlikely(status & SYSErr)) {
                        rtl8169_pcierr_interrupt(dev);
                        break;
@@ -2649,8 +2761,8 @@ rtl8169_interrupt(int irq, void *dev_instance)
                        rtl8169_check_link_status(dev, tp, ioaddr);
 
 #ifdef CONFIG_R8169_NAPI
-               RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event);
-               tp->intr_mask = ~rtl8169_napi_event;
+               RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+               tp->intr_mask = ~tp->napi_event;
 
                if (likely(netif_rx_schedule_prep(dev)))
                        __netif_rx_schedule(dev);
@@ -2661,9 +2773,9 @@ rtl8169_interrupt(int irq, void *dev_instance)
                break;
 #else
                /* Rx interrupt */
-               if (status & (RxOK | RxOverflow | RxFIFOOver)) {
+               if (status & (RxOK | RxOverflow | RxFIFOOver))
                        rtl8169_rx_interrupt(dev, tp, ioaddr);
-               }
+
                /* Tx interrupt */
                if (status & (TxOK | TxErr))
                        rtl8169_tx_interrupt(dev, tp, ioaddr);
@@ -2707,7 +2819,7 @@ static int rtl8169_poll(struct net_device *dev, int *budget)
                 * write is safe - FR
                 */
                smp_wmb();
-               RTL_W16(IntrMask, rtl8169_intr_mask);
+               RTL_W16(IntrMask, tp->intr_event);
        }
 
        return (work_done >= work_to_do);
@@ -2789,14 +2901,13 @@ static int rtl8169_close(struct net_device *dev)
        return 0;
 }
 
-static void
-rtl8169_set_rx_mode(struct net_device *dev)
+static void rtl_set_rx_mode(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
        unsigned long flags;
        u32 mc_filter[2];       /* Multicast hash filter */
-       int i, rx_mode;
+       int rx_mode;
        u32 tmp = 0;
 
        if (dev->flags & IFF_PROMISC) {
@@ -2816,6 +2927,8 @@ rtl8169_set_rx_mode(struct net_device *dev)
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
                struct dev_mc_list *mclist;
+               unsigned int i;
+
                rx_mode = AcceptBroadcast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
                for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -2840,10 +2953,11 @@ rtl8169_set_rx_mode(struct net_device *dev)
                mc_filter[1] = 0xffffffff;
        }
 
-       RTL_W32(RxConfig, tmp);
        RTL_W32(MAR0 + 0, mc_filter[0]);
        RTL_W32(MAR0 + 4, mc_filter[1]);
 
+       RTL_W32(RxConfig, tmp);
+
        spin_unlock_irqrestore(&tp->lock, flags);
 }
 
@@ -2931,14 +3045,12 @@ static struct pci_driver rtl8169_pci_driver = {
 #endif
 };
 
-static int __init
-rtl8169_init_module(void)
+static int __init rtl8169_init_module(void)
 {
        return pci_register_driver(&rtl8169_pci_driver);
 }
 
-static void __exit
-rtl8169_cleanup_module(void)
+static void __exit rtl8169_cleanup_module(void)
 {
        pci_unregister_driver(&rtl8169_pci_driver);
 }
index 09078ff84cd2f20478373d8a93a1ec4db8ce5e66..2d826fff7e2e9270c7dac931172ac2c726f6eae3 100644 (file)
@@ -469,11 +469,18 @@ static struct pci_device_id s2io_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, s2io_tbl);
 
+static struct pci_error_handlers s2io_err_handler = {
+       .error_detected = s2io_io_error_detected,
+       .slot_reset = s2io_io_slot_reset,
+       .resume = s2io_io_resume,
+};
+
 static struct pci_driver s2io_driver = {
       .name = "S2IO",
       .id_table = s2io_tbl,
       .probe = s2io_init_nic,
       .remove = __devexit_p(s2io_rem_nic),
+      .err_handler = &s2io_err_handler,
 };
 
 /* A simplifier macro used both by init and free shared_mem Fns(). */
@@ -2689,6 +2696,9 @@ static void s2io_netpoll(struct net_device *dev)
        u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
        int i;
 
+       if (pci_channel_offline(nic->pdev))
+               return;
+
        disable_irq(dev->irq);
 
        atomic_inc(&nic->isr_cnt);
@@ -3215,6 +3225,8 @@ static void alarm_intr_handler(struct s2io_nic *nic)
        int i;
        if (atomic_read(&nic->card_state) == CARD_DOWN)
                return;
+       if (pci_channel_offline(nic->pdev))
+               return;
        nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
        /* Handling the XPAK counters update */
        if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3958,7 +3970,6 @@ static int s2io_close(struct net_device *dev)
        /* Reset card, kill tasklet and free Tx and Rx buffers. */
        s2io_card_down(sp);
 
-       sp->device_close_flag = TRUE;   /* Device is shut down. */
        return 0;
 }
 
@@ -4314,6 +4325,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
        struct mac_info *mac_control;
        struct config_param *config;
 
+       /* Pretend we handled any irq's from a disconnected card */
+       if (pci_channel_offline(sp->pdev))
+               return IRQ_NONE;
+
        atomic_inc(&sp->isr_cnt);
        mac_control = &sp->mac_control;
        config = &sp->config;
@@ -6569,7 +6584,7 @@ static void s2io_rem_isr(struct s2io_nic * sp)
        } while(cnt < 5);
 }
 
-static void s2io_card_down(struct s2io_nic * sp)
+static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
 {
        int cnt = 0;
        struct XENA_dev_config __iomem *bar0 = sp->bar0;
@@ -6584,7 +6599,8 @@ static void s2io_card_down(struct s2io_nic * sp)
        atomic_set(&sp->card_state, CARD_DOWN);
 
        /* disable Tx and Rx traffic on the NIC */
-       stop_nic(sp);
+       if (do_io)
+               stop_nic(sp);
 
        s2io_rem_isr(sp);
 
@@ -6592,7 +6608,7 @@ static void s2io_card_down(struct s2io_nic * sp)
        tasklet_kill(&sp->task);
 
        /* Check if the device is Quiescent and then Reset the NIC */
-       do {
+       while(do_io) {
                /* As per the HW requirement we need to replenish the
                 * receive buffer to avoid the ring bump. Since there is
                 * no intention of processing the Rx frame at this pointwe are
@@ -6617,8 +6633,9 @@ static void s2io_card_down(struct s2io_nic * sp)
                                  (unsigned long long) val64);
                        break;
                }
-       } while (1);
-       s2io_reset(sp);
+       }
+       if (do_io)
+               s2io_reset(sp);
 
        spin_lock_irqsave(&sp->tx_lock, flags);
        /* Free all Tx buffers */
@@ -6633,6 +6650,11 @@ static void s2io_card_down(struct s2io_nic * sp)
        clear_bit(0, &(sp->link_state));
 }
 
+static void s2io_card_down(struct s2io_nic * sp)
+{
+       do_s2io_card_down(sp, 1);
+}
+
 static int s2io_card_up(struct s2io_nic * sp)
 {
        int i, ret = 0;
@@ -8010,3 +8032,85 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
        sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
        return;
 }
+
+/**
+ * s2io_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
+                                               pci_channel_state_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct s2io_nic *sp = netdev->priv;
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev)) {
+               /* Bring down the card, while avoiding PCI I/O */
+               do_s2io_card_down(sp, 0);
+       }
+       pci_disable_device(pdev);
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * s2io_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ * At this point, the card has exprienced a hard reset,
+ * followed by fixups by BIOS, and has its config space
+ * set up identically to what it was at cold boot.
+ */
+static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct s2io_nic *sp = netdev->priv;
+
+       if (pci_enable_device(pdev)) {
+               printk(KERN_ERR "s2io: "
+                      "Cannot re-enable PCI device after reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       pci_set_master(pdev);
+       s2io_reset(sp);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * s2io_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells
+ * us that its OK to resume normal operation.
+ */
+static void s2io_io_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct s2io_nic *sp = netdev->priv;
+
+       if (netif_running(netdev)) {
+               if (s2io_card_up(sp)) {
+                       printk(KERN_ERR "s2io: "
+                              "Can't bring device back up after reset.\n");
+                       return;
+               }
+
+               if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) {
+                       s2io_card_down(sp);
+                       printk(KERN_ERR "s2io: "
+                              "Can't resetore mac addr after reset.\n");
+                       return;
+               }
+       }
+
+       netif_device_attach(netdev);
+       netif_wake_queue(netdev);
+}
index 54baa0b8ec7c937a17b8f2ae984e2799831cb9c6..58592780f5198b77cfb6517ada8b0db02450a7ce 100644 (file)
@@ -794,7 +794,6 @@ struct s2io_nic {
 
        struct net_device_stats stats;
        int high_dma_flag;
-       int device_close_flag;
        int device_enabled_once;
 
        char name[60];
@@ -1052,6 +1051,11 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
                           struct sk_buff *skb, u32 tcp_len);
 static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring);
 
+static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
+                                             pci_channel_state_t state);
+static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev);
+static void s2io_io_resume(struct pci_dev *pdev);
+
 #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
 #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
 #define s2io_offload_type(skb) skb_shinfo(skb)->gso_type
index fe01b961b597263dc20aad6b331b384c3830d549..b51d73c8f81723df6b2abc6804b8fdc79f54add6 100644 (file)
@@ -50,7 +50,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.14"
+#define DRV_VERSION            "1.15"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -130,7 +130,7 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
-//     { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
        { 0 }
 };
 
@@ -217,13 +217,24 @@ static void sky2_power_on(struct sky2_hw *hw)
                sky2_write8(hw, B2_Y2_CLK_GATE, 0);
 
        if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
-               u32 reg1;
+               u32 reg;
 
-               sky2_pci_write32(hw, PCI_DEV_REG3, 0);
-               reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
-               reg1 &= P_ASPM_CONTROL_MSK;
-               sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
-               sky2_pci_write32(hw, PCI_DEV_REG5, 0);
+               reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+               /* set all bits to 0 except bits 15..12 and 8 */
+               reg &= P_ASPM_CONTROL_MSK;
+               sky2_pci_write32(hw, PCI_DEV_REG4, reg);
+
+               reg = sky2_pci_read32(hw, PCI_DEV_REG5);
+               /* set all bits to 0 except bits 28 & 27 */
+               reg &= P_CTL_TIM_VMAIN_AV_MSK;
+               sky2_pci_write32(hw, PCI_DEV_REG5, reg);
+
+               sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+
+               /* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
+               reg = sky2_read32(hw, B2_GP_IO);
+               reg |= GLB_GPIO_STAT_RACE_DIS;
+               sky2_write32(hw, B2_GP_IO, reg);
        }
 }
 
@@ -650,6 +661,30 @@ static void sky2_wol_init(struct sky2_port *sky2)
 
 }
 
+static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
+{
+       if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) {
+               sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                            TX_STFW_ENA |
+                            (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS);
+       } else {
+               if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+                       /* set Tx GMAC FIFO Almost Empty Threshold */
+                       sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+                                    (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+
+                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                                    TX_JUMBO_ENA | TX_STFW_DIS);
+
+                       /* Can't do offload because of lack of store/forward */
+                       hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG
+                                                    | NETIF_F_ALL_CSUM);
+               } else
+                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                                    TX_JUMBO_DIS | TX_STFW_ENA);
+       }
+}
+
 static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 {
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -730,8 +765,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
        /* Configure Rx MAC FIFO */
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
-       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
-                    GMF_OPER_ON | GMF_RX_F_FL_ON);
+       reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+       if (hw->chip_id == CHIP_ID_YUKON_EX)
+               reg |= GMF_RX_OVER_ON;
+
+       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
 
        /* Flush Rx MAC FIFO on any flow control or error */
        sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
@@ -747,16 +785,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
                sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
                sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
 
-               /* set Tx GMAC FIFO Almost Empty Threshold */
-               sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
-                            (ECU_JUMBO_WM << 16) | ECU_AE_THR);
-
-               if (hw->dev[port]->mtu > ETH_DATA_LEN)
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                                    TX_JUMBO_ENA | TX_STFW_DIS);
-               else
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                                    TX_JUMBO_DIS | TX_STFW_ENA);
+               sky2_set_tx_stfwd(hw, port);
        }
 
 }
@@ -939,14 +968,16 @@ static void rx_set_checksum(struct sky2_port *sky2)
 {
        struct sky2_rx_le *le;
 
-       le = sky2_next_rx(sky2);
-       le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
-       le->ctrl = 0;
-       le->opcode = OP_TCPSTART | HW_OWNER;
+       if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) {
+               le = sky2_next_rx(sky2);
+               le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+               le->ctrl = 0;
+               le->opcode = OP_TCPSTART | HW_OWNER;
 
-       sky2_write32(sky2->hw,
-                    Q_ADDR(rxqaddr[sky2->port], Q_CSR),
-                    sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
+               sky2_write32(sky2->hw,
+                            Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
+       }
 
 }
 
@@ -1134,7 +1165,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
        if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
            (hw->chip_rev == CHIP_REV_YU_EC_U_A1
             || hw->chip_rev == CHIP_REV_YU_EC_U_B0))
-               sky2_write32(hw, Q_ADDR(rxq, Q_F), F_M_RX_RAM_DIS);
+               sky2_write32(hw, Q_ADDR(rxq, Q_TEST), F_M_RX_RAM_DIS);
 
        sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
 
@@ -1285,6 +1316,10 @@ static int sky2_up(struct net_device *dev)
 
        sky2_qset(hw, txqaddr[port]);
 
+       /* This is copied from sk98lin 10.0.5.3; no one tells me about erratta's */
+       if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev == CHIP_REV_YU_EX_B0)
+               sky2_write32(hw, Q_ADDR(txqaddr[port], Q_TEST), F_TX_CHK_AUTO_OFF);
+
        /* Set almost empty threshold */
        if (hw->chip_id == CHIP_ID_YUKON_EC_U
            && hw->chip_rev == CHIP_REV_YU_EC_U_A0)
@@ -1393,14 +1428,16 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        /* Check for TCP Segmentation Offload */
        mss = skb_shinfo(skb)->gso_size;
        if (mss != 0) {
-               mss += tcp_optlen(skb); /* TCP options */
-               mss += ip_hdrlen(skb) + sizeof(struct tcphdr);
-               mss += ETH_HLEN;
-
-               if (mss != sky2->tx_last_mss) {
-                       le = get_tx_le(sky2);
-                       le->addr = cpu_to_le32(mss);
-                       le->opcode = OP_LRGLEN | HW_OWNER;
+               if (hw->chip_id != CHIP_ID_YUKON_EX)
+                       mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
+
+               if (mss != sky2->tx_last_mss) {
+                       le = get_tx_le(sky2);
+                       le->addr = cpu_to_le32(mss);
+                       if (hw->chip_id == CHIP_ID_YUKON_EX)
+                               le->opcode = OP_MSS | HW_OWNER;
+                       else
+                               le->opcode = OP_LRGLEN | HW_OWNER;
                        sky2->tx_last_mss = mss;
                }
        }
@@ -1422,24 +1459,30 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
        /* Handle TCP checksum offload */
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               const unsigned offset = skb_transport_offset(skb);
-               u32 tcpsum;
-
-               tcpsum = offset << 16;          /* sum start */
-               tcpsum |= offset + skb->csum_offset;    /* sum write */
-
-               ctrl |= CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
-               if (ip_hdr(skb)->protocol == IPPROTO_UDP)
-                       ctrl |= UDPTCP;
-
-               if (tcpsum != sky2->tx_tcpsum) {
-                       sky2->tx_tcpsum = tcpsum;
-
-                       le = get_tx_le(sky2);
-                       le->addr = cpu_to_le32(tcpsum);
-                       le->length = 0; /* initial checksum value */
-                       le->ctrl = 1;   /* one packet */
-                       le->opcode = OP_TCPLISW | HW_OWNER;
+               /* On Yukon EX (some versions) encoding change. */
+               if (hw->chip_id == CHIP_ID_YUKON_EX
+                   && hw->chip_rev != CHIP_REV_YU_EX_B0)
+                       ctrl |= CALSUM; /* auto checksum */
+               else {
+                       const unsigned offset = skb_transport_offset(skb);
+                       u32 tcpsum;
+
+                       tcpsum = offset << 16;                  /* sum start */
+                       tcpsum |= offset + skb->csum_offset;    /* sum write */
+
+                       ctrl |= CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
+                       if (ip_hdr(skb)->protocol == IPPROTO_UDP)
+                               ctrl |= UDPTCP;
+
+                       if (tcpsum != sky2->tx_tcpsum) {
+                               sky2->tx_tcpsum = tcpsum;
+
+                               le = get_tx_le(sky2);
+                               le->addr = cpu_to_le32(tcpsum);
+                               le->length = 0; /* initial checksum value */
+                               le->ctrl = 1;   /* one packet */
+                               le->opcode = OP_TCPLISW | HW_OWNER;
+                       }
                }
        }
 
@@ -1913,15 +1956,8 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 
        synchronize_irq(hw->pdev->irq);
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
-               if (new_mtu > ETH_DATA_LEN) {
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                                    TX_JUMBO_ENA | TX_STFW_DIS);
-                       dev->features &= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
-               } else
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                                    TX_JUMBO_DIS | TX_STFW_ENA);
-       }
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+               sky2_set_tx_stfwd(hw, port);
 
        ctl = gma_read16(hw, port, GM_GP_CTRL);
        gma_write16(hw, port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA);
@@ -2118,6 +2154,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
 
        while (hw->st_idx != hwidx) {
                struct sky2_status_le *le  = hw->st_le + hw->st_idx;
+               unsigned port = le->css & CSS_LINK_BIT;
                struct net_device *dev;
                struct sk_buff *skb;
                u32 status;
@@ -2125,9 +2162,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
 
                hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
 
-               BUG_ON(le->link >= 2);
-               dev = hw->dev[le->link];
-
+               dev = hw->dev[port];
                sky2 = netdev_priv(dev);
                length = le16_to_cpu(le->length);
                status = le32_to_cpu(le->status);
@@ -2140,6 +2175,16 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                                goto force_update;
                        }
 
+                       /* This chip reports checksum status differently */
+                       if (hw->chip_id == CHIP_ID_YUKON_EX) {
+                               if (sky2->rx_csum &&
+                                   (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
+                                   (le->css & CSS_TCPUDPCSOK))
+                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               else
+                                       skb->ip_summed = CHECKSUM_NONE;
+                       }
+
                        skb->protocol = eth_type_trans(skb, dev);
                        sky2->net_stats.rx_packets++;
                        sky2->net_stats.rx_bytes += skb->len;
@@ -2155,10 +2200,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                                netif_receive_skb(skb);
 
                        /* Update receiver after 16 frames */
-                       if (++buf_write[le->link] == RX_BUF_WRITE) {
+                       if (++buf_write[port] == RX_BUF_WRITE) {
 force_update:
-                               sky2_put_idx(hw, rxqaddr[le->link], sky2->rx_put);
-                               buf_write[le->link] = 0;
+                               sky2_put_idx(hw, rxqaddr[port], sky2->rx_put);
+                               buf_write[port] = 0;
                        }
 
                        /* Stop after net poll weight */
@@ -2179,6 +2224,9 @@ force_update:
                        if (!sky2->rx_csum)
                                break;
 
+                       if (hw->chip_id == CHIP_ID_YUKON_EX)
+                               break;
+
                        /* Both checksum counters are programmed to start at
                         * the same offset, so unless there is a problem they
                         * should match. This failure is an early indication that
@@ -2194,7 +2242,7 @@ force_update:
                                       dev->name, status);
                                sky2->rx_csum = 0;
                                sky2_write32(sky2->hw,
-                                            Q_ADDR(rxqaddr[le->link], Q_CSR),
+                                            Q_ADDR(rxqaddr[port], Q_CSR),
                                             BMU_DIS_RX_CHKSUM);
                        }
                        break;
@@ -2513,6 +2561,9 @@ static int __devinit sky2_init(struct sky2_hw *hw)
 {
        u8 t8;
 
+       /* Enable all clocks */
+       sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
        sky2_write8(hw, B0_CTST, CS_RST_CLR);
 
        hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
@@ -2522,14 +2573,6 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                return -EOPNOTSUPP;
        }
 
-       if (hw->chip_id == CHIP_ID_YUKON_EX)
-               dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
-                        "Please report success or failure to <netdev@vger.kernel.org>\n");
-
-       /* Make sure and enable all clocks */
-       if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
-               sky2_pci_write32(hw, PCI_DEV_REG3, 0);
-
        hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
 
        /* This rev is really old, and requires untested workarounds */
@@ -2589,6 +2632,11 @@ static void sky2_reset(struct sky2_hw *hw)
        for (i = 0; i < hw->ports; i++) {
                sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
                sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+               if (hw->chip_id == CHIP_ID_YUKON_EX)
+                       sky2_write16(hw, SK_REG(i, GMAC_CTRL),
+                                    GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON
+                                    | GMC_BYP_RETR_ON);
        }
 
        sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
@@ -2735,7 +2783,7 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
        sky2->wol = wol->wolopts;
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
                sky2_write32(hw, B0_CTST, sky2->wol
                             ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
 
@@ -3330,7 +3378,7 @@ static int sky2_get_regs_len(struct net_device *dev)
 
 /*
  * Returns copy of control register region
- * Note: access to the RAM address register set will cause timeouts.
+ * Note: ethtool_get_regs always provides full size (16k) buffer
  */
 static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
                          void *p)
@@ -3338,15 +3386,19 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
        const struct sky2_port *sky2 = netdev_priv(dev);
        const void __iomem *io = sky2->hw->regs;
 
-       BUG_ON(regs->len < B3_RI_WTO_R1);
        regs->version = 1;
        memset(p, 0, regs->len);
 
        memcpy_fromio(p, io, B3_RAM_ADDR);
 
-       memcpy_fromio(p + B3_RI_WTO_R1,
-                     io + B3_RI_WTO_R1,
-                     regs->len - B3_RI_WTO_R1);
+       /* skip diagnostic ram region */
+       memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1);
+
+       /* copy GMAC registers */
+       memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000);
+       if (sky2->hw->ports > 1)
+               memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000);
+
 }
 
 /* In order to do Jumbo packets on these chips, need to turn off the
@@ -3357,9 +3409,7 @@ static int no_tx_offload(struct net_device *dev)
        const struct sky2_port *sky2 = netdev_priv(dev);
        const struct sky2_hw *hw = sky2->hw;
 
-       return dev->mtu > ETH_DATA_LEN &&
-               (hw->chip_id == CHIP_ID_YUKON_EX
-                || hw->chip_id == CHIP_ID_YUKON_EC_U);
+       return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U;
 }
 
 static int sky2_set_tx_csum(struct net_device *dev, u32 data)
index b8c4a3b5eadf9812f7bede24ebeeb20f76a41e6b..8df4643493d19408b81c33418a942ac378408274 100644 (file)
@@ -14,6 +14,8 @@ enum {
        PCI_DEV_REG3    = 0x80,
        PCI_DEV_REG4    = 0x84,
        PCI_DEV_REG5    = 0x88,
+       PCI_CFG_REG_0   = 0x90,
+       PCI_CFG_REG_1   = 0x94,
 };
 
 enum {
@@ -28,6 +30,7 @@ enum {
 enum pci_dev_reg_1 {
        PCI_Y2_PIG_ENA   = 1<<31, /* Enable Plug-in-Go (YUKON-2) */
        PCI_Y2_DLL_DIS   = 1<<30, /* Disable PCI DLL (YUKON-2) */
+       PCI_SW_PWR_ON_RST= 1<<30, /* SW Power on Reset (Yukon-EX) */
        PCI_Y2_PHY2_COMA = 1<<29, /* Set PHY 2 to Coma Mode (YUKON-2) */
        PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
        PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
@@ -67,6 +70,80 @@ enum pci_dev_reg_4 {
                                  | P_ASPM_CLKRUN_REQUEST | P_ASPM_INT_FIFO_EMPTY,
 };
 
+/*     PCI_OUR_REG_5           32 bit  Our Register 5 (Yukon-ECU only) */
+enum pci_dev_reg_5 {
+                                       /* Bit 31..27:  for A3 & later */
+       P_CTL_DIV_CORE_CLK_ENA  = 1<<31, /* Divide Core Clock Enable */
+       P_CTL_SRESET_VMAIN_AV   = 1<<30, /* Soft Reset for Vmain_av De-Glitch */
+       P_CTL_BYPASS_VMAIN_AV   = 1<<29, /* Bypass En. for Vmain_av De-Glitch */
+       P_CTL_TIM_VMAIN_AV_MSK  = 3<<27, /* Bit 28..27: Timer Vmain_av Mask */
+                                        /* Bit 26..16: Release Clock on Event */
+       P_REL_PCIE_RST_DE_ASS   = 1<<26, /* PCIe Reset De-Asserted */
+       P_REL_GPHY_REC_PACKET   = 1<<25, /* GPHY Received Packet */
+       P_REL_INT_FIFO_N_EMPTY  = 1<<24, /* Internal FIFO Not Empty */
+       P_REL_MAIN_PWR_AVAIL    = 1<<23, /* Main Power Available */
+       P_REL_CLKRUN_REQ_REL    = 1<<22, /* CLKRUN Request Release */
+       P_REL_PCIE_RESET_ASS    = 1<<21, /* PCIe Reset Asserted */
+       P_REL_PME_ASSERTED      = 1<<20, /* PME Asserted */
+       P_REL_PCIE_EXIT_L1_ST   = 1<<19, /* PCIe Exit L1 State */
+       P_REL_LOADER_NOT_FIN    = 1<<18, /* EPROM Loader Not Finished */
+       P_REL_PCIE_RX_EX_IDLE   = 1<<17, /* PCIe Rx Exit Electrical Idle State */
+       P_REL_GPHY_LINK_UP      = 1<<16, /* GPHY Link Up */
+
+                                       /* Bit 10.. 0: Mask for Gate Clock */
+       P_GAT_PCIE_RST_ASSERTED = 1<<10,/* PCIe Reset Asserted */
+       P_GAT_GPHY_N_REC_PACKET = 1<<9, /* GPHY Not Received Packet */
+       P_GAT_INT_FIFO_EMPTY    = 1<<8, /* Internal FIFO Empty */
+       P_GAT_MAIN_PWR_N_AVAIL  = 1<<7, /* Main Power Not Available */
+       P_GAT_CLKRUN_REQ_REL    = 1<<6, /* CLKRUN Not Requested */
+       P_GAT_PCIE_RESET_ASS    = 1<<5, /* PCIe Reset Asserted */
+       P_GAT_PME_DE_ASSERTED   = 1<<4, /* PME De-Asserted */
+       P_GAT_PCIE_ENTER_L1_ST  = 1<<3, /* PCIe Enter L1 State */
+       P_GAT_LOADER_FINISHED   = 1<<2, /* EPROM Loader Finished */
+       P_GAT_PCIE_RX_EL_IDLE   = 1<<1, /* PCIe Rx Electrical Idle State */
+       P_GAT_GPHY_LINK_DOWN    = 1<<0, /* GPHY Link Down */
+
+       PCIE_OUR5_EVENT_CLK_D3_SET = P_REL_GPHY_REC_PACKET |
+                                    P_REL_INT_FIFO_N_EMPTY |
+                                    P_REL_PCIE_EXIT_L1_ST |
+                                    P_REL_PCIE_RX_EX_IDLE |
+                                    P_GAT_GPHY_N_REC_PACKET |
+                                    P_GAT_INT_FIFO_EMPTY |
+                                    P_GAT_PCIE_ENTER_L1_ST |
+                                    P_GAT_PCIE_RX_EL_IDLE,
+};
+
+#/*    PCI_CFG_REG_1                   32 bit  Config Register 1 (Yukon-Ext only) */
+enum pci_cfg_reg1 {
+       P_CF1_DIS_REL_EVT_RST   = 1<<24, /* Dis. Rel. Event during PCIE reset */
+                                                                               /* Bit 23..21: Release Clock on Event */
+       P_CF1_REL_LDR_NOT_FIN   = 1<<23, /* EEPROM Loader Not Finished */
+       P_CF1_REL_VMAIN_AVLBL   = 1<<22, /* Vmain available */
+       P_CF1_REL_PCIE_RESET    = 1<<21, /* PCI-E reset */
+                                                                               /* Bit 20..18: Gate Clock on Event */
+       P_CF1_GAT_LDR_NOT_FIN   = 1<<20, /* EEPROM Loader Finished */
+       P_CF1_GAT_PCIE_RX_IDLE  = 1<<19, /* PCI-E Rx Electrical idle */
+       P_CF1_GAT_PCIE_RESET    = 1<<18, /* PCI-E Reset */
+       P_CF1_PRST_PHY_CLKREQ   = 1<<17, /* Enable PCI-E rst & PM2PHY gen. CLKREQ */
+       P_CF1_PCIE_RST_CLKREQ   = 1<<16, /* Enable PCI-E rst generate CLKREQ */
+
+       P_CF1_ENA_CFG_LDR_DONE  = 1<<8, /* Enable core level Config loader done */
+
+       P_CF1_ENA_TXBMU_RD_IDLE = 1<<1, /* Enable TX BMU Read  IDLE for ASPM */
+       P_CF1_ENA_TXBMU_WR_IDLE = 1<<0, /* Enable TX BMU Write IDLE for ASPM */
+
+       PCIE_CFG1_EVENT_CLK_D3_SET = P_CF1_DIS_REL_EVT_RST |
+                                       P_CF1_REL_LDR_NOT_FIN |
+                                       P_CF1_REL_VMAIN_AVLBL |
+                                       P_CF1_REL_PCIE_RESET |
+                                       P_CF1_GAT_LDR_NOT_FIN |
+                                       P_CF1_GAT_PCIE_RESET |
+                                       P_CF1_PRST_PHY_CLKREQ |
+                                       P_CF1_ENA_CFG_LDR_DONE |
+                                       P_CF1_ENA_TXBMU_RD_IDLE |
+                                       P_CF1_ENA_TXBMU_WR_IDLE,
+};
+
 
 #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
                               PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -364,6 +441,20 @@ enum {
        TST_CFG_WRITE_OFF= 1<<0, /* Disable Config Reg WR */
 };
 
+/*     B2_GPIO */
+enum {
+       GLB_GPIO_CLK_DEB_ENA = 1<<31,   /* Clock Debug Enable */
+       GLB_GPIO_CLK_DBG_MSK = 0xf<<26, /* Clock Debug */
+
+       GLB_GPIO_INT_RST_D3_DIS = 1<<15, /* Disable Internal Reset After D3 to D0 */
+       GLB_GPIO_LED_PAD_SPEED_UP = 1<<14, /* LED PAD Speed Up */
+       GLB_GPIO_STAT_RACE_DIS  = 1<<13, /* Status Race Disable */
+       GLB_GPIO_TEST_SEL_MSK   = 3<<11, /* Testmode Select */
+       GLB_GPIO_TEST_SEL_BASE  = 1<<11,
+       GLB_GPIO_RAND_ENA       = 1<<10, /* Random Enable */
+       GLB_GPIO_RAND_BIT_1     = 1<<9,  /* Random Bit 1 */
+};
+
 /*     B2_MAC_CFG               8 bit  MAC Configuration / Chip Revision */
 enum {
        CFG_CHIP_R_MSK    = 0xf<<4,     /* Bit 7.. 4: Chip Revision */
@@ -392,6 +483,11 @@ enum {
        CHIP_REV_YU_FE_A2    = 2,
 
 };
+enum yukon_ex_rev {
+       CHIP_REV_YU_EX_A0    = 1,
+       CHIP_REV_YU_EX_B0    = 2,
+};
+
 
 /*     B2_Y2_CLK_GATE   8 bit  Clock Gating (Yukon-2 only) */
 enum {
@@ -515,23 +611,15 @@ enum {
 enum {
        B8_Q_REGS = 0x0400, /* base of Queue registers */
        Q_D     = 0x00, /* 8*32 bit     Current Descriptor */
-       Q_DA_L  = 0x20, /* 32 bit       Current Descriptor Address Low dWord */
-       Q_DA_H  = 0x24, /* 32 bit       Current Descriptor Address High dWord */
+       Q_VLAN  = 0x20, /* 16 bit       Current VLAN Tag */
+       Q_DONE  = 0x24, /* 16 bit       Done Index */
        Q_AC_L  = 0x28, /* 32 bit       Current Address Counter Low dWord */
        Q_AC_H  = 0x2c, /* 32 bit       Current Address Counter High dWord */
        Q_BC    = 0x30, /* 32 bit       Current Byte Counter */
        Q_CSR   = 0x34, /* 32 bit       BMU Control/Status Register */
-       Q_F     = 0x38, /* 32 bit       Flag Register */
-       Q_T1    = 0x3c, /* 32 bit       Test Register 1 */
-       Q_T1_TR = 0x3c, /*  8 bit       Test Register 1 Transfer SM */
-       Q_T1_WR = 0x3d, /*  8 bit       Test Register 1 Write Descriptor SM */
-       Q_T1_RD = 0x3e, /*  8 bit       Test Register 1 Read Descriptor SM */
-       Q_T1_SV = 0x3f, /*  8 bit       Test Register 1 Supervisor SM */
-       Q_T2    = 0x40, /* 32 bit       Test Register 2 */
-       Q_T3    = 0x44, /* 32 bit       Test Register 3 */
+       Q_TEST  = 0x38, /* 32 bit       Test/Control Register */
 
 /* Yukon-2 */
-       Q_DONE  = 0x24, /* 16 bit       Done Index              (Yukon-2 only) */
        Q_WM    = 0x40, /* 16 bit       FIFO Watermark */
        Q_AL    = 0x42, /*  8 bit       FIFO Alignment */
        Q_RSP   = 0x44, /* 16 bit       FIFO Read Shadow Pointer */
@@ -545,15 +633,16 @@ enum {
 };
 #define Q_ADDR(reg, offs) (B8_Q_REGS + (reg) + (offs))
 
-/*     Q_F                             32 bit  Flag Register */
+/*     Q_TEST                          32 bit  Test Register */
 enum {
-       F_ALM_FULL      = 1<<27, /* Rx FIFO: almost full */
-       F_EMPTY         = 1<<27, /* Tx FIFO: empty flag */
-       F_FIFO_EOF      = 1<<26, /* Tag (EOF Flag) bit in FIFO */
-       F_WM_REACHED    = 1<<25, /* Watermark reached */
+       /* Transmit */
+       F_TX_CHK_AUTO_OFF = 1<<31, /* Tx checksum auto calc off (Yukon EX) */
+       F_TX_CHK_AUTO_ON  = 1<<30, /* Tx checksum auto calc off (Yukon EX) */
+
+       /* Receive */
        F_M_RX_RAM_DIS  = 1<<24, /* MAC Rx RAM Read Port disable */
-       F_FIFO_LEVEL    = 0x1fL<<16, /* Bit 23..16:     # of Qwords in FIFO */
-       F_WATER_MARK    = 0x0007ffL, /* Bit 10.. 0:     Watermark */
+
+       /* Hardware testbits not used */
 };
 
 /* Queue Prefetch Unit Offsets, use Y2_QADDR() to address (Yukon-2 only)*/
@@ -1608,6 +1697,16 @@ enum {
        RX_VLAN_STRIP_ON = 1<<25,       /* enable  VLAN stripping */
        RX_VLAN_STRIP_OFF = 1<<24,      /* disable VLAN stripping */
 
+       RX_MACSEC_FLUSH_ON  = 1<<23,
+       RX_MACSEC_FLUSH_OFF = 1<<22,
+       RX_MACSEC_ASF_FLUSH_ON = 1<<21,
+       RX_MACSEC_ASF_FLUSH_OFF = 1<<20,
+
+       GMF_RX_OVER_ON      = 1<<19,    /* enable flushing on receive overrun */
+       GMF_RX_OVER_OFF     = 1<<18,    /* disable flushing on receive overrun */
+       GMF_ASF_RX_OVER_ON  = 1<<17,    /* enable flushing of ASF when overrun */
+       GMF_ASF_RX_OVER_OFF = 1<<16,    /* disable flushing of ASF when overrun */
+
        GMF_WP_TST_ON   = 1<<14,        /* Write Pointer Test On */
        GMF_WP_TST_OFF  = 1<<13,        /* Write Pointer Test Off */
        GMF_WP_STEP     = 1<<12,        /* Write Pointer Step/Increment */
@@ -1720,6 +1819,15 @@ enum {
 
 /*     GMAC_CTRL               32 bit  GMAC Control Reg (YUKON only) */
 enum {
+       GMC_SET_RST         = 1<<15,/* MAC SEC RST */
+       GMC_SEC_RST_OFF     = 1<<14,/* MAC SEC RSt OFF */
+       GMC_BYP_MACSECRX_ON = 1<<13,/* Bypass macsec RX */
+       GMC_BYP_MACSECRX_OFF= 1<<12,/* Bypass macsec RX off */
+       GMC_BYP_MACSECTX_ON = 1<<11,/* Bypass macsec TX */
+       GMC_BYP_MACSECTX_OFF= 1<<10,/* Bypass macsec TX  off*/
+       GMC_BYP_RETR_ON = 1<<9, /* Bypass retransmit FIFO On */
+       GMC_BYP_RETR_OFF= 1<<8, /* Bypass retransmit FIFO Off */
+
        GMC_H_BURST_ON  = 1<<7, /* Half Duplex Burst Mode On */
        GMC_H_BURST_OFF = 1<<6, /* Half Duplex Burst Mode Off */
        GMC_F_LOOPB_ON  = 1<<5, /* FIFO Loopback On */
@@ -1805,9 +1913,13 @@ enum {
        OP_ADDR64VLAN   = OP_ADDR64 | OP_VLAN,
        OP_LRGLEN       = 0x24,
        OP_LRGLENVLAN   = OP_LRGLEN | OP_VLAN,
+       OP_MSS          = 0x28,
+       OP_MSSVLAN      = OP_MSS | OP_VLAN,
+
        OP_BUFFER       = 0x40,
        OP_PACKET       = 0x41,
        OP_LARGESEND    = 0x43,
+       OP_LSOV2        = 0x45,
 
 /* YUKON-2 STATUS opcodes defines */
        OP_RXSTAT       = 0x60,
@@ -1818,6 +1930,19 @@ enum {
        OP_RXTIMEVLAN   = OP_RXTIMESTAMP | OP_RXVLAN,
        OP_RSS_HASH     = 0x65,
        OP_TXINDEXLE    = 0x68,
+       OP_MACSEC       = 0x6c,
+       OP_PUTIDX       = 0x70,
+};
+
+enum status_css {
+       CSS_TCPUDPCSOK  = 1<<7, /* TCP / UDP checksum is ok */
+       CSS_ISUDP       = 1<<6, /* packet is a UDP packet */
+       CSS_ISTCP       = 1<<5, /* packet is a TCP packet */
+       CSS_ISIPFRAG    = 1<<4, /* packet is a TCP/UDP frag, CS calc not done */
+       CSS_ISIPV6      = 1<<3, /* packet is a IPv6 packet */
+       CSS_IPV4CSUMOK  = 1<<2, /* IP v4: TCP header checksum is ok */
+       CSS_ISIPV4      = 1<<1, /* packet is a IPv4 packet */
+       CSS_LINK_BIT    = 1<<0, /* port number (legacy) */
 };
 
 /* Yukon 2 hardware interface */
@@ -1838,7 +1963,7 @@ struct sky2_rx_le {
 struct sky2_status_le {
        __le32  status; /* also checksum */
        __le16  length; /* also vlan tag */
-       u8      link;
+       u8      css;
        u8      opcode;
 } __attribute((packed));
 
diff --git a/drivers/net/sni_82596.c b/drivers/net/sni_82596.c
new file mode 100644 (file)
index 0000000..2cf6794
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * sni_82596.c -- driver for intel 82596 ethernet controller, as
+ *               used in older SNI RM machines
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
+
+static const char sni_82596_string[] = "snirm_82596";
+
+#define DMA_ALLOC                      dma_alloc_coherent
+#define DMA_FREE                       dma_free_coherent
+#define DMA_WBACK(priv, addr, len)     do { } while (0)
+#define DMA_INV(priv, addr, len)       do { } while (0)
+#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
+
+#define SYSBUS      0x00004400
+
+/* big endian CPU, 82596 little endian */
+#define SWAP32(x)   cpu_to_le32((u32)(x))
+#define SWAP16(x)   cpu_to_le16((u16)(x))
+
+#define OPT_MPU_16BIT    0x01
+
+#include "lib82596.c"
+
+MODULE_AUTHOR("Thomas Bogendoerfer");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "82596 debug mask");
+
+static inline void ca(struct net_device *dev)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       writel(0, lp->ca);
+}
+
+
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
+{
+       struct i596_private *lp = netdev_priv(dev);
+
+       u32 v = (u32) (c) | (u32) (x);
+
+       if (lp->options & OPT_MPU_16BIT) {
+               writew(v & 0xffff, lp->mpu_port);
+               wmb();  /* order writes to MPU port */
+               udelay(1);
+               writew(v >> 16, lp->mpu_port);
+       } else {
+               writel(v, lp->mpu_port);
+               wmb();  /* order writes to MPU port */
+               udelay(1);
+               writel(v, lp->mpu_port);
+       }
+}
+
+
+static int __devinit sni_82596_probe(struct platform_device *dev)
+{
+       struct  net_device *netdevice;
+       struct i596_private *lp;
+       struct  resource *res, *ca, *idprom, *options;
+       int     retval = -ENOMEM;
+       void __iomem *mpu_addr;
+       void __iomem *ca_addr;
+       u8 __iomem *eth_addr;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       options = platform_get_resource(dev, 0, 0);
+       idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
+       if (!res || !ca || !options || !idprom)
+               return -ENODEV;
+       mpu_addr = ioremap_nocache(res->start, 4);
+       if (!mpu_addr)
+               return -ENOMEM;
+       ca_addr = ioremap_nocache(ca->start, 4);
+       if (!ca_addr)
+               goto probe_failed_free_mpu;
+
+       printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
+
+       netdevice = alloc_etherdev(sizeof(struct i596_private));
+       if (!netdevice)
+               goto probe_failed_free_ca;
+
+       SET_NETDEV_DEV(netdevice, &dev->dev);
+       platform_set_drvdata (dev, netdevice);
+
+       netdevice->base_addr = res->start;
+       netdevice->irq = platform_get_irq(dev, 0);
+
+       eth_addr = ioremap_nocache(idprom->start, 0x10);
+       if (!eth_addr)
+               goto probe_failed;
+
+       /* someone seems to like messed up stuff */
+       netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
+       netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
+       netdevice->dev_addr[2] = readb(eth_addr + 0x09);
+       netdevice->dev_addr[3] = readb(eth_addr + 0x08);
+       netdevice->dev_addr[4] = readb(eth_addr + 0x07);
+       netdevice->dev_addr[5] = readb(eth_addr + 0x06);
+       iounmap(eth_addr);
+
+       if (!netdevice->irq) {
+               printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+                       __FILE__, netdevice->base_addr);
+               goto probe_failed;
+       }
+
+       lp = netdev_priv(netdevice);
+       lp->options = options->flags & IORESOURCE_BITS;
+       lp->ca = ca_addr;
+       lp->mpu_port = mpu_addr;
+
+       retval = i82596_probe(netdevice);
+       if (retval == 0)
+               return 0;
+
+probe_failed:
+       free_netdev(netdevice);
+probe_failed_free_ca:
+       iounmap(ca_addr);
+probe_failed_free_mpu:
+       iounmap(mpu_addr);
+       return retval;
+}
+
+static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct i596_private *lp = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
+                lp->dma, lp->dma_addr);
+       iounmap(lp->ca);
+       iounmap(lp->mpu_port);
+       free_netdev (dev);
+       return 0;
+}
+
+static struct platform_driver sni_82596_driver = {
+       .probe  = sni_82596_probe,
+       .remove = __devexit_p(sni_82596_driver_remove),
+       .driver = {
+               .name   = sni_82596_string,
+       },
+};
+
+static int __devinit sni_82596_init(void)
+{
+       printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
+       return platform_driver_register(&sni_82596_driver);
+}
+
+
+static void __exit sni_82596_exit(void)
+{
+       platform_driver_unregister(&sni_82596_driver);
+}
+
+module_init(sni_82596_init);
+module_exit(sni_82596_exit);
index 7a4aa6a9f94913245f2eb7b155a363c33c1399af..f5abb5279d4dbf730e696c892ff478305be43236 100644 (file)
@@ -434,7 +434,8 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
                                      bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
        if (!descr->skb) {
                if (netif_msg_rx_err(card) && net_ratelimit())
-                       pr_err("Not enough memory to allocate rx buffer\n");
+                       dev_err(&card->netdev->dev,
+                               "Not enough memory to allocate rx buffer\n");
                card->spider_stats.alloc_rx_skb_error++;
                return -ENOMEM;
        }
@@ -455,7 +456,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
                dev_kfree_skb_any(descr->skb);
                descr->skb = NULL;
                if (netif_msg_rx_err(card) && net_ratelimit())
-                       pr_err("Could not iommu-map rx buffer\n");
+                       dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");
                card->spider_stats.rx_iommu_map_error++;
                hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
        } else {
@@ -499,6 +500,20 @@ spider_net_enable_rxdmac(struct spider_net_card *card)
                             SPIDER_NET_DMA_RX_VALUE);
 }
 
+/**
+ * spider_net_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_disable_rxdmac terminates processing on the DMA controller
+ * by turing off the DMA controller, with the force-end flag set.
+ */
+static inline void
+spider_net_disable_rxdmac(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+                            SPIDER_NET_DMA_RX_FEND_VALUE);
+}
+
 /**
  * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
  * @card: card structure
@@ -654,20 +669,6 @@ write_hash:
        }
 }
 
-/**
- * spider_net_disable_rxdmac - disables the receive DMA controller
- * @card: card structure
- *
- * spider_net_disable_rxdmac terminates processing on the DMA controller by
- * turing off DMA and issueing a force end
- */
-static void
-spider_net_disable_rxdmac(struct spider_net_card *card)
-{
-       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
-                            SPIDER_NET_DMA_RX_FEND_VALUE);
-}
-
 /**
  * spider_net_prepare_tx_descr - fill tx descriptor with skb data
  * @card: card structure
@@ -692,7 +693,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
        buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
        if (pci_dma_mapping_error(buf)) {
                if (netif_msg_tx_err(card) && net_ratelimit())
-                       pr_err("could not iommu-map packet (%p, %i). "
+                       dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). "
                                  "Dropping packet\n", skb->data, skb->len);
                card->spider_stats.tx_iommu_map_error++;
                return -ENOMEM;
@@ -715,7 +716,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
        hwdescr->data_status = 0;
 
        hwdescr->dmac_cmd_status =
-                       SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
+                       SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_TXFRMTL;
        spin_unlock_irqrestore(&chain->lock, flags);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -832,9 +833,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
                case SPIDER_NET_DESCR_PROTECTION_ERROR:
                case SPIDER_NET_DESCR_FORCE_END:
                        if (netif_msg_tx_err(card))
-                               pr_err("%s: forcing end of tx descriptor "
-                                      "with status x%02x\n",
-                                      card->netdev->name, status);
+                               dev_err(&card->netdev->dev, "forcing end of tx descriptor "
+                                      "with status x%02x\n", status);
                        card->netdev_stats.tx_errors++;
                        break;
 
@@ -1022,34 +1022,94 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
        netif_receive_skb(skb);
 }
 
-#ifdef DEBUG
 static void show_rx_chain(struct spider_net_card *card)
 {
        struct spider_net_descr_chain *chain = &card->rx_chain;
        struct spider_net_descr *start= chain->tail;
        struct spider_net_descr *descr= start;
+       struct spider_net_hw_descr *hwd = start->hwdescr;
+       struct device *dev = &card->netdev->dev;
+       u32 curr_desc, next_desc;
        int status;
 
+       int tot = 0;
        int cnt = 0;
-       int cstat = spider_net_get_descr_status(descr);
-       printk(KERN_INFO "RX chain tail at descr=%ld\n",
-            (start - card->descr) - card->tx_chain.num_desc);
+       int off = start - chain->ring;
+       int cstat = hwd->dmac_cmd_status;
+
+       dev_info(dev, "Total number of descrs=%d\n",
+               chain->num_desc);
+       dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",
+               off, cstat);
+
+       curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);
+       next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);
+
        status = cstat;
        do
        {
-               status = spider_net_get_descr_status(descr);
+               hwd = descr->hwdescr;
+               off = descr - chain->ring;
+               status = hwd->dmac_cmd_status;
+
+               if (descr == chain->head)
+                       dev_info(dev, "Chain head is at %d, head status=0x%x\n",
+                                off, status);
+
+               if (curr_desc == descr->bus_addr)
+                       dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",
+                                off, status);
+
+               if (next_desc == descr->bus_addr)
+                       dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",
+                                off, status);
+
+               if (hwd->next_descr_addr == 0)
+                       dev_info(dev, "chain is cut at %d\n", off);
+
                if (cstat != status) {
-                       printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+                       int from = (chain->num_desc + off - cnt) % chain->num_desc;
+                       int to = (chain->num_desc + off - 1) % chain->num_desc;
+                       dev_info(dev, "Have %d (from %d to %d) descrs "
+                                "with stat=0x%08x\n", cnt, from, to, cstat);
                        cstat = status;
                        cnt = 0;
                }
+
                cnt ++;
+               tot ++;
+               descr = descr->next;
+       } while (descr != start);
+
+       dev_info(dev, "Last %d descrs with stat=0x%08x "
+                "for a total of %d descrs\n", cnt, cstat, tot);
+
+#ifdef DEBUG
+       /* Now dump the whole ring */
+       descr = start;
+       do
+       {
+               struct spider_net_hw_descr *hwd = descr->hwdescr;
+               status = spider_net_get_descr_status(hwd);
+               cnt = descr - chain->ring;
+               dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",
+                        cnt, status, descr->skb);
+               dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",
+                        descr->bus_addr, hwd->buf_addr, hwd->buf_size);
+               dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",
+                        hwd->next_descr_addr, hwd->result_size,
+                        hwd->valid_size);
+               dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",
+                        hwd->dmac_cmd_status, hwd->data_status,
+                        hwd->data_error);
+               dev_info(dev, "\n");
+
                descr = descr->next;
        } while (descr != start);
-       printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
-}
 #endif
 
+}
+
 /**
  * spider_net_resync_head_ptr - Advance head ptr past empty descrs
  *
@@ -1127,6 +1187,7 @@ spider_net_decode_one_descr(struct spider_net_card *card)
        struct spider_net_descr_chain *chain = &card->rx_chain;
        struct spider_net_descr *descr = chain->tail;
        struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+       u32 hw_buf_addr;
        int status;
 
        status = spider_net_get_descr_status(hwdescr);
@@ -1140,15 +1201,17 @@ spider_net_decode_one_descr(struct spider_net_card *card)
        chain->tail = descr->next;
 
        /* unmap descriptor */
-       pci_unmap_single(card->pdev, hwdescr->buf_addr,
+       hw_buf_addr = hwdescr->buf_addr;
+       hwdescr->buf_addr = 0xffffffff;
+       pci_unmap_single(card->pdev, hw_buf_addr,
                        SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
 
        if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
             (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
             (status == SPIDER_NET_DESCR_FORCE_END) ) {
                if (netif_msg_rx_err(card))
-                       pr_err("%s: dropping RX descriptor with state %d\n",
-                              card->netdev->name, status);
+                       dev_err(&card->netdev->dev,
+                              "dropping RX descriptor with state %d\n", status);
                card->netdev_stats.rx_dropped++;
                goto bad_desc;
        }
@@ -1156,8 +1219,8 @@ spider_net_decode_one_descr(struct spider_net_card *card)
        if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
             (status != SPIDER_NET_DESCR_FRAME_END) ) {
                if (netif_msg_rx_err(card))
-                       pr_err("%s: RX descriptor with unknown state %d\n",
-                              card->netdev->name, status);
+                       dev_err(&card->netdev->dev,
+                              "RX descriptor with unknown state %d\n", status);
                card->spider_stats.rx_desc_unk_state++;
                goto bad_desc;
        }
@@ -1165,18 +1228,17 @@ spider_net_decode_one_descr(struct spider_net_card *card)
        /* The cases we'll throw away the packet immediately */
        if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
                if (netif_msg_rx_err(card))
-                       pr_err("%s: error in received descriptor found, "
+                       dev_err(&card->netdev->dev,
+                              "error in received descriptor found, "
                               "data_status=x%08x, data_error=x%08x\n",
-                              card->netdev->name,
                               hwdescr->data_status, hwdescr->data_error);
                goto bad_desc;
        }
 
-       if (hwdescr->dmac_cmd_status & 0xfcf4) {
-               pr_err("%s: bad status, cmd_status=x%08x\n",
-                              card->netdev->name,
+       if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {
+               dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",
                               hwdescr->dmac_cmd_status);
-               pr_err("buf_addr=x%08x\n", hwdescr->buf_addr);
+               pr_err("buf_addr=x%08x\n", hw_buf_addr);
                pr_err("buf_size=x%08x\n", hwdescr->buf_size);
                pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
                pr_err("result_size=x%08x\n", hwdescr->result_size);
@@ -1196,6 +1258,8 @@ spider_net_decode_one_descr(struct spider_net_card *card)
        return 1;
 
 bad_desc:
+       if (netif_msg_rx_err(card))
+               show_rx_chain(card);
        dev_kfree_skb_irq(descr->skb);
        descr->skb = NULL;
        hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
@@ -1221,7 +1285,6 @@ spider_net_poll(struct net_device *netdev, int *budget)
        int packets_to_do, packets_done = 0;
        int no_more_packets = 0;
 
-       spider_net_cleanup_tx_ring(card);
        packets_to_do = min(*budget, netdev->quota);
 
        while (packets_to_do) {
@@ -1246,6 +1309,8 @@ spider_net_poll(struct net_device *netdev, int *budget)
        spider_net_refill_rx_chain(card);
        spider_net_enable_rxdmac(card);
 
+       spider_net_cleanup_tx_ring(card);
+
        /* if all packets are in the stack, enable interrupts and return 0 */
        /* if not, return 1 */
        if (no_more_packets) {
@@ -1415,7 +1480,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GPWFFINT:
                /* PHY command queue full */
                if (netif_msg_intr(card))
-                       pr_err("PHY write queue full\n");
+                       dev_err(&card->netdev->dev, "PHY write queue full\n");
                show_error = 0;
                break;
 
@@ -1582,9 +1647,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        }
 
        if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
-               pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
+               dev_err(&card->netdev->dev, "Error interrupt, GHIINT0STS = 0x%08x, "
                       "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
-                      card->netdev->name,
                       status_reg, error_reg1, error_reg2);
 
        /* clear interrupt sources */
@@ -1849,7 +1913,8 @@ spider_net_init_firmware(struct spider_net_card *card)
                             SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
                if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
                     netif_msg_probe(card) ) {
-                       pr_err("Incorrect size of spidernet firmware in " \
+                       dev_err(&card->netdev->dev,
+                              "Incorrect size of spidernet firmware in " \
                               "filesystem. Looking in host firmware...\n");
                        goto try_host_fw;
                }
@@ -1873,8 +1938,8 @@ try_host_fw:
 
        if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
             netif_msg_probe(card) ) {
-               pr_err("Incorrect size of spidernet firmware in " \
-                      "host firmware\n");
+               dev_err(&card->netdev->dev,
+                      "Incorrect size of spidernet firmware in host firmware\n");
                goto done;
        }
 
@@ -1884,7 +1949,8 @@ done:
        return err;
 out_err:
        if (netif_msg_probe(card))
-               pr_err("Couldn't find spidernet firmware in filesystem " \
+               dev_err(&card->netdev->dev,
+                      "Couldn't find spidernet firmware in filesystem " \
                       "or host firmware\n");
        return err;
 }
@@ -2279,13 +2345,14 @@ spider_net_setup_netdev(struct spider_net_card *card)
 
        result = spider_net_set_mac(netdev, &addr);
        if ((result) && (netif_msg_probe(card)))
-               pr_err("Failed to set MAC address: %i\n", result);
+               dev_err(&card->netdev->dev,
+                       "Failed to set MAC address: %i\n", result);
 
        result = register_netdev(netdev);
        if (result) {
                if (netif_msg_probe(card))
-                       pr_err("Couldn't register net_device: %i\n",
-                                 result);
+                       dev_err(&card->netdev->dev,
+                               "Couldn't register net_device: %i\n", result);
                return result;
        }
 
@@ -2363,17 +2430,19 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
        unsigned long mmio_start, mmio_len;
 
        if (pci_enable_device(pdev)) {
-               pr_err("Couldn't enable PCI device\n");
+               dev_err(&pdev->dev, "Couldn't enable PCI device\n");
                return NULL;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               pr_err("Couldn't find proper PCI device base address.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't find proper PCI device base address.\n");
                goto out_disable_dev;
        }
 
        if (pci_request_regions(pdev, spider_net_driver_name)) {
-               pr_err("Couldn't obtain PCI resources, aborting.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't obtain PCI resources, aborting.\n");
                goto out_disable_dev;
        }
 
@@ -2381,8 +2450,8 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
 
        card = spider_net_alloc_card();
        if (!card) {
-               pr_err("Couldn't allocate net_device structure, "
-                         "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't allocate net_device structure, aborting.\n");
                goto out_release_regions;
        }
        card->pdev = pdev;
@@ -2396,7 +2465,8 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
        card->regs = ioremap(mmio_start, mmio_len);
 
        if (!card->regs) {
-               pr_err("Couldn't obtain PCI resources, aborting.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't obtain PCI resources, aborting.\n");
                goto out_release_regions;
        }
 
index 1d054aa715049779fde4e9b04fcd68d161e3e2d6..dbbdb8cee3c639c0be5480a161d92b3fb16174e9 100644 (file)
@@ -349,11 +349,23 @@ enum spider_net_int2_status {
 #define SPIDER_NET_GPRDAT_MASK                 0x0000ffff
 
 #define SPIDER_NET_DMAC_NOINTR_COMPLETE                0x00800000
-#define SPIDER_NET_DMAC_NOCS                   0x00040000
+#define SPIDER_NET_DMAC_TXFRMTL                0x00040000
 #define SPIDER_NET_DMAC_TCP                    0x00020000
 #define SPIDER_NET_DMAC_UDP                    0x00030000
 #define SPIDER_NET_TXDCEST                     0x08000000
 
+#define SPIDER_NET_DESCR_RXFDIS        0x00000001
+#define SPIDER_NET_DESCR_RXDCEIS       0x00000002
+#define SPIDER_NET_DESCR_RXDEN0IS      0x00000004
+#define SPIDER_NET_DESCR_RXINVDIS      0x00000008
+#define SPIDER_NET_DESCR_RXRERRIS      0x00000010
+#define SPIDER_NET_DESCR_RXFDCIMS      0x00000100
+#define SPIDER_NET_DESCR_RXDCEIMS      0x00000200
+#define SPIDER_NET_DESCR_RXDEN0IMS     0x00000400
+#define SPIDER_NET_DESCR_RXINVDIMS     0x00000800
+#define SPIDER_NET_DESCR_RXRERRMIS     0x00001000
+#define SPIDER_NET_DESCR_UNUSED        0x077fe0e0
+
 #define SPIDER_NET_DESCR_IND_PROC_MASK         0xF0000000
 #define SPIDER_NET_DESCR_COMPLETE              0x00000000 /* used in rx and tx */
 #define SPIDER_NET_DESCR_RESPONSE_ERROR                0x10000000 /* used in rx and tx */
@@ -364,6 +376,13 @@ enum spider_net_int2_status {
 #define SPIDER_NET_DESCR_NOT_IN_USE            0xF0000000
 #define SPIDER_NET_DESCR_TXDESFLG              0x00800000
 
+#define SPIDER_NET_DESCR_BAD_STATUS   (SPIDER_NET_DESCR_RXDEN0IS | \
+                                       SPIDER_NET_DESCR_RXRERRIS | \
+                                       SPIDER_NET_DESCR_RXDEN0IMS | \
+                                       SPIDER_NET_DESCR_RXINVDIMS | \
+                                       SPIDER_NET_DESCR_RXRERRMIS | \
+                                       SPIDER_NET_DESCR_UNUSED)
+
 /* Descriptor, as defined by the hardware */
 struct spider_net_hw_descr {
        u32 buf_addr;
index 8c9634a98c111f92aee2cf674e7a856de3dd48a1..1c537d5a30627bbeef1b8aebbd84692a3e08facf 100644 (file)
@@ -2,17 +2,17 @@
 # Tulip family network device configuration
 #
 
-menu "Tulip family network device support"
-       depends on NET_ETHERNET && (PCI || EISA || CARDBUS)
-
-config NET_TULIP
+menuconfig NET_TULIP
        bool "\"Tulip\" family network device support"
+       depends on PCI || EISA || CARDBUS
        help
          This selects the "Tulip" family of EISA/PCI network cards.
 
+if NET_TULIP
+
 config DE2104X
        tristate "Early DECchip Tulip (dc2104x) PCI support (EXPERIMENTAL)"
-       depends on NET_TULIP && PCI && EXPERIMENTAL
+       depends on PCI && EXPERIMENTAL
        select CRC32
        ---help---
          This driver is developed for the SMC EtherPower series Ethernet
@@ -30,7 +30,7 @@ config DE2104X
 
 config TULIP
        tristate "DECchip Tulip (dc2114x) PCI support"
-       depends on NET_TULIP && PCI
+       depends on PCI
        select CRC32
        ---help---
          This driver is developed for the SMC EtherPower series Ethernet
@@ -95,7 +95,7 @@ config TULIP_NAPI_HW_MITIGATION
 
 config DE4X5
        tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA"
-       depends on NET_TULIP && (PCI || EISA)
+       depends on PCI || EISA
        select CRC32
        ---help---
          This is support for the DIGITAL series of PCI/EISA Ethernet cards.
@@ -112,7 +112,7 @@ config DE4X5
 
 config WINBOND_840
        tristate "Winbond W89c840 Ethernet support"
-       depends on NET_TULIP && PCI
+       depends on PCI
        select CRC32
        select MII
        help
@@ -123,7 +123,7 @@ config WINBOND_840
 
 config DM9102
        tristate "Davicom DM910x/DM980x support"
-       depends on NET_TULIP && PCI
+       depends on PCI
        select CRC32
        ---help---
          This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
@@ -137,7 +137,7 @@ config DM9102
 
 config ULI526X
        tristate "ULi M526x controller support"
-       depends on NET_TULIP && PCI
+       depends on PCI
        select CRC32
        ---help---
          This driver is for ULi M5261/M5263 10/100M Ethernet Controller
@@ -149,7 +149,7 @@ config ULI526X
          
 config PCMCIA_XIRCOM
        tristate "Xircom CardBus support (new driver)"
-       depends on NET_TULIP && CARDBUS
+       depends on CARDBUS
        ---help---
          This driver is for the Digital "Tulip" Ethernet CardBus adapters.
          It should work with most DEC 21*4*-based chips/ethercards, as well
@@ -162,7 +162,7 @@ config PCMCIA_XIRCOM
 
 config PCMCIA_XIRTULIP
        tristate "Xircom Tulip-like CardBus support (old driver)"
-       depends on NET_TULIP && CARDBUS && BROKEN_ON_SMP
+       depends on CARDBUS && BROKEN_ON_SMP
        select CRC32
        ---help---
          This driver is for the Digital "Tulip" Ethernet CardBus adapters.
@@ -174,5 +174,4 @@ config PCMCIA_XIRTULIP
          <file:Documentation/networking/net-modules.txt>.  The module will
          be called xircom_tulip_cb.  If unsure, say N.
 
-endmenu
-
+endif # NET_TULIP
index 861729806dc19cb3a0c6a9a6ad0480fe20dc22ef..d380e0b3f05a1fe0925eaee771b37e324dc08d70 100644 (file)
@@ -785,7 +785,6 @@ static void __de_set_rx_mode (struct net_device *dev)
 
        de->tx_head = NEXT_TX(entry);
 
-       BUG_ON(TX_BUFFS_AVAIL(de) < 0);
        if (TX_BUFFS_AVAIL(de) == 0)
                netif_stop_queue(dev);
 
index 62143f92c23136110cef20c248b48b0ddbc92b7d..42fca26afc500fef9c40fc1b109df1b9b91d3246 100644 (file)
@@ -597,7 +597,7 @@ static char *args;
 #endif
 
 struct parameters {
-    int fdx;
+    bool fdx;
     int autosense;
 };
 
@@ -809,10 +809,10 @@ struct de4x5_private {
     s32  irq_en;                            /* Summary interrupt bits       */
     int  media;                             /* Media (eg TP), mode (eg 100B)*/
     int  c_media;                           /* Remember the last media conn */
-    int  fdx;                               /* media full duplex flag       */
+    bool fdx;                               /* media full duplex flag       */
     int  linkOK;                            /* Link is OK                   */
     int  autosense;                         /* Allow/disallow autosensing   */
-    int  tx_enable;                         /* Enable descriptor polling    */
+    bool tx_enable;                         /* Enable descriptor polling    */
     int  setup_f;                           /* Setup frame filtering type   */
     int  local_state;                       /* State within a 'media' state */
     struct mii_phy phy[DE4X5_MAX_PHY];      /* List of attached PHY devices */
@@ -838,8 +838,8 @@ struct de4x5_private {
     struct de4x5_srom srom;                 /* A copy of the SROM           */
     int cfrv;                              /* Card CFRV copy */
     int rx_ovf;                             /* Check for 'RX overflow' tag  */
-    int useSROM;                            /* For non-DEC card use SROM    */
-    int useMII;                             /* Infoblock using the MII      */
+    bool useSROM;                           /* For non-DEC card use SROM    */
+    bool useMII;                            /* Infoblock using the MII      */
     int asBitValid;                         /* Autosense bits in GEP?       */
     int asPolarity;                         /* 0 => asserted high           */
     int asBit;                              /* Autosense bit number in GEP  */
@@ -928,7 +928,7 @@ static int     dc21040_state(struct net_device *dev, int csr13, int csr14, int c
 static int     test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
 static int     test_for_100Mb(struct net_device *dev, int msec);
 static int     wait_for_link(struct net_device *dev);
-static int     test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec);
+static int     test_mii_reg(struct net_device *dev, int reg, int mask, bool pol, long msec);
 static int     is_spd_100(struct net_device *dev);
 static int     is_100_up(struct net_device *dev);
 static int     is_10_up(struct net_device *dev);
@@ -1109,7 +1109,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
     /*
     ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
     */
-    lp->useSROM = FALSE;
+    lp->useSROM = false;
     if (lp->bus == PCI) {
        PCI_signature(name, lp);
     } else {
@@ -1137,7 +1137,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
        lp->cache.gepc = GEP_INIT;
        lp->asBit = GEP_SLNK;
        lp->asPolarity = GEP_SLNK;
-       lp->asBitValid = TRUE;
+       lp->asBitValid = ~0;
        lp->timeout = -1;
        lp->gendev = gendev;
        spin_lock_init(&lp->lock);
@@ -1463,7 +1463,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
     u_long flags = 0;
 
     netif_stop_queue(dev);
-    if (lp->tx_enable == NO) {                   /* Cannot send for now */
+    if (!lp->tx_enable) {                   /* Cannot send for now */
        return -1;
     }
 
@@ -2424,7 +2424,7 @@ dc21040_autoconf(struct net_device *dev)
     switch (lp->media) {
     case INIT:
        DISABLE_IRQs;
-       lp->tx_enable = NO;
+       lp->tx_enable = false;
        lp->timeout = -1;
        de4x5_save_skbs(dev);
        if ((lp->autosense == AUTO) || (lp->autosense == TP)) {
@@ -2477,7 +2477,7 @@ dc21040_autoconf(struct net_device *dev)
            lp->c_media = lp->media;
        }
        lp->media = INIT;
-       lp->tx_enable = NO;
+       lp->tx_enable = false;
        break;
     }
 
@@ -2578,7 +2578,7 @@ dc21041_autoconf(struct net_device *dev)
     switch (lp->media) {
     case INIT:
        DISABLE_IRQs;
-       lp->tx_enable = NO;
+       lp->tx_enable = false;
        lp->timeout = -1;
        de4x5_save_skbs(dev);          /* Save non transmitted skb's */
        if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) {
@@ -2757,7 +2757,7 @@ dc21041_autoconf(struct net_device *dev)
            lp->c_media = lp->media;
        }
        lp->media = INIT;
-       lp->tx_enable = NO;
+       lp->tx_enable = false;
        break;
     }
 
@@ -2781,7 +2781,7 @@ dc21140m_autoconf(struct net_device *dev)
     case INIT:
         if (lp->timeout < 0) {
            DISABLE_IRQs;
-           lp->tx_enable = FALSE;
+           lp->tx_enable = false;
            lp->linkOK = 0;
            de4x5_save_skbs(dev);          /* Save non transmitted skb's */
        }
@@ -2830,7 +2830,7 @@ dc21140m_autoconf(struct net_device *dev)
            if (lp->timeout < 0) {
                mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
            }
-           cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+           cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, false, 500);
            if (cr < 0) {
                next_tick = cr & ~TIMER_CB;
            } else {
@@ -2845,7 +2845,7 @@ dc21140m_autoconf(struct net_device *dev)
            break;
 
        case 1:
-           if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+           if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, true, 2000)) < 0) {
                next_tick = sr & ~TIMER_CB;
            } else {
                lp->media = SPD_DET;
@@ -2857,10 +2857,10 @@ dc21140m_autoconf(struct net_device *dev)
                    if (!(anlpa & MII_ANLPA_RF) &&
                         (cap = anlpa & MII_ANLPA_TAF & ana)) {
                        if (cap & MII_ANA_100M) {
-                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+                           lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) != 0;
                            lp->media = _100Mb;
                        } else if (cap & MII_ANA_10M) {
-                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+                           lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) != 0;
 
                            lp->media = _10Mb;
                        }
@@ -2932,7 +2932,7 @@ dc21140m_autoconf(struct net_device *dev)
            lp->c_media = lp->media;
        }
        lp->media = INIT;
-       lp->tx_enable = FALSE;
+       lp->tx_enable = false;
        break;
     }
 
@@ -2965,7 +2965,7 @@ dc2114x_autoconf(struct net_device *dev)
     case INIT:
         if (lp->timeout < 0) {
            DISABLE_IRQs;
-           lp->tx_enable = FALSE;
+           lp->tx_enable = false;
            lp->linkOK = 0;
             lp->timeout = -1;
            de4x5_save_skbs(dev);            /* Save non transmitted skb's */
@@ -3013,7 +3013,7 @@ dc2114x_autoconf(struct net_device *dev)
            if (lp->timeout < 0) {
                mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
            }
-           cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+           cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, false, 500);
            if (cr < 0) {
                next_tick = cr & ~TIMER_CB;
            } else {
@@ -3028,7 +3028,8 @@ dc2114x_autoconf(struct net_device *dev)
            break;
 
        case 1:
-           if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+           sr = test_mii_reg(dev, MII_SR, MII_SR_ASSC, true, 2000);
+           if (sr < 0) {
                next_tick = sr & ~TIMER_CB;
            } else {
                lp->media = SPD_DET;
@@ -3040,10 +3041,10 @@ dc2114x_autoconf(struct net_device *dev)
                    if (!(anlpa & MII_ANLPA_RF) &&
                         (cap = anlpa & MII_ANLPA_TAF & ana)) {
                        if (cap & MII_ANA_100M) {
-                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+                           lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) != 0;
                            lp->media = _100Mb;
                        } else if (cap & MII_ANA_10M) {
-                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+                           lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) != 0;
                            lp->media = _10Mb;
                        }
                    }
@@ -3222,14 +3223,14 @@ srom_map_media(struct net_device *dev)
 {
     struct de4x5_private *lp = netdev_priv(dev);
 
-    lp->fdx = 0;
+    lp->fdx = false;
     if (lp->infoblock_media == lp->media)
       return 0;
 
     switch(lp->infoblock_media) {
       case SROM_10BASETF:
        if (!lp->params.fdx) return -1;
-       lp->fdx = TRUE;
+       lp->fdx = true;
       case SROM_10BASET:
        if (lp->params.fdx && !lp->fdx) return -1;
        if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
@@ -3249,7 +3250,7 @@ srom_map_media(struct net_device *dev)
 
       case SROM_100BASETF:
         if (!lp->params.fdx) return -1;
-       lp->fdx = TRUE;
+       lp->fdx = true;
       case SROM_100BASET:
        if (lp->params.fdx && !lp->fdx) return -1;
        lp->media = _100Mb;
@@ -3261,7 +3262,7 @@ srom_map_media(struct net_device *dev)
 
       case SROM_100BASEFF:
        if (!lp->params.fdx) return -1;
-       lp->fdx = TRUE;
+       lp->fdx = true;
       case SROM_100BASEF:
        if (lp->params.fdx && !lp->fdx) return -1;
        lp->media = _100Mb;
@@ -3297,7 +3298,7 @@ de4x5_init_connection(struct net_device *dev)
     spin_lock_irqsave(&lp->lock, flags);
     de4x5_rst_desc_ring(dev);
     de4x5_setup_intr(dev);
-    lp->tx_enable = YES;
+    lp->tx_enable = true;
     spin_unlock_irqrestore(&lp->lock, flags);
     outl(POLL_DEMAND, DE4X5_TPD);
 
@@ -3336,7 +3337,7 @@ de4x5_reset_phy(struct net_device *dev)
             }
         }
        if (lp->useMII) {
-           next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
+           next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, false, 500);
        }
     } else if (lp->chipset == DC21140) {
        PHY_HARD_RESET;
@@ -3466,7 +3467,7 @@ wait_for_link(struct net_device *dev)
 **
 */
 static int
-test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
+test_mii_reg(struct net_device *dev, int reg, int mask, bool pol, long msec)
 {
     struct de4x5_private *lp = netdev_priv(dev);
     int test;
@@ -3476,9 +3477,8 @@ test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
        lp->timeout = msec/100;
     }
 
-    if (pol) pol = ~0;
     reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
-    test = (reg ^ pol) & mask;
+    test = (reg ^ (pol ? ~0 : 0)) & mask;
 
     if (test && --lp->timeout) {
        reg = 100 | TIMER_CB;
@@ -3992,10 +3992,10 @@ PCI_signature(char *name, struct de4x5_private *lp)
                             )))))));
        }
        if (lp->chipset != DC21041) {
-           lp->useSROM = TRUE;             /* card is not recognisably DEC */
+           lp->useSROM = true;             /* card is not recognisably DEC */
        }
     } else if ((lp->chipset & ~0x00ff) == DC2114x) {
-       lp->useSROM = TRUE;
+       lp->useSROM = true;
     }
 
     return status;
@@ -4216,7 +4216,7 @@ srom_repair(struct net_device *dev, int card)
        memset((char *)&lp->srom, 0, sizeof(struct de4x5_srom));
        memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
        memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
-       lp->useSROM = TRUE;
+       lp->useSROM = true;
        break;
     }
 
@@ -4392,7 +4392,7 @@ srom_infoleaf_info(struct net_device *dev)
        if (lp->chipset == infoleaf_array[i].chipset) break;
     }
     if (i == INFOLEAF_SIZE) {
-       lp->useSROM = FALSE;
+       lp->useSROM = false;
        printk("%s: Cannot find correct chipset for SROM decoding!\n",
                                                                  dev->name);
        return -ENXIO;
@@ -4409,7 +4409,7 @@ srom_infoleaf_info(struct net_device *dev)
            if (lp->device == *p) break;
        }
        if (i == 0) {
-           lp->useSROM = FALSE;
+           lp->useSROM = false;
            printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n",
                                                       dev->name, lp->device);
            return -ENXIO;
@@ -4542,7 +4542,7 @@ dc21140_infoleaf(struct net_device *dev)
        }
        lp->media = INIT;
        lp->tcount = 0;
-       lp->tx_enable = FALSE;
+       lp->tx_enable = false;
     }
 
     return next_tick & ~TIMER_CB;
@@ -4577,7 +4577,7 @@ dc21142_infoleaf(struct net_device *dev)
        }
        lp->media = INIT;
        lp->tcount = 0;
-       lp->tx_enable = FALSE;
+       lp->tx_enable = false;
     }
 
     return next_tick & ~TIMER_CB;
@@ -4611,7 +4611,7 @@ dc21143_infoleaf(struct net_device *dev)
        }
        lp->media = INIT;
        lp->tcount = 0;
-       lp->tx_enable = FALSE;
+       lp->tx_enable = false;
     }
 
     return next_tick & ~TIMER_CB;
@@ -4650,7 +4650,7 @@ compact_infoblock(struct net_device *dev, u_char count, u_char *p)
        lp->asBit = 1 << ((csr6 >> 1) & 0x07);
        lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
        lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
-       lp->useMII = FALSE;
+       lp->useMII = false;
 
        de4x5_switch_mac_port(dev);
     }
@@ -4691,7 +4691,7 @@ type0_infoblock(struct net_device *dev, u_char count, u_char *p)
        lp->asBit = 1 << ((csr6 >> 1) & 0x07);
        lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
        lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
-       lp->useMII = FALSE;
+       lp->useMII = false;
 
        de4x5_switch_mac_port(dev);
     }
@@ -4731,7 +4731,7 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p)
         lp->ibn = 1;
         lp->active = *p;
        lp->infoblock_csr6 = OMR_MII_100;
-       lp->useMII = TRUE;
+       lp->useMII = true;
        lp->infoblock_media = ANS;
 
        de4x5_switch_mac_port(dev);
@@ -4773,7 +4773,7 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p)
         lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
         lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16);
        lp->infoblock_csr6 = OMR_SIA;
-       lp->useMII = FALSE;
+       lp->useMII = false;
 
        de4x5_switch_mac_port(dev);
     }
@@ -4814,7 +4814,7 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p)
        lp->active = *p;
        if (MOTO_SROM_BUG) lp->active = 0;
        lp->infoblock_csr6 = OMR_MII_100;
-       lp->useMII = TRUE;
+       lp->useMII = true;
        lp->infoblock_media = ANS;
 
        de4x5_switch_mac_port(dev);
@@ -4856,7 +4856,7 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p)
        lp->asBit = 1 << ((csr6 >> 1) & 0x07);
        lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
        lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
-       lp->useMII = FALSE;
+       lp->useMII = false;
 
        de4x5_switch_mac_port(dev);
     }
@@ -5077,7 +5077,7 @@ mii_get_phy(struct net_device *dev)
     int id;
 
     lp->active = 0;
-    lp->useMII = TRUE;
+    lp->useMII = true;
 
     /* Search the MII address space for possible PHY devices */
     for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(i+1)%DE4X5_MAX_MII) {
@@ -5127,7 +5127,7 @@ mii_get_phy(struct net_device *dev)
            de4x5_dbg_mii(dev, k);
        }
     }
-    if (!lp->mii_cnt) lp->useMII = FALSE;
+    if (!lp->mii_cnt) lp->useMII = false;
 
     return lp->mii_cnt;
 }
index 57226e5eb8a680993a9f227b2e133485b244f247..12af0cc037fbf3859ebd55f8223ebfc9899d78c6 100644 (file)
 #define ALL                  0     /* Clear out all the setup frame */
 #define PHYS_ADDR_ONLY       1     /* Update the physical address only */
 
-/*
-** Booleans
-*/
-#define NO                   0
-#define FALSE                0
-
-#define YES                  ~0
-#define TRUE                 ~0
-
 /*
 ** Adapter state
 */
index a12f576391cf3150d2716b040e6bc06d1eb93844..86b6908433620428c345077b0ac3c86144afcfa7 100644 (file)
@@ -192,7 +192,7 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf)
                                usb_pipeendpoint(pipe), maxp, period);
                }
        }
-       return  0;
+       return 0;
 }
 
 /* Passes this packet up the stack, updating its accounting.
@@ -326,7 +326,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
        if (netif_running (dev->net)
                        && netif_device_present (dev->net)
                        && !test_bit (EVENT_RX_HALT, &dev->flags)) {
-               switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
+               switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
                case -EPIPE:
                        usbnet_defer_kevent (dev, EVENT_RX_HALT);
                        break;
@@ -393,8 +393,8 @@ static void rx_complete (struct urb *urb)
        entry->urb = NULL;
 
        switch (urb_status) {
-           // success
-           case 0:
+       /* success */
+       case 0:
                if (skb->len < dev->net->hard_header_len) {
                        entry->state = rx_cleanup;
                        dev->stats.rx_errors++;
@@ -404,28 +404,30 @@ static void rx_complete (struct urb *urb)
                }
                break;
 
-           // stalls need manual reset. this is rare ... except that
-           // when going through USB 2.0 TTs, unplug appears this way.
-           // we avoid the highspeed version of the ETIMEOUT/EILSEQ
-           // storm, recovering as needed.
-           case -EPIPE:
+       /* stalls need manual reset. this is rare ... except that
+        * when going through USB 2.0 TTs, unplug appears this way.
+        * we avoid the highspeed version of the ETIMEOUT/EILSEQ
+        * storm, recovering as needed.
+        */
+       case -EPIPE:
                dev->stats.rx_errors++;
                usbnet_defer_kevent (dev, EVENT_RX_HALT);
                // FALLTHROUGH
 
-           // software-driven interface shutdown
-           case -ECONNRESET:           // async unlink
-           case -ESHUTDOWN:            // hardware gone
+       /* software-driven interface shutdown */
+       case -ECONNRESET:               /* async unlink */
+       case -ESHUTDOWN:                /* hardware gone */
                if (netif_msg_ifdown (dev))
                        devdbg (dev, "rx shutdown, code %d", urb_status);
                goto block;
 
-           // we get controller i/o faults during khubd disconnect() delays.
-           // throttle down resubmits, to avoid log floods; just temporarily,
-           // so we still recover when the fault isn't a khubd delay.
-           case -EPROTO:
-           case -ETIME:
-           case -EILSEQ:
+       /* we get controller i/o faults during khubd disconnect() delays.
+        * throttle down resubmits, to avoid log floods; just temporarily,
+        * so we still recover when the fault isn't a khubd delay.
+        */
+       case -EPROTO:
+       case -ETIME:
+       case -EILSEQ:
                dev->stats.rx_errors++;
                if (!timer_pending (&dev->delay)) {
                        mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
@@ -438,12 +440,12 @@ block:
                urb = NULL;
                break;
 
-           // data overrun ... flush fifo?
-           case -EOVERFLOW:
+       /* data overrun ... flush fifo? */
+       case -EOVERFLOW:
                dev->stats.rx_over_errors++;
                // FALLTHROUGH
 
-           default:
+       default:
                entry->state = rx_cleanup;
                dev->stats.rx_errors++;
                if (netif_msg_rx_err (dev))
@@ -471,22 +473,22 @@ static void intr_complete (struct urb *urb)
        int             status = urb->status;
 
        switch (status) {
-           /* success */
-           case 0:
+       /* success */
+       case 0:
                dev->driver_info->status(dev, urb);
                break;
 
-           /* software-driven interface shutdown */
-           case -ENOENT:               // urb killed
-           case -ESHUTDOWN:            // hardware gone
+       /* software-driven interface shutdown */
+       case -ENOENT:           /* urb killed */
+       case -ESHUTDOWN:        /* hardware gone */
                if (netif_msg_ifdown (dev))
                        devdbg (dev, "intr shutdown, code %d", status);
                return;
 
-           /* NOTE:  not throttling like RX/TX, since this endpoint
-            * already polls infrequently
-            */
-           default:
+       /* NOTE:  not throttling like RX/TX, since this endpoint
+        * already polls infrequently
+        */
+       default:
                devdbg (dev, "intr status %d", status);
                break;
        }
@@ -569,9 +571,9 @@ static int usbnet_stop (struct net_device *net)
        temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
 
        // maybe wait for deletions to finish.
-       while (!skb_queue_empty(&dev->rxq) &&
-              !skb_queue_empty(&dev->txq) &&
-              !skb_queue_empty(&dev->done)) {
+       while (!skb_queue_empty(&dev->rxq)
+                       && !skb_queue_empty(&dev->txq)
+                       && !skb_queue_empty(&dev->done)) {
                msleep(UNLINK_TIMEOUT_MS);
                if (netif_msg_ifdown (dev))
                        devdbg (dev, "waited for %d urb completions", temp);
@@ -1011,16 +1013,16 @@ static void usbnet_bh (unsigned long param)
        while ((skb = skb_dequeue (&dev->done))) {
                entry = (struct skb_data *) skb->cb;
                switch (entry->state) {
-                   case rx_done:
+               case rx_done:
                        entry->state = rx_cleanup;
                        rx_process (dev, skb);
                        continue;
-                   case tx_done:
-                   case rx_cleanup:
+               case tx_done:
+               case rx_cleanup:
                        usb_free_urb (entry->urb);
                        dev_kfree_skb (skb);
                        continue;
-                   default:
+               default:
                        devdbg (dev, "bogus skb state %d", entry->state);
                }
        }
index a3f8b9e7bc00551d12690555d412ed28a9c9d55c..a6c5820767de7f52920d1904ca1149b721c2f3f3 100644 (file)
@@ -47,7 +47,7 @@ struct usbnet {
        unsigned long           data [5];
        u32                     xid;
        u32                     hard_mtu;       /* count any extra framing */
-       size_t                  rx_urb_size;    /* size for rx urbs  */
+       size_t                  rx_urb_size;    /* size for rx urbs */
        struct mii_if_info      mii;
 
        /* various kinds of pending driver work */
@@ -85,7 +85,7 @@ struct driver_info {
 #define FLAG_NO_SETINT 0x0010          /* device can't set_interface() */
 #define FLAG_ETHER     0x0020          /* maybe use "eth%d" names */
 
-#define FLAG_FRAMING_AX 0x0040          /* AX88772/178 packets */
+#define FLAG_FRAMING_AX 0x0040         /* AX88772/178 packets */
 
        /* init device ... can sleep, or cause probe() failure */
        int     (*bind)(struct usbnet *, struct usb_interface *);
@@ -146,9 +146,9 @@ extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
 
 /* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
 #define        DEFAULT_FILTER  (USB_CDC_PACKET_TYPE_BROADCAST \
-                       |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
-                       |USB_CDC_PACKET_TYPE_PROMISCUOUS \
-                       |USB_CDC_PACKET_TYPE_DIRECTED)
+                       |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+                       |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+                       |USB_CDC_PACKET_TYPE_DIRECTED)
 
 
 /* we record the state for each of our queued skbs */
index fa2399cbd5cab472074b51d64a117bff1feb1d59..ae27af0141c02ee5b6100aa7f512dfdd77c4e703 100644 (file)
@@ -546,6 +546,18 @@ config USB_ZD1201
          To compile this driver as a module, choose M here: the
          module will be called zd1201.
 
+config RTL8187
+       tristate "Realtek 8187 USB support"
+       depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+       select EEPROM_93CX6
+       ---help---
+         This is a driver for RTL8187 based cards.
+         These are USB based chips found in cards such as:
+
+         Netgear WG111v2
+
+         Thanks to Realtek for their support!
+
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
index d2124602263bf8f193d575428f1fc3b11825cece..ef35bc6c4a228491723bd6c4efc9d5816dd8009b 100644 (file)
@@ -44,3 +44,6 @@ obj-$(CONFIG_PCMCIA_WL3501)   += wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)       += zd1201.o
 obj-$(CONFIG_LIBERTAS_USB)     += libertas/
+
+rtl8187-objs           := rtl8187_dev.o rtl8187_rtl8225.o
+obj-$(CONFIG_RTL8187)  += rtl8187.o
index b37f1e348700c9c775dce61695bd2bde12101b6e..d779199c30d056d707ea341530ce453472f09bc2 100644 (file)
@@ -1638,7 +1638,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
                return;
        }
 
-       if (phy->analog > 1) {
+       if (phy->analog == 1) {
                value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
                value |= (baseband_attenuation << 2) & 0x003C;
        } else {
index 5b3abd54d0e504a03b22ff1e9f33ff46a3b17207..90900525379c045b89a6be172634694929d2b5e4 100644 (file)
@@ -326,7 +326,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
        char *p = page;
        struct ap_data *ap = (struct ap_data *) data;
        char *policy_txt;
-       struct list_head *ptr;
        struct mac_entry *entry;
 
        if (off != 0) {
@@ -352,14 +351,12 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
        p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
        p += sprintf(p, "MAC list:\n");
        spin_lock_bh(&ap->mac_restrictions.lock);
-       for (ptr = ap->mac_restrictions.mac_list.next;
-            ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) {
+       list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) {
                if (p - page > PAGE_SIZE - 80) {
                        p += sprintf(p, "All entries did not fit one page.\n");
                        break;
                }
 
-               entry = list_entry(ptr, struct mac_entry, list);
                p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
        }
        spin_unlock_bh(&ap->mac_restrictions.lock);
@@ -413,7 +410,6 @@ int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
 static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
                               u8 *mac)
 {
-       struct list_head *ptr;
        struct mac_entry *entry;
        int found = 0;
 
@@ -421,10 +417,7 @@ static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
                return 0;
 
        spin_lock_bh(&mac_restrictions->lock);
-       for (ptr = mac_restrictions->mac_list.next;
-            ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
-               entry = list_entry(ptr, struct mac_entry, list);
-
+       list_for_each_entry(entry, &mac_restrictions->mac_list, list) {
                if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
                        found = 1;
                        break;
@@ -519,7 +512,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
 {
        char *p = page;
        struct ap_data *ap = (struct ap_data *) data;
-       struct list_head *ptr;
+       struct sta_info *sta;
        int i;
 
        if (off > PROC_LIMIT) {
@@ -529,9 +522,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
 
        p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
        spin_lock_bh(&ap->sta_table_lock);
-       for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
-               struct sta_info *sta = (struct sta_info *) ptr;
-
+       list_for_each_entry(sta, &ap->sta_list, list) {
                if (!sta->ap)
                        continue;
 
@@ -861,7 +852,7 @@ void hostap_init_ap_proc(local_info_t *local)
 
 void hostap_free_data(struct ap_data *ap)
 {
-       struct list_head *n, *ptr;
+       struct sta_info *n, *sta;
 
        if (ap == NULL || !ap->initialized) {
                printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
@@ -875,8 +866,7 @@ void hostap_free_data(struct ap_data *ap)
        ap->crypt = ap->crypt_priv = NULL;
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 
-       list_for_each_safe(ptr, n, &ap->sta_list) {
-               struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+       list_for_each_entry_safe(sta, n, &ap->sta_list, list) {
                ap_sta_hash_del(ap, sta);
                list_del(&sta->list);
                if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
@@ -2704,6 +2694,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
 
        if (hdr->addr1[0] & 0x01) {
                /* broadcast/multicast frame - no AP related processing */
+               if (local->ap->num_sta <= 0)
+                       ret = AP_TX_DROP;
                goto out;
        }
 
@@ -3198,15 +3190,14 @@ int hostap_update_rx_stats(struct ap_data *ap,
 
 void hostap_update_rates(local_info_t *local)
 {
-       struct list_head *ptr;
+       struct sta_info *sta;
        struct ap_data *ap = local->ap;
 
        if (!ap)
                return;
 
        spin_lock_bh(&ap->sta_table_lock);
-       for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
-               struct sta_info *sta = (struct sta_info *) ptr;
+       list_for_each_entry(sta, &ap->sta_list, list) {
                prism2_check_tx_rates(sta);
        }
        spin_unlock_bh(&ap->sta_table_lock);
@@ -3242,11 +3233,10 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
 void hostap_add_wds_links(local_info_t *local)
 {
        struct ap_data *ap = local->ap;
-       struct list_head *ptr;
+       struct sta_info *sta;
 
        spin_lock_bh(&ap->sta_table_lock);
-       list_for_each(ptr, &ap->sta_list) {
-               struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+       list_for_each_entry(sta, &ap->sta_list, list) {
                if (sta->ap)
                        hostap_wds_link_oper(local, sta->addr, WDS_ADD);
        }
index c090a5aebb58d55f108da5fbe83a92ea9e64e5b6..30acd39d76a2892de5a684b9b716201c74b9da1f 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef HOSTAP_CONFIG_H
 #define HOSTAP_CONFIG_H
 
-#define PRISM2_VERSION "0.4.4-kernel"
-
 /* In the previous versions of Host AP driver, support for user space version
  * of IEEE 802.11 management (hostapd) used to be disabled in the default
  * configuration. From now on, support for hostapd is always included and it is
index ee1532b62e42e1c8d74075cdc86f7faab09984e4..30e723f65979fafa484c4102a8e61bd19445e617 100644 (file)
@@ -22,7 +22,6 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static dev_info_t dev_info = "hostap_cs";
 
 MODULE_AUTHOR("Jouni Malinen");
@@ -30,7 +29,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
                   "cards (PC Card).");
 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 
 static int ignore_cis_vcc;
@@ -910,14 +908,12 @@ static struct pcmcia_driver hostap_driver = {
 
 static int __init init_prism2_pccard(void)
 {
-       printk(KERN_INFO "%s: %s\n", dev_info, version);
        return pcmcia_register_driver(&hostap_driver);
 }
 
 static void __exit exit_prism2_pccard(void)
 {
        pcmcia_unregister_driver(&hostap_driver);
-       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 
 
index cdea7f71b9eba7e6d01fc7637da1cd1854bd5182..8c71077d653cf10a076f1c2004c93eff5ec663aa 100644 (file)
@@ -3893,8 +3893,6 @@ static void prism2_get_drvinfo(struct net_device *dev,
        local = iface->local;
 
        strncpy(info->driver, "hostap", sizeof(info->driver) - 1);
-       strncpy(info->version, PRISM2_VERSION,
-               sizeof(info->version) - 1);
        snprintf(info->fw_version, sizeof(info->fw_version) - 1,
                 "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
                 (local->sta_fw_ver >> 8) & 0xff,
index 4743426cf6add721905919080ff5ab477c9542bb..446de51bab74399d8b18db7cd07e085701327693 100644 (file)
@@ -37,7 +37,6 @@
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Host AP common routines");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 #define TX_TIMEOUT (2 * HZ)
 
index db4899ed4bb1211d4b4a9b0386f32a794638a041..0cd48d151f5ee950ee9f96e677bcfea140b1f557 100644 (file)
@@ -20,7 +20,6 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_pci";
 
 
@@ -29,7 +28,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
                   "PCI cards.");
 MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 
 /* struct local_info::hw_priv */
@@ -462,8 +460,6 @@ static struct pci_driver prism2_pci_drv_id = {
 
 static int __init init_prism2_pci(void)
 {
-       printk(KERN_INFO "%s: %s\n", dev_info, version);
-
        return pci_register_driver(&prism2_pci_drv_id);
 }
 
@@ -471,7 +467,6 @@ static int __init init_prism2_pci(void)
 static void __exit exit_prism2_pci(void)
 {
        pci_unregister_driver(&prism2_pci_drv_id);
-       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 
 
index f0fd5ecdb24dceb0f2ac8316afbbcbf17a875b85..0183df757b3ec92df8f71aa64e8e4ec8de084f22 100644 (file)
@@ -23,7 +23,6 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_plx";
 
 
@@ -32,7 +31,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
                   "cards (PLX).");
 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 
 static int ignore_cis;
@@ -623,8 +621,6 @@ static struct pci_driver prism2_plx_drv_id = {
 
 static int __init init_prism2_plx(void)
 {
-       printk(KERN_INFO "%s: %s\n", dev_info, version);
-
        return pci_register_driver(&prism2_plx_drv_id);
 }
 
@@ -632,7 +628,6 @@ static int __init init_prism2_plx(void)
 static void __exit exit_prism2_plx(void)
 {
        pci_unregister_driver(&prism2_plx_drv_id);
-       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 
 
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
new file mode 100644 (file)
index 0000000..6124e46
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Definitions for RTL8187 hardware
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * 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 RTL8187_H
+#define RTL8187_H
+
+#include "rtl818x.h"
+
+#define RTL8187_EEPROM_TXPWR_BASE      0x05
+#define RTL8187_EEPROM_MAC_ADDR                0x07
+#define RTL8187_EEPROM_TXPWR_CHAN_1    0x16    /* 3 channels */
+#define RTL8187_EEPROM_TXPWR_CHAN_6    0x1B    /* 2 channels */
+#define RTL8187_EEPROM_TXPWR_CHAN_4    0x3D    /* 2 channels */
+
+#define RTL8187_REQT_READ      0xC0
+#define RTL8187_REQT_WRITE     0x40
+#define RTL8187_REQ_GET_REG    0x05
+#define RTL8187_REQ_SET_REG    0x05
+
+#define RTL8187_MAX_RX         0x9C4
+
+struct rtl8187_rx_info {
+       struct urb *urb;
+       struct ieee80211_hw *dev;
+};
+
+struct rtl8187_rx_hdr {
+       __le16 len;
+       __le16 rate;
+       u8 noise;
+       u8 signal;
+       u8 agc;
+       u8 reserved;
+       __le64 mac_time;
+} __attribute__((packed));
+
+struct rtl8187_tx_info {
+       struct ieee80211_tx_control *control;
+       struct urb *urb;
+       struct ieee80211_hw *dev;
+};
+
+struct rtl8187_tx_hdr {
+       __le32 flags;
+#define RTL8187_TX_FLAG_NO_ENCRYPT     (1 << 15)
+#define RTL8187_TX_FLAG_MORE_FRAG      (1 << 17)
+#define RTL8187_TX_FLAG_CTS            (1 << 18)
+#define RTL8187_TX_FLAG_RTS            (1 << 23)
+       __le16 rts_duration;
+       __le16 len;
+       __le32 retry;
+} __attribute__((packed));
+
+struct rtl8187_priv {
+       /* common between rtl818x drivers */
+       struct rtl818x_csr *map;
+       void (*rf_init)(struct ieee80211_hw *);
+       int mode;
+
+       /* rtl8187 specific */
+       struct ieee80211_channel channels[14];
+       struct ieee80211_rate rates[12];
+       struct ieee80211_hw_mode modes[2];
+       struct usb_device *udev;
+       u8 *hwaddr;
+       u16 txpwr_base;
+       u8 asic_rev;
+       struct sk_buff_head rx_queue;
+};
+
+void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
+
+static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
+{
+       u8 val;
+
+       usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+                       (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+       return val;
+}
+
+static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
+{
+       __le16 val;
+
+       usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+                       (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+       return le16_to_cpu(val);
+}
+
+static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
+{
+       __le32 val;
+
+       usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+                       (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+       return le32_to_cpu(val);
+}
+
+static inline void rtl818x_iowrite8(struct rtl8187_priv *priv,
+                                   u8 *addr, u8 val)
+{
+       usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+                       (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+}
+
+static inline void rtl818x_iowrite16(struct rtl8187_priv *priv,
+                                    __le16 *addr, u16 val)
+{
+       __le16 buf = cpu_to_le16(val);
+
+       usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+                       (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
+}
+
+static inline void rtl818x_iowrite32(struct rtl8187_priv *priv,
+                                    __le32 *addr, u32 val)
+{
+       __le32 buf = cpu_to_le32(val);
+
+       usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+                       (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
+}
+
+#endif /* RTL8187_H */
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
new file mode 100644 (file)
index 0000000..cea8589
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * Linux device driver for RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Magic delays and register offsets below are taken from the original
+ * r8187 driver sources.  Thanks to Realtek for their support!
+ *
+ * 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 <linux/init.h>
+#include <linux/usb.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+#include "rtl8187_rtl8225.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_DESCRIPTION("RTL8187 USB wireless driver");
+MODULE_LICENSE("GPL");
+
+static struct usb_device_id rtl8187_table[] __devinitdata = {
+       /* Realtek */
+       {USB_DEVICE(0x0bda, 0x8187)},
+       /* Netgear */
+       {USB_DEVICE(0x0846, 0x6100)},
+       {USB_DEVICE(0x0846, 0x6a00)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, rtl8187_table);
+
+void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       data <<= 8;
+       data |= addr | 0x80;
+
+       rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF);
+       rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
+       rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
+       rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
+
+       msleep(1);
+}
+
+static void rtl8187_tx_cb(struct urb *urb)
+{
+       struct ieee80211_tx_status status = { {0} };
+       struct sk_buff *skb = (struct sk_buff *)urb->context;
+       struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
+
+       usb_free_urb(info->urb);
+       if (info->control)
+               memcpy(&status.control, info->control, sizeof(status.control));
+       kfree(info->control);
+       skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
+       status.flags |= IEEE80211_TX_STATUS_ACK;
+       ieee80211_tx_status_irqsafe(info->dev, skb, &status);
+}
+
+static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+                     struct ieee80211_tx_control *control)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       struct rtl8187_tx_hdr *hdr;
+       struct rtl8187_tx_info *info;
+       struct urb *urb;
+       u32 tmp;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
+       tmp = skb->len - sizeof(*hdr);
+       tmp |= RTL8187_TX_FLAG_NO_ENCRYPT;
+       tmp |= control->rts_cts_rate << 19;
+       tmp |= control->tx_rate << 24;
+       if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb))
+               tmp |= RTL8187_TX_FLAG_MORE_FRAG;
+       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+               tmp |= RTL8187_TX_FLAG_RTS;
+               hdr->rts_duration =
+                       ieee80211_rts_duration(dev, skb->len, control);
+       }
+       if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+               tmp |= RTL8187_TX_FLAG_CTS;
+       hdr->flags = cpu_to_le32(tmp);
+       hdr->len = 0;
+       tmp = control->retry_limit << 8;
+       hdr->retry = cpu_to_le32(tmp);
+
+       info = (struct rtl8187_tx_info *)skb->cb;
+       info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
+       info->urb = urb;
+       info->dev = dev;
+       usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
+                         hdr, skb->len, rtl8187_tx_cb, skb);
+       usb_submit_urb(urb, GFP_ATOMIC);
+
+       return 0;
+}
+
+static void rtl8187_rx_cb(struct urb *urb)
+{
+       struct sk_buff *skb = (struct sk_buff *)urb->context;
+       struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb;
+       struct ieee80211_hw *dev = info->dev;
+       struct rtl8187_priv *priv = dev->priv;
+       struct rtl8187_rx_hdr *hdr;
+       struct ieee80211_rx_status rx_status = { 0 };
+       int rate, signal;
+
+       spin_lock(&priv->rx_queue.lock);
+       if (skb->next)
+               __skb_unlink(skb, &priv->rx_queue);
+       else {
+               spin_unlock(&priv->rx_queue.lock);
+               return;
+       }
+       spin_unlock(&priv->rx_queue.lock);
+
+       if (unlikely(urb->status)) {
+               usb_free_urb(urb);
+               dev_kfree_skb_irq(skb);
+               return;
+       }
+
+       skb_put(skb, urb->actual_length);
+       hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
+       skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+
+       signal = hdr->agc >> 1;
+       rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+       if (rate > 3) { /* OFDM rate */
+               if (signal > 90)
+                       signal = 90;
+               else if (signal < 25)
+                       signal = 25;
+               signal = 90 - signal;
+       } else {        /* CCK rate */
+               if (signal > 95)
+                       signal = 95;
+               else if (signal < 30)
+                       signal = 30;
+               signal = 95 - signal;
+       }
+
+       rx_status.antenna = (hdr->signal >> 7) & 1;
+       rx_status.signal = 64 - min(hdr->noise, (u8)64);
+       rx_status.ssi = signal;
+       rx_status.rate = rate;
+       rx_status.freq = dev->conf.freq;
+       rx_status.channel = dev->conf.channel;
+       rx_status.phymode = dev->conf.phymode;
+       rx_status.mactime = le64_to_cpu(hdr->mac_time);
+       ieee80211_rx_irqsafe(dev, skb, &rx_status);
+
+       skb = dev_alloc_skb(RTL8187_MAX_RX);
+       if (unlikely(!skb)) {
+               usb_free_urb(urb);
+               /* TODO check rx queue length and refill *somewhere* */
+               return;
+       }
+
+       info = (struct rtl8187_rx_info *)skb->cb;
+       info->urb = urb;
+       info->dev = dev;
+       urb->transfer_buffer = skb_tail_pointer(skb);
+       urb->context = skb;
+       skb_queue_tail(&priv->rx_queue, skb);
+
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int rtl8187_init_urbs(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       struct urb *entry;
+       struct sk_buff *skb;
+       struct rtl8187_rx_info *info;
+
+       while (skb_queue_len(&priv->rx_queue) < 8) {
+               skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
+               if (!skb)
+                       break;
+               entry = usb_alloc_urb(0, GFP_KERNEL);
+               if (!entry) {
+                       kfree_skb(skb);
+                       break;
+               }
+               usb_fill_bulk_urb(entry, priv->udev,
+                                 usb_rcvbulkpipe(priv->udev, 1),
+                                 skb_tail_pointer(skb),
+                                 RTL8187_MAX_RX, rtl8187_rx_cb, skb);
+               info = (struct rtl8187_rx_info *)skb->cb;
+               info->urb = entry;
+               info->dev = dev;
+               skb_queue_tail(&priv->rx_queue, skb);
+               usb_submit_urb(entry, GFP_KERNEL);
+       }
+
+       return 0;
+}
+
+static int rtl8187_init_hw(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u8 reg;
+       int i;
+
+       /* reset */
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+       msleep(200);
+       rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
+       rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
+       rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
+       msleep(200);
+
+       reg = rtl818x_ioread8(priv, &priv->map->CMD);
+       reg &= (1 << 1);
+       reg |= RTL818X_CMD_RESET;
+       rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+       i = 10;
+       do {
+               msleep(2);
+               if (!(rtl818x_ioread8(priv, &priv->map->CMD) &
+                     RTL818X_CMD_RESET))
+                       break;
+       } while (--i);
+
+       if (!i) {
+               printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
+               return -ETIMEDOUT;
+       }
+
+       /* reload registers from eeprom */
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
+
+       i = 10;
+       do {
+               msleep(4);
+               if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) &
+                     RTL818X_EEPROM_CMD_CONFIG))
+                       break;
+       } while (--i);
+
+       if (!i) {
+               printk(KERN_ERR "%s: eeprom reset timeout!\n",
+                      wiphy_name(dev->wiphy));
+               return -ETIMEDOUT;
+       }
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       /* setup card */
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
+       rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
+       rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       for (i = 0; i < ETH_ALEN; i++)
+               rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
+
+       rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
+       reg &= 0x3F;
+       reg |= 0x80;
+       rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg);
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+       rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
+       rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
+
+       // TODO: set RESP_RATE and BRSR properly
+       rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
+       rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+
+       /* host_usb_init */
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+       reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
+       rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
+       rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
+       rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80);
+       msleep(100);
+
+       rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
+       rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+       rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
+       msleep(100);
+
+       priv->rf_init(dev);
+
+       rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+       reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe;
+       rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1);
+       rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10);
+       rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80);
+       rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
+       rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+
+       return 0;
+}
+
+static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
+{
+       u32 reg;
+       struct rtl8187_priv *priv = dev->priv;
+
+       reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+       /* Enable TX loopback on MAC level to avoid TX during channel
+        * changes, as this has be seen to causes problems and the
+        * card will stop work until next reset
+        */
+       rtl818x_iowrite32(priv, &priv->map->TX_CONF,
+                         reg | RTL818X_TX_CONF_LOOPBACK_MAC);
+       msleep(10);
+       rtl8225_rf_set_channel(dev, channel);
+       msleep(10);
+       rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+}
+
+static int rtl8187_open(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u32 reg;
+       int ret;
+
+       ret = rtl8187_init_hw(dev);
+       if (ret)
+               return ret;
+
+       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+
+       rtl8187_init_urbs(dev);
+
+       reg = RTL818X_RX_CONF_ONLYERLPKT |
+             RTL818X_RX_CONF_RX_AUTORESETPHY |
+             RTL818X_RX_CONF_BSSID |
+             RTL818X_RX_CONF_MGMT |
+             RTL818X_RX_CONF_CTRL |
+             RTL818X_RX_CONF_DATA |
+             (7 << 13 /* RX FIFO threshold NONE */) |
+             (7 << 10 /* MAX RX DMA */) |
+             RTL818X_RX_CONF_BROADCAST |
+             RTL818X_RX_CONF_MULTICAST |
+             RTL818X_RX_CONF_NICMAC;
+       if (priv->mode == IEEE80211_IF_TYPE_MNTR)
+               reg |= RTL818X_RX_CONF_MONITOR;
+
+       rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
+
+       reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
+       reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
+       reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+       rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
+
+       reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+       reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
+       reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+       reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
+       rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+
+       reg  = RTL818X_TX_CONF_CW_MIN |
+              (7 << 21 /* MAX TX DMA */) |
+              RTL818X_TX_CONF_NO_ICV;
+       rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+
+       reg = rtl818x_ioread8(priv, &priv->map->CMD);
+       reg |= RTL818X_CMD_TX_ENABLE;
+       reg |= RTL818X_CMD_RX_ENABLE;
+       rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+       return 0;
+}
+
+static int rtl8187_stop(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       struct rtl8187_rx_info *info;
+       struct sk_buff *skb;
+       u32 reg;
+
+       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+       reg = rtl818x_ioread8(priv, &priv->map->CMD);
+       reg &= ~RTL818X_CMD_TX_ENABLE;
+       reg &= ~RTL818X_CMD_RX_ENABLE;
+       rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+       rtl8225_rf_stop(dev);
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       while ((skb = skb_dequeue(&priv->rx_queue))) {
+               info = (struct rtl8187_rx_info *)skb->cb;
+               usb_kill_urb(info->urb);
+               kfree_skb(skb);
+       }
+       return 0;
+}
+
+static int rtl8187_add_interface(struct ieee80211_hw *dev,
+                                struct ieee80211_if_init_conf *conf)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
+       if (priv->mode != IEEE80211_IF_TYPE_MGMT)
+               return -1;
+
+       switch (conf->type) {
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_MNTR:
+               priv->mode = conf->type;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       priv->hwaddr = conf->mac_addr;
+
+       return 0;
+}
+
+static void rtl8187_remove_interface(struct ieee80211_hw *dev,
+                                    struct ieee80211_if_init_conf *conf)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       priv->mode = IEEE80211_IF_TYPE_MGMT;
+}
+
+static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       rtl8187_set_channel(dev, conf->channel);
+
+       rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+
+       if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+               rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+               rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+               rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
+               rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
+       } else {
+               rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+               rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+               rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
+               rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
+       }
+
+       rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
+       rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
+       rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
+       rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
+       return 0;
+}
+
+static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
+                                   struct ieee80211_if_conf *conf)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       int i;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
+
+       if (is_valid_ether_addr(conf->bssid))
+               rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
+       else
+               rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
+
+       return 0;
+}
+
+static const struct ieee80211_ops rtl8187_ops = {
+       .tx                     = rtl8187_tx,
+       .open                   = rtl8187_open,
+       .stop                   = rtl8187_stop,
+       .add_interface          = rtl8187_add_interface,
+       .remove_interface       = rtl8187_remove_interface,
+       .config                 = rtl8187_config,
+       .config_interface       = rtl8187_config_interface,
+};
+
+static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+       struct ieee80211_hw *dev = eeprom->data;
+       struct rtl8187_priv *priv = dev->priv;
+       u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+
+       eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
+       eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
+       eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
+       eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
+}
+
+static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+       struct ieee80211_hw *dev = eeprom->data;
+       struct rtl8187_priv *priv = dev->priv;
+       u8 reg = RTL818X_EEPROM_CMD_PROGRAM;
+
+       if (eeprom->reg_data_in)
+               reg |= RTL818X_EEPROM_CMD_WRITE;
+       if (eeprom->reg_data_out)
+               reg |= RTL818X_EEPROM_CMD_READ;
+       if (eeprom->reg_data_clock)
+               reg |= RTL818X_EEPROM_CMD_CK;
+       if (eeprom->reg_chip_select)
+               reg |= RTL818X_EEPROM_CMD_CS;
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
+       udelay(10);
+}
+
+static int __devinit rtl8187_probe(struct usb_interface *intf,
+                                  const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct ieee80211_hw *dev;
+       struct rtl8187_priv *priv;
+       struct eeprom_93cx6 eeprom;
+       struct ieee80211_channel *channel;
+       u16 txpwr, reg;
+       int err, i;
+
+       dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
+       if (!dev) {
+               printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n");
+               return -ENOMEM;
+       }
+
+       priv = dev->priv;
+
+       SET_IEEE80211_DEV(dev, &intf->dev);
+       usb_set_intfdata(intf, dev);
+       priv->udev = udev;
+
+       usb_get_dev(udev);
+
+       skb_queue_head_init(&priv->rx_queue);
+       memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
+       memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
+       priv->map = (struct rtl818x_csr *)0xFF00;
+       priv->modes[0].mode = MODE_IEEE80211G;
+       priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
+       priv->modes[0].rates = priv->rates;
+       priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
+       priv->modes[0].channels = priv->channels;
+       priv->modes[1].mode = MODE_IEEE80211B;
+       priv->modes[1].num_rates = 4;
+       priv->modes[1].rates = priv->rates;
+       priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
+       priv->modes[1].channels = priv->channels;
+       priv->mode = IEEE80211_IF_TYPE_MGMT;
+       dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+                    IEEE80211_HW_RX_INCLUDES_FCS |
+                    IEEE80211_HW_WEP_INCLUDE_IV |
+                    IEEE80211_HW_DATA_NULLFUNC_ACK;
+       dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
+       dev->queues = 1;
+       dev->max_rssi = 65;
+       dev->max_signal = 64;
+
+       for (i = 0; i < 2; i++)
+               if ((err = ieee80211_register_hwmode(dev, &priv->modes[i])))
+                       goto err_free_dev;
+
+       eeprom.data = dev;
+       eeprom.register_read = rtl8187_eeprom_register_read;
+       eeprom.register_write = rtl8187_eeprom_register_write;
+       if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
+               eeprom.width = PCI_EEPROM_WIDTH_93C66;
+       else
+               eeprom.width = PCI_EEPROM_WIDTH_93C46;
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       udelay(10);
+
+       eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR,
+                              (__le16 __force *)dev->wiphy->perm_addr, 3);
+       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+               printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly "
+                      "generated MAC address\n");
+               random_ether_addr(dev->wiphy->perm_addr);
+       }
+
+       channel = priv->channels;
+       for (i = 0; i < 3; i++) {
+               eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i,
+                                 &txpwr);
+               (*channel++).val = txpwr & 0xFF;
+               (*channel++).val = txpwr >> 8;
+       }
+       for (i = 0; i < 2; i++) {
+               eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i,
+                                 &txpwr);
+               (*channel++).val = txpwr & 0xFF;
+               (*channel++).val = txpwr >> 8;
+       }
+       for (i = 0; i < 2; i++) {
+               eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i,
+                                 &txpwr);
+               (*channel++).val = txpwr & 0xFF;
+               (*channel++).val = txpwr >> 8;
+       }
+
+       eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE,
+                         &priv->txpwr_base);
+
+       reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1;
+       rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1);
+       /* 0 means asic B-cut, we should use SW 3 wire
+        * bit-by-bit banging for radio. 1 means we can use
+        * USB specific request to write radio registers */
+       priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3;
+       rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       rtl8225_write(dev, 0, 0x1B7);
+
+       if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700)
+               priv->rf_init = rtl8225_rf_init;
+       else
+               priv->rf_init = rtl8225z2_rf_init;
+
+       rtl8225_write(dev, 0, 0x0B7);
+
+       err = ieee80211_register_hw(dev);
+       if (err) {
+               printk(KERN_ERR "rtl8187: Cannot register device\n");
+               goto err_free_dev;
+       }
+
+       printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
+              wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
+              priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
+              "rtl8225" : "rtl8225z2");
+
+       return 0;
+
+ err_free_dev:
+       ieee80211_free_hw(dev);
+       usb_set_intfdata(intf, NULL);
+       usb_put_dev(udev);
+       return err;
+}
+
+static void __devexit rtl8187_disconnect(struct usb_interface *intf)
+{
+       struct ieee80211_hw *dev = usb_get_intfdata(intf);
+       struct rtl8187_priv *priv;
+
+       if (!dev)
+               return;
+
+       ieee80211_unregister_hw(dev);
+
+       priv = dev->priv;
+       usb_put_dev(interface_to_usbdev(intf));
+       ieee80211_free_hw(dev);
+}
+
+static struct usb_driver rtl8187_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = rtl8187_table,
+       .probe          = rtl8187_probe,
+       .disconnect     = rtl8187_disconnect,
+};
+
+static int __init rtl8187_init(void)
+{
+       return usb_register(&rtl8187_driver);
+}
+
+static void __exit rtl8187_exit(void)
+{
+       usb_deregister(&rtl8187_driver);
+}
+
+module_init(rtl8187_init);
+module_exit(rtl8187_exit);
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
new file mode 100644 (file)
index 0000000..e25a09f
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+ * Radio tuning for RTL8225 on RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Magic delays, register offsets, and phy value tables below are
+ * taken from the original r8187 driver sources.  Thanks to Realtek
+ * for their support!
+ *
+ * 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 <linux/init.h>
+#include <linux/usb.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+#include "rtl8187_rtl8225.h"
+
+static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u16 reg80, reg84, reg82;
+       u32 bangdata;
+       int i;
+
+       bangdata = (data << 4) | (addr & 0xf);
+
+       reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
+       reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
+
+       reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
+       udelay(10);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       udelay(2);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+       udelay(10);
+
+       for (i = 15; i >= 0; i--) {
+               u16 reg = reg80 | (bangdata & (1 << i)) >> i;
+
+               if (i & 1)
+                       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+
+               if (!(i & 1))
+                       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+       }
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       udelay(10);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+       msleep(2);
+}
+
+static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u16 reg80, reg82, reg84;
+
+       reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+       reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+       reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+
+       reg80 &= ~(0x3 << 2);
+       reg84 &= ~0xF;
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);
+       udelay(10);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       udelay(2);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+       udelay(10);
+
+       usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+                       RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+                       addr, 0x8225, &data, sizeof(data), HZ / 2);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       udelay(10);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+       msleep(2);
+}
+
+void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       if (priv->asic_rev)
+               rtl8225_write_8051(dev, addr, data);
+       else
+               rtl8225_write_bitbang(dev, addr, data);
+}
+
+u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u16 reg80, reg82, reg84, out;
+       int i;
+
+       reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+       reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+       reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+
+       reg80 &= ~0xF;
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+       udelay(4);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+       udelay(5);
+
+       for (i = 4; i >= 0; i--) {
+               u16 reg = reg80 | ((addr >> i) & 1);
+
+               if (!(i & 1)) {
+                       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+                       udelay(1);
+               }
+
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg | (1 << 1));
+               udelay(2);
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg | (1 << 1));
+               udelay(2);
+
+               if (i & 1) {
+                       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+                       udelay(1);
+               }
+       }
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                         reg80 | (1 << 3) | (1 << 1));
+       udelay(2);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                         reg80 | (1 << 3));
+       udelay(2);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                         reg80 | (1 << 3));
+       udelay(2);
+
+       out = 0;
+       for (i = 11; i >= 0; i--) {
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg80 | (1 << 3));
+               udelay(1);
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg80 | (1 << 3) | (1 << 1));
+               udelay(2);
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg80 | (1 << 3) | (1 << 1));
+               udelay(2);
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg80 | (1 << 3) | (1 << 1));
+               udelay(2);
+
+               if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
+                       out |= 1 << i;
+
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                                 reg80 | (1 << 3));
+               udelay(2);
+       }
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+                         reg80 | (1 << 3) | (1 << 2));
+       udelay(2);
+
+       rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+       rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
+
+       return out;
+}
+
+static const u16 rtl8225bcd_rxgain[] = {
+       0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+       0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+       0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+       0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+       0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+       0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+       0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+       0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+       0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+       0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+       0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
+       0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
+};
+
+static const u8 rtl8225_agc[] = {
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
+       0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
+       0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
+       0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
+       0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
+       0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
+       0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
+       0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
+       0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
+       0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
+       0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
+       0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static const u8 rtl8225_gain[] = {
+       0x23, 0x88, 0x7c, 0xa5, /* -82dBm */
+       0x23, 0x88, 0x7c, 0xb5, /* -82dBm */
+       0x23, 0x88, 0x7c, 0xc5, /* -82dBm */
+       0x33, 0x80, 0x79, 0xc5, /* -78dBm */
+       0x43, 0x78, 0x76, 0xc5, /* -74dBm */
+       0x53, 0x60, 0x73, 0xc5, /* -70dBm */
+       0x63, 0x58, 0x70, 0xc5, /* -66dBm */
+};
+
+static const u8 rtl8225_threshold[] = {
+       0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
+};
+
+static const u8 rtl8225_tx_gain_cck_ofdm[] = {
+       0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225_tx_power_cck[] = {
+       0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+       0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+       0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+       0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+       0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+       0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225_tx_power_cck_ch14[] = {
+       0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+       0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+       0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+       0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+       0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225_tx_power_ofdm[] = {
+       0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225_chan[] = {
+       0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
+       0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
+};
+
+static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u8 cck_power, ofdm_power;
+       const u8 *tmp;
+       u32 reg;
+       int i;
+
+       cck_power = priv->channels[channel - 1].val & 0xF;
+       ofdm_power = priv->channels[channel - 1].val >> 4;
+
+       cck_power = min(cck_power, (u8)11);
+       ofdm_power = min(ofdm_power, (u8)35);
+
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+                        rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
+
+       if (channel == 14)
+               tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
+       else
+               tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
+
+       for (i = 0; i < 8; i++)
+               rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+       msleep(1); // FIXME: optional?
+
+       /* anaparam2 on */
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       rtl8225_write_phy_ofdm(dev, 2, 0x42);
+       rtl8225_write_phy_ofdm(dev, 6, 0x00);
+       rtl8225_write_phy_ofdm(dev, 8, 0x00);
+
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+                        rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
+
+       tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
+
+       rtl8225_write_phy_ofdm(dev, 5, *tmp);
+       rtl8225_write_phy_ofdm(dev, 7, *tmp);
+
+       msleep(1);
+}
+
+void rtl8225_rf_init(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       int i;
+
+       rtl8225_write(dev, 0x0, 0x067); msleep(1);
+       rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
+       rtl8225_write(dev, 0x2, 0x44D); msleep(1);
+       rtl8225_write(dev, 0x3, 0x441); msleep(1);
+       rtl8225_write(dev, 0x4, 0x486); msleep(1);
+       rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
+       rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
+       rtl8225_write(dev, 0x7, 0x82A); msleep(1);
+       rtl8225_write(dev, 0x8, 0x01F); msleep(1);
+       rtl8225_write(dev, 0x9, 0x334); msleep(1);
+       rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
+       rtl8225_write(dev, 0xB, 0x391); msleep(1);
+       rtl8225_write(dev, 0xC, 0x050); msleep(1);
+       rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
+       rtl8225_write(dev, 0xE, 0x029); msleep(1);
+       rtl8225_write(dev, 0xF, 0x914); msleep(100);
+
+       rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
+       rtl8225_write(dev, 0x2, 0x44D); msleep(200);
+
+       if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+               rtl8225_write(dev, 0x02, 0x0c4d);
+               msleep(200);
+               rtl8225_write(dev, 0x02, 0x044d);
+               msleep(100);
+               if (!(rtl8225_read(dev, 6) & (1 << 7)))
+                       printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
+                              wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+       }
+
+       rtl8225_write(dev, 0x0, 0x127);
+
+       for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
+               rtl8225_write(dev, 0x1, i + 1);
+               rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
+       }
+
+       rtl8225_write(dev, 0x0, 0x027);
+       rtl8225_write(dev, 0x0, 0x22F);
+
+       for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+               rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+               msleep(1);
+               rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+               msleep(1);
+       }
+
+       msleep(1);
+
+       rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+
+       rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
+       rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
+       rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
+       rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
+
+       rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+       rtl8225_write_phy_cck(dev, 0x19, 0x00);
+       rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+       rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+       rtl8225_write_phy_cck(dev, 0x40, 0x86);
+       rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+
+       rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
+
+       rtl8225_rf_set_tx_power(dev, 1);
+
+       /* RX antenna default to A */
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);      /* B: 0xDB */
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);     /* B: 0x10 */
+
+       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);   /* B: 0x00 */
+       msleep(1);
+       rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
+
+       /* set sensitivity */
+       rtl8225_write(dev, 0x0c, 0x50);
+       rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
+       rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
+       rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
+       rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
+       rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
+}
+
+static const u8 rtl8225z2_tx_power_cck_ch14[] = {
+       0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225z2_tx_power_cck[] = {
+       0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_ofdm[] = {
+       0x42, 0x00, 0x40, 0x00, 0x40
+};
+
+static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+       0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+       0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+       0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+       0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
+};
+
+static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       u8 cck_power, ofdm_power;
+       const u8 *tmp;
+       u32 reg;
+       int i;
+
+       cck_power = priv->channels[channel - 1].val & 0xF;
+       ofdm_power = priv->channels[channel - 1].val >> 4;
+
+       cck_power = min(cck_power, (u8)15);
+       cck_power += priv->txpwr_base & 0xF;
+       cck_power = min(cck_power, (u8)35);
+
+       ofdm_power = min(ofdm_power, (u8)15);
+       ofdm_power += priv->txpwr_base >> 4;
+       ofdm_power = min(ofdm_power, (u8)35);
+
+       if (channel == 14)
+               tmp = rtl8225z2_tx_power_cck_ch14;
+       else
+               tmp = rtl8225z2_tx_power_cck;
+
+       for (i = 0; i < 8; i++)
+               rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+                        rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+       msleep(1);
+
+       /* anaparam2 on */
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+       rtl8225_write_phy_ofdm(dev, 2, 0x42);
+       rtl8225_write_phy_ofdm(dev, 5, 0x00);
+       rtl8225_write_phy_ofdm(dev, 6, 0x40);
+       rtl8225_write_phy_ofdm(dev, 7, 0x00);
+       rtl8225_write_phy_ofdm(dev, 8, 0x40);
+
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+                        rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
+       msleep(1);
+}
+
+static const u16 rtl8225z2_rxgain[] = {
+       0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+       0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+       0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+       0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+       0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+       0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+       0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+       0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+       0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+       0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+       0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+       0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static const u8 rtl8225z2_gain_bg[] = {
+       0x23, 0x15, 0xa5, /* -82-1dBm */
+       0x23, 0x15, 0xb5, /* -82-2dBm */
+       0x23, 0x15, 0xc5, /* -82-3dBm */
+       0x33, 0x15, 0xc5, /* -78dBm */
+       0x43, 0x15, 0xc5, /* -74dBm */
+       0x53, 0x15, 0xc5, /* -70dBm */
+       0x63, 0x15, 0xc5  /* -66dBm */
+};
+
+void rtl8225z2_rf_init(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+       int i;
+
+       rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
+       rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
+       rtl8225_write(dev, 0x2, 0x44D); msleep(1);
+       rtl8225_write(dev, 0x3, 0x441); msleep(1);
+       rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
+       rtl8225_write(dev, 0x5, 0xC72); msleep(1);
+       rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
+       rtl8225_write(dev, 0x7, 0x82A); msleep(1);
+       rtl8225_write(dev, 0x8, 0x03F); msleep(1);
+       rtl8225_write(dev, 0x9, 0x335); msleep(1);
+       rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
+       rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
+       rtl8225_write(dev, 0xc, 0x850); msleep(1);
+       rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
+       rtl8225_write(dev, 0xe, 0x02B); msleep(1);
+       rtl8225_write(dev, 0xf, 0x114); msleep(100);
+
+       rtl8225_write(dev, 0x0, 0x1B7);
+
+       for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
+               rtl8225_write(dev, 0x1, i + 1);
+               rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
+       }
+
+       rtl8225_write(dev, 0x3, 0x080);
+       rtl8225_write(dev, 0x5, 0x004);
+       rtl8225_write(dev, 0x0, 0x0B7);
+       rtl8225_write(dev, 0x2, 0xc4D);
+
+       msleep(200);
+       rtl8225_write(dev, 0x2, 0x44D);
+       msleep(100);
+
+       if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+               rtl8225_write(dev, 0x02, 0x0C4D);
+               msleep(200);
+               rtl8225_write(dev, 0x02, 0x044D);
+               msleep(100);
+               if (!(rtl8225_read(dev, 6) & (1 << 7)))
+                       printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
+                              wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+       }
+
+       msleep(200);
+
+       rtl8225_write(dev, 0x0, 0x2BF);
+
+       for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+               rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+               msleep(1);
+               rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+               msleep(1);
+       }
+
+       msleep(1);
+
+       rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
+       rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
+       rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+
+       rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
+       rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
+       rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
+       rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
+
+       rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+       rtl8225_write_phy_cck(dev, 0x19, 0x00);
+       rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+       rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+       rtl8225_write_phy_cck(dev, 0x40, 0x86);
+       rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+
+       rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
+
+       rtl8225z2_rf_set_tx_power(dev, 1);
+
+       /* RX antenna default to A */
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);      /* B: 0xDB */
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);     /* B: 0x10 */
+
+       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);   /* B: 0x00 */
+       msleep(1);
+       rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
+}
+
+void rtl8225_rf_stop(struct ieee80211_hw *dev)
+{
+       u8 reg;
+       struct rtl8187_priv *priv = dev->priv;
+
+       rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       if (priv->rf_init == rtl8225_rf_init)
+               rtl8225_rf_set_tx_power(dev, channel);
+       else
+               rtl8225z2_rf_set_tx_power(dev, channel);
+
+       rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
+       msleep(10);
+}
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h
new file mode 100644 (file)
index 0000000..798ba4a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Radio tuning definitions for RTL8225 on RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * 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 RTL8187_RTL8225_H
+#define RTL8187_RTL8225_H
+
+#define RTL8225_ANAPARAM_ON    0xa0000a59
+#define RTL8225_ANAPARAM2_ON   0x860c7312
+#define RTL8225_ANAPARAM_OFF   0xa00beb59
+#define RTL8225_ANAPARAM2_OFF  0x840dec11
+
+void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data);
+u16  rtl8225_read(struct ieee80211_hw *, u8 addr);
+
+void rtl8225_rf_init(struct ieee80211_hw *);
+void rtl8225z2_rf_init(struct ieee80211_hw *);
+void rtl8225_rf_stop(struct ieee80211_hw *);
+void rtl8225_rf_set_channel(struct ieee80211_hw *, int);
+
+
+static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
+                                         u8 addr, u32 data)
+{
+       rtl8187_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev,
+                                        u8 addr, u32 data)
+{
+       rtl8187_write_phy(dev, addr, data | 0x10000);
+}
+
+#endif /* RTL8187_RTL8225_H */
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
new file mode 100644 (file)
index 0000000..283de30
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Definitions for RTL818x hardware
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * 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 RTL818X_H
+#define RTL818X_H
+
+struct rtl818x_csr {
+       u8      MAC[6];
+       u8      reserved_0[2];
+       __le32  MAR[2];
+       u8      RX_FIFO_COUNT;
+       u8      reserved_1;
+       u8      TX_FIFO_COUNT;
+       u8      BQREQ;
+       u8      reserved_2[4];
+       __le32  TSFT[2];
+       __le32  TLPDA;
+       __le32  TNPDA;
+       __le32  THPDA;
+       __le16  BRSR;
+       u8      BSSID[6];
+       u8      RESP_RATE;
+       u8      EIFS;
+       u8      reserved_3[1];
+       u8      CMD;
+#define RTL818X_CMD_TX_ENABLE          (1 << 2)
+#define RTL818X_CMD_RX_ENABLE          (1 << 3)
+#define RTL818X_CMD_RESET              (1 << 4)
+       u8      reserved_4[4];
+       __le16  INT_MASK;
+       __le16  INT_STATUS;
+#define RTL818X_INT_RX_OK              (1 <<  0)
+#define RTL818X_INT_RX_ERR             (1 <<  1)
+#define RTL818X_INT_TXL_OK             (1 <<  2)
+#define RTL818X_INT_TXL_ERR            (1 <<  3)
+#define RTL818X_INT_RX_DU              (1 <<  4)
+#define RTL818X_INT_RX_FO              (1 <<  5)
+#define RTL818X_INT_TXN_OK             (1 <<  6)
+#define RTL818X_INT_TXN_ERR            (1 <<  7)
+#define RTL818X_INT_TXH_OK             (1 <<  8)
+#define RTL818X_INT_TXH_ERR            (1 <<  9)
+#define RTL818X_INT_TXB_OK             (1 << 10)
+#define RTL818X_INT_TXB_ERR            (1 << 11)
+#define RTL818X_INT_ATIM               (1 << 12)
+#define RTL818X_INT_BEACON             (1 << 13)
+#define RTL818X_INT_TIME_OUT           (1 << 14)
+#define RTL818X_INT_TX_FO              (1 << 15)
+       __le32  TX_CONF;
+#define RTL818X_TX_CONF_LOOPBACK_MAC   (1 << 17)
+#define RTL818X_TX_CONF_NO_ICV         (1 << 19)
+#define RTL818X_TX_CONF_DISCW          (1 << 20)
+#define RTL818X_TX_CONF_R8180_ABCD     (2 << 25)
+#define RTL818X_TX_CONF_R8180_F                (3 << 25)
+#define RTL818X_TX_CONF_R8185_ABC      (4 << 25)
+#define RTL818X_TX_CONF_R8185_D                (5 << 25)
+#define RTL818X_TX_CONF_HWVER_MASK     (7 << 25)
+#define RTL818X_TX_CONF_CW_MIN         (1 << 31)
+       __le32  RX_CONF;
+#define RTL818X_RX_CONF_MONITOR                (1 <<  0)
+#define RTL818X_RX_CONF_NICMAC         (1 <<  1)
+#define RTL818X_RX_CONF_MULTICAST      (1 <<  2)
+#define RTL818X_RX_CONF_BROADCAST      (1 <<  3)
+#define RTL818X_RX_CONF_DATA           (1 << 18)
+#define RTL818X_RX_CONF_CTRL           (1 << 19)
+#define RTL818X_RX_CONF_MGMT           (1 << 20)
+#define RTL818X_RX_CONF_BSSID          (1 << 23)
+#define RTL818X_RX_CONF_RX_AUTORESETPHY        (1 << 28)
+#define RTL818X_RX_CONF_ONLYERLPKT     (1 << 31)
+       __le32  INT_TIMEOUT;
+       __le32  TBDA;
+       u8      EEPROM_CMD;
+#define RTL818X_EEPROM_CMD_READ                (1 << 0)
+#define RTL818X_EEPROM_CMD_WRITE       (1 << 1)
+#define RTL818X_EEPROM_CMD_CK          (1 << 2)
+#define RTL818X_EEPROM_CMD_CS          (1 << 3)
+#define RTL818X_EEPROM_CMD_NORMAL      (0 << 6)
+#define RTL818X_EEPROM_CMD_LOAD                (1 << 6)
+#define RTL818X_EEPROM_CMD_PROGRAM     (2 << 6)
+#define RTL818X_EEPROM_CMD_CONFIG      (3 << 6)
+       u8      CONFIG0;
+       u8      CONFIG1;
+       u8      CONFIG2;
+       __le32  ANAPARAM;
+       u8      MSR;
+#define RTL818X_MSR_NO_LINK            (0 << 2)
+#define RTL818X_MSR_ADHOC              (1 << 2)
+#define RTL818X_MSR_INFRA              (2 << 2)
+       u8      CONFIG3;
+#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6)
+       u8      CONFIG4;
+#define RTL818X_CONFIG4_POWEROFF       (1 << 6)
+#define RTL818X_CONFIG4_VCOOFF         (1 << 7)
+       u8      TESTR;
+       u8      reserved_9[2];
+       __le16  PGSELECT;
+       __le32  ANAPARAM2;
+       u8      reserved_10[12];
+       __le16  BEACON_INTERVAL;
+       __le16  ATIM_WND;
+       __le16  BEACON_INTERVAL_TIME;
+       __le16  ATIMTR_INTERVAL;
+       u8      reserved_11[4];
+       u8      PHY[4];
+       __le16  RFPinsOutput;
+       __le16  RFPinsEnable;
+       __le16  RFPinsSelect;
+       __le16  RFPinsInput;
+       __le32  RF_PARA;
+       __le32  RF_TIMING;
+       u8      GP_ENABLE;
+       u8      GPIO;
+       u8      reserved_12[10];
+       u8      TX_AGC_CTL;
+#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT                (1 << 0)
+#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT      (1 << 1)
+#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT                        (1 << 2)
+       u8      TX_GAIN_CCK;
+       u8      TX_GAIN_OFDM;
+       u8      TX_ANTENNA;
+       u8      reserved_13[16];
+       u8      WPA_CONF;
+       u8      reserved_14[3];
+       u8      SIFS;
+       u8      DIFS;
+       u8      SLOT;
+       u8      reserved_15[5];
+       u8      CW_CONF;
+#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT     (1 << 0)
+#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT  (1 << 1)
+       u8      CW_VAL;
+       u8      RATE_FALLBACK;
+       u8      reserved_16[25];
+       u8      CONFIG5;
+       u8      TX_DMA_POLLING;
+       u8      reserved_17[2];
+       __le16  CWR;
+       u8      RETRY_CTR;
+       u8      reserved_18[5];
+       __le32  RDSAR;
+       u8      reserved_19[18];
+       u16     TALLY_CNT;
+       u8      TALLY_SEL;
+} __attribute__((packed));
+
+static const struct ieee80211_rate rtl818x_rates[] = {
+       { .rate = 10,
+         .val = 0,
+         .flags = IEEE80211_RATE_CCK },
+       { .rate = 20,
+         .val = 1,
+         .flags = IEEE80211_RATE_CCK },
+       { .rate = 55,
+         .val = 2,
+         .flags = IEEE80211_RATE_CCK },
+       { .rate = 110,
+         .val = 3,
+         .flags = IEEE80211_RATE_CCK },
+       { .rate = 60,
+         .val = 4,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 90,
+         .val = 5,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 120,
+         .val = 6,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 180,
+         .val = 7,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 240,
+         .val = 8,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 360,
+         .val = 9,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 480,
+         .val = 10,
+         .flags = IEEE80211_RATE_OFDM },
+       { .rate = 540,
+         .val = 11,
+         .flags = IEEE80211_RATE_OFDM },
+};
+
+static const struct ieee80211_channel rtl818x_channels[] = {
+       { .chan = 1,
+         .freq = 2412},
+       { .chan = 2,
+         .freq = 2417},
+       { .chan = 3,
+         .freq = 2422},
+       { .chan = 4,
+         .freq = 2427},
+       { .chan = 5,
+         .freq = 2432},
+       { .chan = 6,
+         .freq = 2437},
+       { .chan = 7,
+         .freq = 2442},
+       { .chan = 8,
+         .freq = 2447},
+       { .chan = 9,
+         .freq = 2452},
+       { .chan = 10,
+         .freq = 2457},
+       { .chan = 11,
+         .freq = 2462},
+       { .chan = 12,
+         .freq = 2467},
+       { .chan = 13,
+         .freq = 2472},
+       { .chan = 14,
+         .freq = 2484}
+};
+
+#endif /* RTL818X_H */
index 6603ad5be63d09a3752913775034ce570c141797..4d505903352c3f7235f494dd01196ce2bf200221 100644 (file)
@@ -3,7 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
 zd1211rw-objs := zd_chip.o zd_ieee80211.o \
                zd_mac.o zd_netdev.o \
                zd_rf_al2230.o zd_rf_rf2959.o \
-               zd_rf_al7230b.o \
+               zd_rf_al7230b.o zd_rf_uw2453.o \
                zd_rf.o zd_usb.o zd_util.o
 
 ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
index 95b4a2a26707b2f85cf6755d07092975450aa2a8..5b624bfc01a6037b7f76c04eba638b666038987f 100644 (file)
@@ -1253,6 +1253,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
 {
        int r;
 
+       if (!zd_rf_should_update_pwr_int(&chip->rf))
+               return 0;
+
        r = update_pwr_int(chip, channel);
        if (r)
                return r;
@@ -1283,7 +1286,7 @@ static int patch_cck_gain(struct zd_chip *chip)
        int r;
        u32 value;
 
-       if (!chip->patch_cck_gain)
+       if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf))
                return 0;
 
        ZD_ASSERT(mutex_is_locked(&chip->mutex));
index ce0a5f6da0d2e3326442e1d6c913ecb681795130..79d0288c193a41f3aa31fb097f4bc3b9d8e43623 100644 (file)
@@ -608,6 +608,9 @@ enum {
 #define CR_ZD1211B_TXOP                        CTL_REG(0x0b20)
 #define CR_ZD1211B_RETRY_MAX           CTL_REG(0x0b28)
 
+/* Used to detect PLL lock */
+#define UW2453_INTR_REG                        ((zd_addr_t)0x85c1)
+
 #define CWIN_SIZE                      0x007f043f
 
 
index 549c23bcd6ccce78b752060892f0326d6b54b57d..7407409b60b19b0ee22bf3a1d6921723a31a39c4 100644 (file)
@@ -52,34 +52,38 @@ const char *zd_rf_name(u8 type)
 void zd_rf_init(struct zd_rf *rf)
 {
        memset(rf, 0, sizeof(*rf));
+
+       /* default to update channel integration, as almost all RF's do want
+        * this */
+       rf->update_channel_int = 1;
 }
 
 void zd_rf_clear(struct zd_rf *rf)
 {
+       if (rf->clear)
+               rf->clear(rf);
        ZD_MEMCLEAR(rf, sizeof(*rf));
 }
 
 int zd_rf_init_hw(struct zd_rf *rf, u8 type)
 {
-       int r, t;
+       int r = 0;
+       int t;
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
        ZD_ASSERT(mutex_is_locked(&chip->mutex));
        switch (type) {
        case RF2959_RF:
                r = zd_rf_init_rf2959(rf);
-               if (r)
-                       return r;
                break;
        case AL2230_RF:
                r = zd_rf_init_al2230(rf);
-               if (r)
-                       return r;
                break;
        case AL7230B_RF:
                r = zd_rf_init_al7230b(rf);
-               if (r)
-                       return r;
+               break;
+       case UW2453_RF:
+               r = zd_rf_init_uw2453(rf);
                break;
        default:
                dev_err(zd_chip_dev(chip),
@@ -88,6 +92,9 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
                return -ENODEV;
        }
 
+       if (r)
+               return r;
+
        rf->type = type;
 
        r = zd_chip_lock_phy_regs(chip);
index aa9cc105ce60daf199c062952cddbfb83eeb6f48..c6dfd8227f6e78b5bc76e118668a2adefd389050 100644 (file)
@@ -48,12 +48,26 @@ struct zd_rf {
 
        u8 channel;
 
+       /* whether channel integration and calibration should be updated
+        * defaults to 1 (yes) */
+       u8 update_channel_int:1;
+
+       /* whether CR47 should be patched from the EEPROM, if the appropriate
+        * flag is set in the POD. The vendor driver suggests that this should
+        * be done for all RF's, but a bug in their code prevents but their
+        * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */
+       u8 patch_cck_gain:1;
+
+       /* private RF driver data */
+       void *priv;
+
        /* RF-specific functions */
        int (*init_hw)(struct zd_rf *rf);
        int (*set_channel)(struct zd_rf *rf, u8 channel);
        int (*switch_radio_on)(struct zd_rf *rf);
        int (*switch_radio_off)(struct zd_rf *rf);
        int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
+       void (*clear)(struct zd_rf *rf);
 };
 
 const char *zd_rf_name(u8 type);
@@ -71,10 +85,24 @@ int zd_switch_radio_off(struct zd_rf *rf);
 int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
 int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
 
+static inline int zd_rf_should_update_pwr_int(struct zd_rf *rf)
+{
+       return rf->update_channel_int;
+}
+
+static inline int zd_rf_should_patch_cck_gain(struct zd_rf *rf)
+{
+       return rf->patch_cck_gain;
+}
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
 /* Functions for individual RF chips */
 
 int zd_rf_init_rf2959(struct zd_rf *rf);
 int zd_rf_init_al2230(struct zd_rf *rf);
 int zd_rf_init_al7230b(struct zd_rf *rf);
+int zd_rf_init_uw2453(struct zd_rf *rf);
 
 #endif /* _ZD_RF_H */
index 511392acfedf3f179359c840fb01b87e114f3124..e7a4ecf7b6e21483d7b4916f6c7f1c3983cd75a5 100644 (file)
@@ -432,5 +432,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
                rf->switch_radio_on = zd1211_al2230_switch_radio_on;
        }
        rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+       rf->patch_cck_gain = 1;
        return 0;
 }
index 5e5e9ddc6a7467501fe6bc891df6b3980dbb2a8b..f4e8b6ada854c54644b4ccfea7061a6ab1162c26 100644 (file)
@@ -483,6 +483,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf)
                rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
                rf->set_channel = zd1211_al7230b_set_channel;
                rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+               rf->patch_cck_gain = 1;
        }
 
        rf->switch_radio_off = al7230b_switch_radio_off;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
new file mode 100644 (file)
index 0000000..414e40d
--- /dev/null
@@ -0,0 +1,534 @@
+/* zd_rf_uw2453.c: Functions for the UW2453 RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+/* This RF programming code is based upon the code found in v2.16.0.0 of the
+ * ZyDAS vendor driver. Unlike other RF's, Ubec publish full technical specs
+ * for this RF on their website, so we're able to understand more than
+ * usual as to what is going on. Thumbs up for Ubec for doing that. */
+
+/* The 3-wire serial interface provides access to 8 write-only registers.
+ * The data format is a 4 bit register address followed by a 20 bit value. */
+#define UW2453_REGWRITE(reg, val) ((((reg) & 0xf) << 20) | ((val) & 0xfffff))
+
+/* For channel tuning, we have to configure registers 1 (synthesizer), 2 (synth
+ * fractional divide ratio) and 3 (VCO config).
+ *
+ * We configure the RF to produce an interrupt when the PLL is locked onto
+ * the configured frequency. During initialization, we run through a variety
+ * of different VCO configurations on channel 1 until we detect a PLL lock.
+ * When this happens, we remember which VCO configuration produced the lock
+ * and use it later. Actually, we use the configuration *after* the one that
+ * produced the lock, which seems odd, but it works.
+ *
+ * If we do not see a PLL lock on any standard VCO config, we fall back on an
+ * autocal configuration, which has a fixed (as opposed to per-channel) VCO
+ * config and different synth values from the standard set (divide ratio
+ * is still shared with the standard set). */
+
+/* The per-channel synth values for all standard VCO configurations. These get
+ * written to register 1. */
+static const u8 uw2453_std_synth[] = {
+       RF_CHANNEL( 1) = 0x47,
+       RF_CHANNEL( 2) = 0x47,
+       RF_CHANNEL( 3) = 0x67,
+       RF_CHANNEL( 4) = 0x67,
+       RF_CHANNEL( 5) = 0x67,
+       RF_CHANNEL( 6) = 0x67,
+       RF_CHANNEL( 7) = 0x57,
+       RF_CHANNEL( 8) = 0x57,
+       RF_CHANNEL( 9) = 0x57,
+       RF_CHANNEL(10) = 0x57,
+       RF_CHANNEL(11) = 0x77,
+       RF_CHANNEL(12) = 0x77,
+       RF_CHANNEL(13) = 0x77,
+       RF_CHANNEL(14) = 0x4f,
+};
+
+/* This table stores the synthesizer fractional divide ratio for *all* VCO
+ * configurations (both standard and autocal). These get written to register 2.
+ */
+static const u16 uw2453_synth_divide[] = {
+       RF_CHANNEL( 1) = 0x999,
+       RF_CHANNEL( 2) = 0x99b,
+       RF_CHANNEL( 3) = 0x998,
+       RF_CHANNEL( 4) = 0x99a,
+       RF_CHANNEL( 5) = 0x999,
+       RF_CHANNEL( 6) = 0x99b,
+       RF_CHANNEL( 7) = 0x998,
+       RF_CHANNEL( 8) = 0x99a,
+       RF_CHANNEL( 9) = 0x999,
+       RF_CHANNEL(10) = 0x99b,
+       RF_CHANNEL(11) = 0x998,
+       RF_CHANNEL(12) = 0x99a,
+       RF_CHANNEL(13) = 0x999,
+       RF_CHANNEL(14) = 0xccc,
+};
+
+/* Here is the data for all the standard VCO configurations. We shrink our
+ * table a little by observing that both channels in a consecutive pair share
+ * the same value. We also observe that the high 4 bits ([0:3] in the specs)
+ * are all 'Reserved' and are always set to 0x4 - we chop them off in the data
+ * below. */
+#define CHAN_TO_PAIRIDX(a) ((a - 1) / 2)
+#define RF_CHANPAIR(a,b) [CHAN_TO_PAIRIDX(a)]
+static const u16 uw2453_std_vco_cfg[][7] = {
+       { /* table 1 */
+               RF_CHANPAIR( 1,  2) = 0x664d,
+               RF_CHANPAIR( 3,  4) = 0x604d,
+               RF_CHANPAIR( 5,  6) = 0x6675,
+               RF_CHANPAIR( 7,  8) = 0x6475,
+               RF_CHANPAIR( 9, 10) = 0x6655,
+               RF_CHANPAIR(11, 12) = 0x6455,
+               RF_CHANPAIR(13, 14) = 0x6665,
+       },
+       { /* table 2 */
+               RF_CHANPAIR( 1,  2) = 0x666d,
+               RF_CHANPAIR( 3,  4) = 0x606d,
+               RF_CHANPAIR( 5,  6) = 0x664d,
+               RF_CHANPAIR( 7,  8) = 0x644d,
+               RF_CHANPAIR( 9, 10) = 0x6675,
+               RF_CHANPAIR(11, 12) = 0x6475,
+               RF_CHANPAIR(13, 14) = 0x6655,
+       },
+       { /* table 3 */
+               RF_CHANPAIR( 1,  2) = 0x665d,
+               RF_CHANPAIR( 3,  4) = 0x605d,
+               RF_CHANPAIR( 5,  6) = 0x666d,
+               RF_CHANPAIR( 7,  8) = 0x646d,
+               RF_CHANPAIR( 9, 10) = 0x664d,
+               RF_CHANPAIR(11, 12) = 0x644d,
+               RF_CHANPAIR(13, 14) = 0x6675,
+       },
+       { /* table 4 */
+               RF_CHANPAIR( 1,  2) = 0x667d,
+               RF_CHANPAIR( 3,  4) = 0x607d,
+               RF_CHANPAIR( 5,  6) = 0x665d,
+               RF_CHANPAIR( 7,  8) = 0x645d,
+               RF_CHANPAIR( 9, 10) = 0x666d,
+               RF_CHANPAIR(11, 12) = 0x646d,
+               RF_CHANPAIR(13, 14) = 0x664d,
+       },
+       { /* table 5 */
+               RF_CHANPAIR( 1,  2) = 0x6643,
+               RF_CHANPAIR( 3,  4) = 0x6043,
+               RF_CHANPAIR( 5,  6) = 0x667d,
+               RF_CHANPAIR( 7,  8) = 0x647d,
+               RF_CHANPAIR( 9, 10) = 0x665d,
+               RF_CHANPAIR(11, 12) = 0x645d,
+               RF_CHANPAIR(13, 14) = 0x666d,
+       },
+       { /* table 6 */
+               RF_CHANPAIR( 1,  2) = 0x6663,
+               RF_CHANPAIR( 3,  4) = 0x6063,
+               RF_CHANPAIR( 5,  6) = 0x6643,
+               RF_CHANPAIR( 7,  8) = 0x6443,
+               RF_CHANPAIR( 9, 10) = 0x667d,
+               RF_CHANPAIR(11, 12) = 0x647d,
+               RF_CHANPAIR(13, 14) = 0x665d,
+       },
+       { /* table 7 */
+               RF_CHANPAIR( 1,  2) = 0x6653,
+               RF_CHANPAIR( 3,  4) = 0x6053,
+               RF_CHANPAIR( 5,  6) = 0x6663,
+               RF_CHANPAIR( 7,  8) = 0x6463,
+               RF_CHANPAIR( 9, 10) = 0x6643,
+               RF_CHANPAIR(11, 12) = 0x6443,
+               RF_CHANPAIR(13, 14) = 0x667d,
+       },
+       { /* table 8 */
+               RF_CHANPAIR( 1,  2) = 0x6673,
+               RF_CHANPAIR( 3,  4) = 0x6073,
+               RF_CHANPAIR( 5,  6) = 0x6653,
+               RF_CHANPAIR( 7,  8) = 0x6453,
+               RF_CHANPAIR( 9, 10) = 0x6663,
+               RF_CHANPAIR(11, 12) = 0x6463,
+               RF_CHANPAIR(13, 14) = 0x6643,
+       },
+       { /* table 9 */
+               RF_CHANPAIR( 1,  2) = 0x664b,
+               RF_CHANPAIR( 3,  4) = 0x604b,
+               RF_CHANPAIR( 5,  6) = 0x6673,
+               RF_CHANPAIR( 7,  8) = 0x6473,
+               RF_CHANPAIR( 9, 10) = 0x6653,
+               RF_CHANPAIR(11, 12) = 0x6453,
+               RF_CHANPAIR(13, 14) = 0x6663,
+       },
+       { /* table 10 */
+               RF_CHANPAIR( 1,  2) = 0x666b,
+               RF_CHANPAIR( 3,  4) = 0x606b,
+               RF_CHANPAIR( 5,  6) = 0x664b,
+               RF_CHANPAIR( 7,  8) = 0x644b,
+               RF_CHANPAIR( 9, 10) = 0x6673,
+               RF_CHANPAIR(11, 12) = 0x6473,
+               RF_CHANPAIR(13, 14) = 0x6653,
+       },
+       { /* table 11 */
+               RF_CHANPAIR( 1,  2) = 0x665b,
+               RF_CHANPAIR( 3,  4) = 0x605b,
+               RF_CHANPAIR( 5,  6) = 0x666b,
+               RF_CHANPAIR( 7,  8) = 0x646b,
+               RF_CHANPAIR( 9, 10) = 0x664b,
+               RF_CHANPAIR(11, 12) = 0x644b,
+               RF_CHANPAIR(13, 14) = 0x6673,
+       },
+
+};
+
+/* The per-channel synth values for autocal. These get written to register 1. */
+static const u16 uw2453_autocal_synth[] = {
+       RF_CHANNEL( 1) = 0x6847,
+       RF_CHANNEL( 2) = 0x6847,
+       RF_CHANNEL( 3) = 0x6867,
+       RF_CHANNEL( 4) = 0x6867,
+       RF_CHANNEL( 5) = 0x6867,
+       RF_CHANNEL( 6) = 0x6867,
+       RF_CHANNEL( 7) = 0x6857,
+       RF_CHANNEL( 8) = 0x6857,
+       RF_CHANNEL( 9) = 0x6857,
+       RF_CHANNEL(10) = 0x6857,
+       RF_CHANNEL(11) = 0x6877,
+       RF_CHANNEL(12) = 0x6877,
+       RF_CHANNEL(13) = 0x6877,
+       RF_CHANNEL(14) = 0x684f,
+};
+
+/* The VCO configuration for autocal (all channels) */
+static const u16 UW2453_AUTOCAL_VCO_CFG = 0x6662;
+
+/* TX gain settings. The array index corresponds to the TX power integration
+ * values found in the EEPROM. The values get written to register 7. */
+static u32 uw2453_txgain[] = {
+       [0x00] = 0x0e313,
+       [0x01] = 0x0fb13,
+       [0x02] = 0x0e093,
+       [0x03] = 0x0f893,
+       [0x04] = 0x0ea93,
+       [0x05] = 0x1f093,
+       [0x06] = 0x1f493,
+       [0x07] = 0x1f693,
+       [0x08] = 0x1f393,
+       [0x09] = 0x1f35b,
+       [0x0a] = 0x1e6db,
+       [0x0b] = 0x1ff3f,
+       [0x0c] = 0x1ffff,
+       [0x0d] = 0x361d7,
+       [0x0e] = 0x37fbf,
+       [0x0f] = 0x3ff8b,
+       [0x10] = 0x3ff33,
+       [0x11] = 0x3fb3f,
+       [0x12] = 0x3ffff,
+};
+
+/* RF-specific structure */
+struct uw2453_priv {
+       /* index into synth/VCO config tables where PLL lock was found
+        * -1 means autocal */
+       int config;
+};
+
+#define UW2453_PRIV(rf) ((struct uw2453_priv *) (rf)->priv)
+
+static int uw2453_synth_set_channel(struct zd_chip *chip, int channel,
+       bool autocal)
+{
+       int r;
+       int idx = channel - 1;
+       u32 val;
+
+       if (autocal)
+               val = UW2453_REGWRITE(1, uw2453_autocal_synth[idx]);
+       else
+               val = UW2453_REGWRITE(1, uw2453_std_synth[idx]);
+
+       r = zd_rfwrite_locked(chip, val, RF_RV_BITS);
+       if (r)
+               return r;
+
+       return zd_rfwrite_locked(chip,
+               UW2453_REGWRITE(2, uw2453_synth_divide[idx]), RF_RV_BITS);
+}
+
+static int uw2453_write_vco_cfg(struct zd_chip *chip, u16 value)
+{
+       /* vendor driver always sets these upper bits even though the specs say
+        * they are reserved */
+       u32 val = 0x40000 | value;
+       return zd_rfwrite_locked(chip, UW2453_REGWRITE(3, val), RF_RV_BITS);
+}
+
+static int uw2453_init_mode(struct zd_chip *chip)
+{
+       static const u32 rv[] = {
+               UW2453_REGWRITE(0, 0x25f98), /* enter IDLE mode */
+               UW2453_REGWRITE(0, 0x25f9a), /* enter CAL_VCO mode */
+               UW2453_REGWRITE(0, 0x25f94), /* enter RX/TX mode */
+               UW2453_REGWRITE(0, 0x27fd4), /* power down RSSI circuit */
+       };
+
+       return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int uw2453_set_tx_gain_level(struct zd_chip *chip, int channel)
+{
+       u8 int_value = chip->pwr_int_values[channel - 1];
+
+       if (int_value >= ARRAY_SIZE(uw2453_txgain)) {
+               dev_dbg_f(zd_chip_dev(chip), "can't configure TX gain for "
+                         "int value %x on channel %d\n", int_value, channel);
+               return 0;
+       }
+
+       return zd_rfwrite_locked(chip,
+               UW2453_REGWRITE(7, uw2453_txgain[int_value]), RF_RV_BITS);
+}
+
+static int uw2453_init_hw(struct zd_rf *rf)
+{
+       int i, r;
+       int found_config = -1;
+       u16 intr_status;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR10,  0x89 }, { CR15,  0x20 },
+               { CR17,  0x28 }, /* 6112 no change */
+               { CR23,  0x38 }, { CR24,  0x20 }, { CR26,  0x93 },
+               { CR27,  0x15 }, { CR28,  0x3e }, { CR29,  0x00 },
+               { CR33,  0x28 }, { CR34,  0x30 },
+               { CR35,  0x43 }, /* 6112 3e->43 */
+               { CR41,  0x24 }, { CR44,  0x32 },
+               { CR46,  0x92 }, /* 6112 96->92 */
+               { CR47,  0x1e },
+               { CR48,  0x04 }, /* 5602 Roger */
+               { CR49,  0xfa }, { CR79,  0x58 }, { CR80,  0x30 },
+               { CR81,  0x30 }, { CR87,  0x0a }, { CR89,  0x04 },
+               { CR91,  0x00 }, { CR92,  0x0a }, { CR98,  0x8d },
+               { CR99,  0x28 }, { CR100, 0x02 },
+               { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
+               { CR102, 0x27 },
+               { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */
+               { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
+               { CR109, 0x13 },
+               { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
+               { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 },
+               { CR114, 0x23 }, /* 6221 27->23 */
+               { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
+               { CR116, 0x24 }, /* 6220 1c->24 */
+               { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
+               { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
+               { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
+               { CR120, 0x4f },
+               { CR121, 0x1f }, /* 6220 4f->1f */
+               { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad },
+               { CR126, 0x6c }, { CR127, 0x03 },
+               { CR128, 0x14 }, /* 6302 12->11 */
+               { CR129, 0x12 }, /* 6301 10->0f */
+               { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 },
+               { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff },
+               { CR253, 0xff },
+       };
+
+       static const u32 rv[] = {
+               UW2453_REGWRITE(4, 0x2b),    /* configure reciever gain */
+               UW2453_REGWRITE(5, 0x19e4f), /* configure transmitter gain */
+               UW2453_REGWRITE(6, 0xf81ad), /* enable RX/TX filter tuning */
+               UW2453_REGWRITE(7, 0x3fffe), /* disable TX gain in test mode */
+
+               /* enter CAL_FIL mode, TX gain set by registers, RX gain set by pins,
+                * RSSI circuit powered down, reduced RSSI range */
+               UW2453_REGWRITE(0, 0x25f9c), /* 5d01 cal_fil */
+
+               /* synthesizer configuration for channel 1 */
+               UW2453_REGWRITE(1, 0x47),
+               UW2453_REGWRITE(2, 0x999),
+
+               /* disable manual VCO band selection */
+               UW2453_REGWRITE(3, 0x7602),
+
+               /* enable manual VCO band selection, configure current level */
+               UW2453_REGWRITE(3, 0x46063),
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               return r;
+
+       r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+       if (r)
+               return r;
+
+       r = uw2453_init_mode(chip);
+       if (r)
+               return r;
+
+       /* Try all standard VCO configuration settings on channel 1 */
+       for (i = 0; i < ARRAY_SIZE(uw2453_std_vco_cfg) - 1; i++) {
+               /* Configure synthesizer for channel 1 */
+               r = uw2453_synth_set_channel(chip, 1, false);
+               if (r)
+                       return r;
+
+               /* Write VCO config */
+               r = uw2453_write_vco_cfg(chip, uw2453_std_vco_cfg[i][0]);
+               if (r)
+                       return r;
+
+               /* ack interrupt event */
+               r = zd_iowrite16_locked(chip, 0x0f, UW2453_INTR_REG);
+               if (r)
+                       return r;
+
+               /* check interrupt status */
+               r = zd_ioread16_locked(chip, &intr_status, UW2453_INTR_REG);
+               if (r)
+                       return r;
+
+               if (!intr_status & 0xf) {
+                       dev_dbg_f(zd_chip_dev(chip),
+                               "PLL locked on configuration %d\n", i);
+                       found_config = i;
+                       break;
+               }
+       }
+
+       if (found_config == -1) {
+               /* autocal */
+               dev_dbg_f(zd_chip_dev(chip),
+                       "PLL did not lock, using autocal\n");
+
+               r = uw2453_synth_set_channel(chip, 1, true);
+               if (r)
+                       return r;
+
+               r = uw2453_write_vco_cfg(chip, UW2453_AUTOCAL_VCO_CFG);
+               if (r)
+                       return r;
+       }
+
+       /* To match the vendor driver behaviour, we use the configuration after
+        * the one that produced a lock. */
+       UW2453_PRIV(rf)->config = found_config + 1;
+
+       return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int r;
+       u16 vco_cfg;
+       int config = UW2453_PRIV(rf)->config;
+       bool autocal = (config == -1);
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
+               { CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+       };
+
+       r = uw2453_synth_set_channel(chip, channel, autocal);
+       if (r)
+               return r;
+
+       if (autocal)
+               vco_cfg = UW2453_AUTOCAL_VCO_CFG;
+       else
+               vco_cfg = uw2453_std_vco_cfg[config][CHAN_TO_PAIRIDX(channel)];
+
+       r = uw2453_write_vco_cfg(chip, vco_cfg);
+       if (r)
+               return r;
+
+       r = uw2453_init_mode(chip);
+       if (r)
+               return r;
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               return r;
+
+       r = uw2453_set_tx_gain_level(chip, channel);
+       if (r)
+               return r;
+
+       return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int uw2453_switch_radio_on(struct zd_rf *rf)
+{
+       int r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x00 }, { CR251, 0x3f },
+       };
+
+       /* enter RXTX mode */
+       r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f94), RF_RV_BITS);
+       if (r)
+               return r;
+
+       if (chip->is_zd1211b)
+               ioreqs[1].value = 0x7f;
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int uw2453_switch_radio_off(struct zd_rf *rf)
+{
+       int r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x04 }, { CR251, 0x2f },
+       };
+
+       /* enter IDLE mode */
+       /* FIXME: shouldn't we go to SLEEP? sent email to zydas */
+       r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f90), RF_RV_BITS);
+       if (r)
+               return r;
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static void uw2453_clear(struct zd_rf *rf)
+{
+       kfree(rf->priv);
+}
+
+int zd_rf_init_uw2453(struct zd_rf *rf)
+{
+       rf->init_hw = uw2453_init_hw;
+       rf->set_channel = uw2453_set_channel;
+       rf->switch_radio_on = uw2453_switch_radio_on;
+       rf->switch_radio_off = uw2453_switch_radio_off;
+       rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+       rf->clear = uw2453_clear;
+       /* we have our own TX integration code */
+       rf->update_channel_int = 0;
+
+       rf->priv = kmalloc(sizeof(struct uw2453_priv), GFP_KERNEL);
+       if (rf->priv == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
index 8459549d0cee6e8c3e1375b7e3deedd9371430e4..740a2194fdde516a3196adc0e67ac3f1b627da1f 100644 (file)
@@ -54,6 +54,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
        /* ZD1211B */
        { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
index 6b76babc7fbf5ece40cce4444c7c9438f76e7597..a0ea43598515b360115108d319d4ce25aeb3071e 100644 (file)
@@ -842,12 +842,16 @@ static struct pcmcia_device_id serial_ids[] = {
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
        PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
        PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
        PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
index f544a285592343d4ac4cb9d1455a2c4e602cc2b9..36e381c6a99a69a761973cf3e61c38f226e00ee3 100644 (file)
@@ -33,7 +33,7 @@ const struct file_operations adfs_file_operations = {
        .fsync          = file_fsync,
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 const struct inode_operations adfs_file_inode_operations = {
index c8796906f584bdb2bffe406e186b4f17e6aa5c75..c314a35f09187bac060460a2fe948b4434f36c71 100644 (file)
@@ -35,7 +35,7 @@ const struct file_operations affs_file_operations = {
        .open           = affs_file_open,
        .release        = affs_file_release,
        .fsync          = file_fsync,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 const struct inode_operations affs_file_inode_operations = {
index 9c0e721d9fc219fff078507b879b92b7ae41b1fb..aede7eb66dd4f970a74021b41487a5a0a70c0616 100644 (file)
@@ -32,7 +32,7 @@ const struct file_operations afs_file_operations = {
        .aio_read       = generic_file_aio_read,
        .aio_write      = afs_file_write,
        .mmap           = generic_file_readonly_mmap,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
        .fsync          = afs_fsync,
 };
 
index 329ee473eede9514d2b6511aa9d41fc3e3884beb..521ff7caadbd687ada5ed347edc696d70168392f 100644 (file)
@@ -114,12 +114,6 @@ static int bad_file_lock(struct file *file, int cmd, struct file_lock *fl)
        return -EIO;
 }
 
-static ssize_t bad_file_sendfile(struct file *in_file, loff_t *ppos,
-                       size_t count, read_actor_t actor, void *target)
-{
-       return -EIO;
-}
-
 static ssize_t bad_file_sendpage(struct file *file, struct page *page,
                        int off, size_t len, loff_t *pos, int more)
 {
@@ -182,7 +176,6 @@ static const struct file_operations bad_file_ops =
        .aio_fsync      = bad_file_aio_fsync,
        .fasync         = bad_file_fasync,
        .lock           = bad_file_lock,
-       .sendfile       = bad_file_sendfile,
        .sendpage       = bad_file_sendpage,
        .get_unmapped_area = bad_file_get_unmapped_area,
        .check_flags    = bad_file_check_flags,
index ef4d1fa04e654f3f792840cff4db34ab82b9a1f0..24310e9ee05ad343245c0d9e881f150006c8e69f 100644 (file)
@@ -24,7 +24,7 @@ const struct file_operations bfs_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb)
index 093345f00128b841cd7a4026378f1021e2e9785d..33e46340a76666ebca0bc1b8aa3a40f44d6d1535 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1223,8 +1223,6 @@ EXPORT_SYMBOL(bio_hw_segments);
 EXPORT_SYMBOL(bio_add_page);
 EXPORT_SYMBOL(bio_add_pc_page);
 EXPORT_SYMBOL(bio_get_nr_vecs);
-EXPORT_SYMBOL(bio_map_user);
-EXPORT_SYMBOL(bio_unmap_user);
 EXPORT_SYMBOL(bio_map_kern);
 EXPORT_SYMBOL(bio_pair_release);
 EXPORT_SYMBOL(bio_split);
index ea1480a16f517d85d12de02bfde8afa53a43037c..b3e9bfa748cf99971567913492428524aa847e2b 100644 (file)
@@ -1346,7 +1346,6 @@ const struct file_operations def_blk_fops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = compat_blkdev_ioctl,
 #endif
-       .sendfile       = generic_file_sendfile,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
 };
index 7c04752b76cb88f1678e3f76cd4a2642a4a1a929..8b0cbf4a4ad0aa33dfecf6100afeb139151e5b03 100644 (file)
@@ -616,7 +616,7 @@ const struct file_operations cifs_file_ops = {
        .fsync = cifs_fsync,
        .flush = cifs_flush,
        .mmap  = cifs_file_mmap,
-       .sendfile = generic_file_sendfile,
+       .splice_read = generic_file_splice_read,
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_POSIX
        .ioctl  = cifs_ioctl,
@@ -637,7 +637,7 @@ const struct file_operations cifs_file_direct_ops = {
        .lock = cifs_lock,
        .fsync = cifs_fsync,
        .flush = cifs_flush,
-       .sendfile = generic_file_sendfile, /* BB removeme BB */
+       .splice_read = generic_file_splice_read,
 #ifdef CONFIG_CIFS_POSIX
        .ioctl  = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
@@ -656,7 +656,7 @@ const struct file_operations cifs_file_nobrl_ops = {
        .fsync = cifs_fsync,
        .flush = cifs_flush,
        .mmap  = cifs_file_mmap,
-       .sendfile = generic_file_sendfile,
+       .splice_read = generic_file_splice_read,
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_POSIX
        .ioctl  = cifs_ioctl,
@@ -676,7 +676,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
        .release = cifs_close,
        .fsync = cifs_fsync,
        .flush = cifs_flush,
-       .sendfile = generic_file_sendfile, /* BB removeme BB */
+       .splice_read = generic_file_splice_read,
 #ifdef CONFIG_CIFS_POSIX
        .ioctl  = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
index 5ef2b609ec7dd3164f3f70bfac44a281105f2691..99dbe866816d277ba5c90ccbf04ff92567725bee 100644 (file)
@@ -47,8 +47,9 @@ coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *p
 }
 
 static ssize_t
-coda_file_sendfile(struct file *coda_file, loff_t *ppos, size_t count,
-                  read_actor_t actor, void *target)
+coda_file_splice_read(struct file *coda_file, loff_t *ppos,
+                     struct pipe_inode_info *pipe, size_t count,
+                     unsigned int flags)
 {
        struct coda_file_info *cfi;
        struct file *host_file;
@@ -57,10 +58,10 @@ coda_file_sendfile(struct file *coda_file, loff_t *ppos, size_t count,
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
        host_file = cfi->cfi_container;
 
-       if (!host_file->f_op || !host_file->f_op->sendfile)
+       if (!host_file->f_op || !host_file->f_op->splice_read)
                return -EINVAL;
 
-       return host_file->f_op->sendfile(host_file, ppos, count, actor, target);
+       return host_file->f_op->splice_read(host_file, ppos, pipe, count,flags);
 }
 
 static ssize_t
@@ -295,6 +296,6 @@ const struct file_operations coda_file_operations = {
        .flush          = coda_flush,
        .release        = coda_release,
        .fsync          = coda_fsync,
-       .sendfile       = coda_file_sendfile,
+       .splice_read    = coda_file_splice_read,
 };
 
index 59288d817078879ad36c1ece17a51208488d571e..94f456fe4d9b70487686a707b9954d49895a3fb4 100644 (file)
@@ -338,16 +338,17 @@ static int ecryptfs_fasync(int fd, struct file *file, int flag)
        return rc;
 }
 
-static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
-                                size_t count, read_actor_t actor, void *target)
+static ssize_t ecryptfs_splice_read(struct file *file, loff_t * ppos,
+                                   struct pipe_inode_info *pipe, size_t count,
+                                   unsigned int flags)
 {
        struct file *lower_file = NULL;
        int rc = -EINVAL;
 
        lower_file = ecryptfs_file_to_lower(file);
-       if (lower_file->f_op && lower_file->f_op->sendfile)
-               rc = lower_file->f_op->sendfile(lower_file, ppos, count,
-                                               actor, target);
+       if (lower_file->f_op && lower_file->f_op->splice_read)
+               rc = lower_file->f_op->splice_read(lower_file, ppos, pipe,
+                                               count, flags);
 
        return rc;
 }
@@ -364,7 +365,7 @@ const struct file_operations ecryptfs_dir_fops = {
        .release = ecryptfs_release,
        .fsync = ecryptfs_fsync,
        .fasync = ecryptfs_fasync,
-       .sendfile = ecryptfs_sendfile,
+       .splice_read = ecryptfs_splice_read,
 };
 
 const struct file_operations ecryptfs_main_fops = {
@@ -381,7 +382,7 @@ const struct file_operations ecryptfs_main_fops = {
        .release = ecryptfs_release,
        .fsync = ecryptfs_fsync,
        .fasync = ecryptfs_fasync,
-       .sendfile = ecryptfs_sendfile,
+       .splice_read = ecryptfs_splice_read,
 };
 
 static int
index 566d4e2d3852353d4e54032c417b6bd593d72fa2..04afeecaaef31acde466b50f48ea6057ac3f98a9 100644 (file)
@@ -53,7 +53,6 @@ const struct file_operations ext2_file_operations = {
        .open           = generic_file_open,
        .release        = ext2_release_file,
        .fsync          = ext2_sync_file,
-       .sendfile       = generic_file_sendfile,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
 };
@@ -71,7 +70,6 @@ const struct file_operations ext2_xip_file_operations = {
        .open           = generic_file_open,
        .release        = ext2_release_file,
        .fsync          = ext2_sync_file,
-       .sendfile       = xip_file_sendfile,
 };
 #endif
 
index 1e6f13864536e7180a465ace2ce6555256d7292f..acc4913d30199079007726e8c4a49b4a07dd77cc 100644 (file)
@@ -120,7 +120,6 @@ const struct file_operations ext3_file_operations = {
        .open           = generic_file_open,
        .release        = ext3_release_file,
        .fsync          = ext3_sync_file,
-       .sendfile       = generic_file_sendfile,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
 };
index 3c6c1fd2be902524eb1901776aa8a0b45db4a167..d4c8186aed646f6a4439b17d0b0cda9655aadf55 100644 (file)
@@ -120,7 +120,6 @@ const struct file_operations ext4_file_operations = {
        .open           = generic_file_open,
        .release        = ext4_release_file,
        .fsync          = ext4_sync_file,
-       .sendfile       = generic_file_sendfile,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
 };
index 55d3c7461c5b9acb50b851fae64df4a68dcd3d01..69a83b59dce80bdc84f1d4507e1ad74195c38690 100644 (file)
@@ -134,7 +134,7 @@ const struct file_operations fat_file_operations = {
        .release        = fat_file_release,
        .ioctl          = fat_generic_ioctl,
        .fsync          = file_fsync,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 static int fat_cont_expand(struct inode *inode, loff_t size)
index adf7995232b8b851250ed83839fdd5436c85c143..f79de7c8cdfaae3260009c86127f88ae4283cc22 100644 (file)
@@ -802,7 +802,7 @@ static const struct file_operations fuse_file_operations = {
        .release        = fuse_release,
        .fsync          = fuse_fsync,
        .lock           = fuse_file_lock,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 static const struct file_operations fuse_direct_io_file_operations = {
@@ -814,7 +814,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
        .release        = fuse_release,
        .fsync          = fuse_fsync,
        .lock           = fuse_file_lock,
-       /* no mmap and sendfile */
+       /* no mmap and splice_read */
 };
 
 static const struct address_space_operations fuse_file_aops  = {
index 550032c3b5f7e283a6f97d5534d0ba37ff442a81..196d83266e34348a66ce2042449a803568d7c07b 100644 (file)
@@ -635,7 +635,6 @@ const struct file_operations gfs2_file_fops = {
        .release        = gfs2_close,
        .fsync          = gfs2_fsync,
        .lock           = gfs2_lock,
-       .sendfile       = generic_file_sendfile,
        .flock          = gfs2_flock,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
index 9a934db0bd8ae927509a9c168ff1ee07cc167562..bc835f272a6e0a9e017aac7517e672a4ea0db5bb 100644 (file)
@@ -607,7 +607,7 @@ static const struct file_operations hfs_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
        .fsync          = file_fsync,
        .open           = hfs_file_open,
        .release        = hfs_file_release,
index 45dab5d6cc10a25f7e37a80d847566f6c4001a66..409ce5429c91ccb8b53d5a9fff6ef0118546722d 100644 (file)
@@ -288,7 +288,7 @@ static const struct file_operations hfsplus_file_operations = {
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
        .fsync          = file_fsync,
        .open           = hfsplus_file_open,
        .release        = hfsplus_file_release,
index 8286491dbf31dbccca606b241ae755d5cd77cee8..c77862032e844262a199549d01ca16489b0578f8 100644 (file)
@@ -390,7 +390,7 @@ int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 static const struct file_operations hostfs_file_fops = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
        .aio_read       = generic_file_aio_read,
        .aio_write      = generic_file_aio_write,
        .write          = do_sync_write,
index b4eafc0f1e54b40007b9831a6661012cfaa0ebe0..5b53e5c5d8dfb4cbdd4808efa6fa945a4ec4a51f 100644 (file)
@@ -129,7 +129,7 @@ const struct file_operations hpfs_file_ops =
        .mmap           = generic_file_mmap,
        .release        = hpfs_file_release,
        .fsync          = hpfs_file_fsync,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 const struct inode_operations hpfs_file_iops =
index 99871279a1edf167aa6abd63c9c1d948a56bb4e3..c2530197be0c8d6db52a3fcf2ada23ca33196a02 100644 (file)
@@ -47,7 +47,7 @@ const struct file_operations jffs2_file_operations =
        .ioctl =        jffs2_ioctl,
        .mmap =         generic_file_readonly_mmap,
        .fsync =        jffs2_fsync,
-       .sendfile =     generic_file_sendfile
+       .splice_read =  generic_file_splice_read,
 };
 
 /* jffs2_file_inode_operations */
index 79494c4f2b10c2601c20044085d10815661d34a9..fa92f7f1d0d0d709d0edeb910dd95bf3bcd8bcee 100644 (file)
@@ -29,7 +29,7 @@
        __u32 __x = (x); \
        ((__u32)( \
                ((__x & (__u32)0x000000ffUL) << 16) | \
-                (__x & (__u32)0x0000ff00UL)        | \
+                (__x & (__u32)0x0000ff00UL)        | \
                ((__x & (__u32)0x00ff0000UL) >> 16) )); \
 })
 
index f7f8eff19b7b2c4358fc58053b827fb5becd8d37..87eb93694af75832c792f1863c3edbe13d6c5c56 100644 (file)
@@ -108,7 +108,6 @@ const struct file_operations jfs_file_operations = {
        .aio_read       = generic_file_aio_read,
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
-       .sendfile       = generic_file_sendfile,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
        .fsync          = jfs_fsync,
index 9c5d59632aac98730aea6df4f5a50cac665e7a2c..887f5759e53643bdba5086363d587d82a789c5d3 100644 (file)
 #include "jfs_filsys.h"
 #include "jfs_debug.h"
 
-#ifdef CONFIG_JFS_DEBUG
-void dump_mem(char *label, void *data, int length)
-{
-       int i, j;
-       int *intptr = data;
-       char *charptr = data;
-       char buf[10], line[80];
-
-       printk("%s: dump of %d bytes of data at 0x%p\n\n", label, length,
-              data);
-       for (i = 0; i < length; i += 16) {
-               line[0] = 0;
-               for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
-                       sprintf(buf, " %08x", intptr[i / 4 + j]);
-                       strcat(line, buf);
-               }
-               buf[0] = ' ';
-               buf[2] = 0;
-               for (j = 0; (j < 16) && (i + j < length); j++) {
-                       buf[1] =
-                           isprint(charptr[i + j]) ? charptr[i + j] : '.';
-                       strcat(line, buf);
-               }
-               printk("%s\n", line);
-       }
-}
-#endif
-
 #ifdef PROC_FS_JFS /* see jfs_debug.h */
 
 static struct proc_dir_entry *base;
index 7378798f0b2151c1a0df6e9146ac9cf6b08995b1..044c1e654cc00e4f1790bd16e67ecc053944a213 100644 (file)
@@ -62,7 +62,6 @@ extern void jfs_proc_clean(void);
 
 extern int jfsloglevel;
 
-extern void dump_mem(char *label, void *data, int length);
 extern int jfs_txanchor_read(char *, char **, off_t, int, int *, void *);
 
 /* information message: e.g., configuration, major event */
@@ -94,7 +93,6 @@ extern int jfs_txanchor_read(char *, char **, off_t, int, int *, void *);
  *     ---------
  */
 #else                          /* CONFIG_JFS_DEBUG */
-#define dump_mem(label,data,length) do {} while (0)
 #define ASSERT(p) do {} while (0)
 #define jfs_info(fmt, arg...) do {} while (0)
 #define jfs_debug(fmt, arg...) do {} while (0)
index 40b20111383c5f2c07419ab41cb5103fbed57a41..c387540d34255334431ef4f02a995ae7399cb273 100644 (file)
 #define _H_JFS_DINODE
 
 /*
- *      jfs_dinode.h: on-disk inode manager
+ *     jfs_dinode.h: on-disk inode manager
  */
 
-#define INODESLOTSIZE           128
-#define L2INODESLOTSIZE         7
-#define log2INODESIZE           9      /* log2(bytes per dinode) */
+#define INODESLOTSIZE          128
+#define L2INODESLOTSIZE                7
+#define log2INODESIZE                /* log2(bytes per dinode) */
 
 
 /*
- *      on-disk inode : 512 bytes
+ *     on-disk inode : 512 bytes
  *
  * note: align 64-bit fields on 8-byte boundary.
  */
 struct dinode {
        /*
-        *      I. base area (128 bytes)
-        *      ------------------------
+        *      I. base area (128 bytes)
+        *      ------------------------
         *
         * define generic/POSIX attributes
         */
@@ -70,16 +70,16 @@ struct dinode {
        __le32 di_acltype;      /* 4: Type of ACL */
 
        /*
-        *      Extension Areas.
+        *      Extension Areas.
         *
-        *      Historically, the inode was partitioned into 4 128-byte areas,
-        *      the last 3 being defined as unions which could have multiple
-        *      uses.  The first 96 bytes had been completely unused until
-        *      an index table was added to the directory.  It is now more
-        *      useful to describe the last 3/4 of the inode as a single
-        *      union.  We would probably be better off redesigning the
-        *      entire structure from scratch, but we don't want to break
-        *      commonality with OS/2's JFS at this time.
+        *      Historically, the inode was partitioned into 4 128-byte areas,
+        *      the last 3 being defined as unions which could have multiple
+        *      uses.  The first 96 bytes had been completely unused until
+        *      an index table was added to the directory.  It is now more
+        *      useful to describe the last 3/4 of the inode as a single
+        *      union.  We would probably be better off redesigning the
+        *      entire structure from scratch, but we don't want to break
+        *      commonality with OS/2's JFS at this time.
         */
        union {
                struct {
@@ -95,7 +95,7 @@ struct dinode {
                } _dir;                                 /* (384) */
 #define di_dirtable    u._dir._table
 #define di_dtroot      u._dir._dtroot
-#define di_parent       di_dtroot.header.idotdot
+#define di_parent      di_dtroot.header.idotdot
 #define di_DASD                di_dtroot.header.DASD
 
                struct {
@@ -127,14 +127,14 @@ struct dinode {
 #define di_inlinedata  u._file._u2._special._u
 #define di_rdev                u._file._u2._special._u._rdev
 #define di_fastsymlink u._file._u2._special._u._fastsymlink
-#define di_inlineea     u._file._u2._special._inlineea
+#define di_inlineea    u._file._u2._special._inlineea
        } u;
 };
 
 /* extended mode bits (on-disk inode di_mode) */
-#define IFJOURNAL       0x00010000     /* journalled file */
-#define ISPARSE         0x00020000     /* sparse file enabled */
-#define INLINEEA        0x00040000     /* inline EA area free */
+#define IFJOURNAL      0x00010000      /* journalled file */
+#define ISPARSE                0x00020000      /* sparse file enabled */
+#define INLINEEA       0x00040000      /* inline EA area free */
 #define ISWAPFILE      0x00800000      /* file open for pager swap space */
 
 /* more extended mode bits: attributes for OS/2 */
index f3b1ebb2228036ba4fbdb2a483f0b958323ca16a..e1985066b1c63273cf5bf568ea6f9a417abb0a7a 100644 (file)
@@ -154,12 +154,12 @@ static const s8 budtab[256] = {
  *             the in-core descriptor is initialized from disk.
  *
  * PARAMETERS:
- *      ipbmap -  pointer to in-core inode for the block map.
+ *     ipbmap  - pointer to in-core inode for the block map.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOMEM        - insufficient memory
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOMEM - insufficient memory
+ *     -EIO    - i/o error
  */
 int dbMount(struct inode *ipbmap)
 {
@@ -232,11 +232,11 @@ int dbMount(struct inode *ipbmap)
  *             the memory for this descriptor is freed.
  *
  * PARAMETERS:
- *      ipbmap -  pointer to in-core inode for the block map.
+ *     ipbmap  - pointer to in-core inode for the block map.
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  */
 int dbUnmount(struct inode *ipbmap, int mounterror)
 {
@@ -320,13 +320,13 @@ int dbSync(struct inode *ipbmap)
  *             at a time.
  *
  * PARAMETERS:
- *      ip     -  pointer to in-core inode;
- *      blkno  -  starting block number to be freed.
- *      nblocks        -  number of blocks to be freed.
+ *     ip      - pointer to in-core inode;
+ *     blkno   - starting block number to be freed.
+ *     nblocks - number of blocks to be freed.
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  */
 int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
 {
@@ -395,23 +395,23 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
 /*
  * NAME:       dbUpdatePMap()
  *
- * FUNCTION:    update the allocation state (free or allocate) of the
+ * FUNCTION:   update the allocation state (free or allocate) of the
  *             specified block range in the persistent block allocation map.
  *
  *             the blocks will be updated in the persistent map one
  *             dmap at a time.
  *
  * PARAMETERS:
- *      ipbmap -  pointer to in-core inode for the block map.
- *      free   -  'true' if block range is to be freed from the persistent
- *                map; 'false' if it is to   be allocated.
- *      blkno  -  starting block number of the range.
- *      nblocks        -  number of contiguous blocks in the range.
- *      tblk   -  transaction block;
+ *     ipbmap  - pointer to in-core inode for the block map.
+ *     free    - 'true' if block range is to be freed from the persistent
+ *               map; 'false' if it is to be allocated.
+ *     blkno   - starting block number of the range.
+ *     nblocks - number of contiguous blocks in the range.
+ *     tblk    - transaction block;
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  */
 int
 dbUpdatePMap(struct inode *ipbmap,
@@ -573,7 +573,7 @@ dbUpdatePMap(struct inode *ipbmap,
 /*
  * NAME:       dbNextAG()
  *
- * FUNCTION:    find the preferred allocation group for new allocations.
+ * FUNCTION:   find the preferred allocation group for new allocations.
  *
  *             Within the allocation groups, we maintain a preferred
  *             allocation group which consists of a group with at least
@@ -589,10 +589,10 @@ dbUpdatePMap(struct inode *ipbmap,
  *             empty ags around for large allocations.
  *
  * PARAMETERS:
- *      ipbmap -  pointer to in-core inode for the block map.
+ *     ipbmap  - pointer to in-core inode for the block map.
  *
  * RETURN VALUES:
- *      the preferred allocation group number.
+ *     the preferred allocation group number.
  */
 int dbNextAG(struct inode *ipbmap)
 {
@@ -656,7 +656,7 @@ unlock:
 /*
  * NAME:       dbAlloc()
  *
- * FUNCTION:    attempt to allocate a specified number of contiguous free
+ * FUNCTION:   attempt to allocate a specified number of contiguous free
  *             blocks from the working allocation block map.
  *
  *             the block allocation policy uses hints and a multi-step
@@ -680,16 +680,16 @@ unlock:
  *             size or requests that specify no hint value.
  *
  * PARAMETERS:
- *      ip     -  pointer to in-core inode;
- *      hint   - allocation hint.
- *      nblocks        - number of contiguous blocks in the range.
- *      results        - on successful return, set to the starting block number
+ *     ip      - pointer to in-core inode;
+ *     hint    - allocation hint.
+ *     nblocks - number of contiguous blocks in the range.
+ *     results - on successful return, set to the starting block number
  *               of the newly allocated contiguous range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  */
 int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
 {
@@ -706,12 +706,6 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
        /* assert that nblocks is valid */
        assert(nblocks > 0);
 
-#ifdef _STILL_TO_PORT
-       /* DASD limit check                                     F226941 */
-       if (OVER_LIMIT(ip, nblocks))
-               return -ENOSPC;
-#endif                         /* _STILL_TO_PORT */
-
        /* get the log2 number of blocks to be allocated.
         * if the number of blocks is not a log2 multiple,
         * it will be rounded up to the next log2 multiple.
@@ -720,7 +714,6 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
 
        bmp = JFS_SBI(ip->i_sb)->bmap;
 
-//retry:        /* serialize w.r.t.extendfs() */
        mapSize = bmp->db_mapsize;
 
        /* the hint should be within the map */
@@ -879,17 +872,17 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
 /*
  * NAME:       dbAllocExact()
  *
- * FUNCTION:    try to allocate the requested extent;
+ * FUNCTION:   try to allocate the requested extent;
  *
  * PARAMETERS:
- *      ip     - pointer to in-core inode;
- *      blkno  - extent address;
- *      nblocks        - extent length;
+ *     ip      - pointer to in-core inode;
+ *     blkno   - extent address;
+ *     nblocks - extent length;
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  */
 int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
 {
@@ -946,7 +939,7 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
 /*
  * NAME:       dbReAlloc()
  *
- * FUNCTION:    attempt to extend a current allocation by a specified
+ * FUNCTION:   attempt to extend a current allocation by a specified
  *             number of blocks.
  *
  *             this routine attempts to satisfy the allocation request
@@ -959,21 +952,21 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
  *             number of blocks required.
  *
  * PARAMETERS:
- *      ip         -  pointer to in-core inode requiring allocation.
- *      blkno      -  starting block of the current allocation.
- *      nblocks            -  number of contiguous blocks within the current
+ *     ip          -  pointer to in-core inode requiring allocation.
+ *     blkno       -  starting block of the current allocation.
+ *     nblocks     -  number of contiguous blocks within the current
  *                    allocation.
- *      addnblocks  -  number of blocks to add to the allocation.
- *      results        -      on successful return, set to the starting block number
+ *     addnblocks  -  number of blocks to add to the allocation.
+ *     results -      on successful return, set to the starting block number
  *                    of the existing allocation if the existing allocation
  *                    was extended in place or to a newly allocated contiguous
  *                    range if the existing allocation could not be extended
  *                    in place.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  */
 int
 dbReAlloc(struct inode *ip,
@@ -1004,7 +997,7 @@ dbReAlloc(struct inode *ip,
 /*
  * NAME:       dbExtend()
  *
- * FUNCTION:    attempt to extend a current allocation by a specified
+ * FUNCTION:   attempt to extend a current allocation by a specified
  *             number of blocks.
  *
  *             this routine attempts to satisfy the allocation request
@@ -1013,16 +1006,16 @@ dbReAlloc(struct inode *ip,
  *             immediately following the current allocation.
  *
  * PARAMETERS:
- *      ip         -  pointer to in-core inode requiring allocation.
- *      blkno      -  starting block of the current allocation.
- *      nblocks            -  number of contiguous blocks within the current
+ *     ip          -  pointer to in-core inode requiring allocation.
+ *     blkno       -  starting block of the current allocation.
+ *     nblocks     -  number of contiguous blocks within the current
  *                    allocation.
- *      addnblocks  -  number of blocks to add to the allocation.
+ *     addnblocks  -  number of blocks to add to the allocation.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  */
 static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
 {
@@ -1109,19 +1102,19 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
 /*
  * NAME:       dbAllocNext()
  *
- * FUNCTION:    attempt to allocate the blocks of the specified block
+ * FUNCTION:   attempt to allocate the blocks of the specified block
  *             range within a dmap.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      dp     -  pointer to dmap.
- *      blkno  -  starting block number of the range.
- *      nblocks        -  number of contiguous free blocks of the range.
+ *     bmp     -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap.
+ *     blkno   -  starting block number of the range.
+ *     nblocks -  number of contiguous free blocks of the range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  */
@@ -1233,7 +1226,7 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
 /*
  * NAME:       dbAllocNear()
  *
- * FUNCTION:    attempt to allocate a number of contiguous free blocks near
+ * FUNCTION:   attempt to allocate a number of contiguous free blocks near
  *             a specified block (hint) within a dmap.
  *
  *             starting with the dmap leaf that covers the hint, we'll
@@ -1242,18 +1235,18 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
  *             the desired free space.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      dp     -  pointer to dmap.
- *      blkno  -  block number to allocate near.
- *      nblocks        -  actual number of contiguous free blocks desired.
- *      l2nb   -  log2 number of contiguous free blocks desired.
- *      results        -  on successful return, set to the starting block number
+ *     bmp     -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap.
+ *     blkno   -  block number to allocate near.
+ *     nblocks -  actual number of contiguous free blocks desired.
+ *     l2nb    -  log2 number of contiguous free blocks desired.
+ *     results -  on successful return, set to the starting block number
  *                of the newly allocated range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  */
@@ -1316,7 +1309,7 @@ dbAllocNear(struct bmap * bmp,
 /*
  * NAME:       dbAllocAG()
  *
- * FUNCTION:    attempt to allocate the specified number of contiguous
+ * FUNCTION:   attempt to allocate the specified number of contiguous
  *             free blocks within the specified allocation group.
  *
  *             unless the allocation group size is equal to the number
@@ -1353,17 +1346,17 @@ dbAllocNear(struct bmap * bmp,
  *             the allocation group.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
+ *     bmp     -  pointer to bmap descriptor
  *     agno    - allocation group number.
- *      nblocks        -  actual number of contiguous free blocks desired.
- *      l2nb   -  log2 number of contiguous free blocks desired.
- *      results        -  on successful return, set to the starting block number
+ *     nblocks -  actual number of contiguous free blocks desired.
+ *     l2nb    -  log2 number of contiguous free blocks desired.
+ *     results -  on successful return, set to the starting block number
  *                of the newly allocated range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * note: IWRITE_LOCK(ipmap) held on entry/exit;
  */
@@ -1546,7 +1539,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
 /*
  * NAME:       dbAllocAny()
  *
- * FUNCTION:    attempt to allocate the specified number of contiguous
+ * FUNCTION:   attempt to allocate the specified number of contiguous
  *             free blocks anywhere in the file system.
  *
  *             dbAllocAny() attempts to find the sufficient free space by
@@ -1556,16 +1549,16 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
  *             desired free space is allocated.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      nblocks         -  actual number of contiguous free blocks desired.
- *      l2nb    -  log2 number of contiguous free blocks desired.
- *      results        -  on successful return, set to the starting block number
+ *     bmp     -  pointer to bmap descriptor
+ *     nblocks  -  actual number of contiguous free blocks desired.
+ *     l2nb     -  log2 number of contiguous free blocks desired.
+ *     results -  on successful return, set to the starting block number
  *                of the newly allocated range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1598,9 +1591,9 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
 /*
  * NAME:       dbFindCtl()
  *
- * FUNCTION:    starting at a specified dmap control page level and block
+ * FUNCTION:   starting at a specified dmap control page level and block
  *             number, search down the dmap control levels for a range of
- *             contiguous free blocks large enough to satisfy an allocation
+ *             contiguous free blocks large enough to satisfy an allocation
  *             request for the specified number of free blocks.
  *
  *             if sufficient contiguous free blocks are found, this routine
@@ -1609,17 +1602,17 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
  *             is sufficient in size.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      level  -  starting dmap control page level.
- *      l2nb   -  log2 number of contiguous free blocks desired.
- *      *blkno -  on entry, starting block number for conducting the search.
+ *     bmp     -  pointer to bmap descriptor
+ *     level   -  starting dmap control page level.
+ *     l2nb    -  log2 number of contiguous free blocks desired.
+ *     *blkno  -  on entry, starting block number for conducting the search.
  *                on successful return, the first block within a dmap page
  *                that contains or starts a range of contiguous free blocks.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1699,7 +1692,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
 /*
  * NAME:       dbAllocCtl()
  *
- * FUNCTION:    attempt to allocate a specified number of contiguous
+ * FUNCTION:   attempt to allocate a specified number of contiguous
  *             blocks starting within a specific dmap.
  *
  *             this routine is called by higher level routines that search
@@ -1726,18 +1719,18 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
  *             first dmap (i.e. blkno).
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      nblocks         -  actual number of contiguous free blocks to allocate.
- *      l2nb    -  log2 number of contiguous free blocks to allocate.
- *      blkno   -  starting block number of the dmap to start the allocation
+ *     bmp     -  pointer to bmap descriptor
+ *     nblocks  -  actual number of contiguous free blocks to allocate.
+ *     l2nb     -  log2 number of contiguous free blocks to allocate.
+ *     blkno    -  starting block number of the dmap to start the allocation
  *                 from.
- *      results        -  on successful return, set to the starting block number
+ *     results -  on successful return, set to the starting block number
  *                of the newly allocated range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1870,7 +1863,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
 /*
  * NAME:       dbAllocDmapLev()
  *
- * FUNCTION:    attempt to allocate a specified number of contiguous blocks
+ * FUNCTION:   attempt to allocate a specified number of contiguous blocks
  *             from a specified dmap.
  *
  *             this routine checks if the contiguous blocks are available.
@@ -1878,17 +1871,17 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
  *             returned.
  *
  * PARAMETERS:
- *      mp     -  pointer to bmap descriptor
- *      dp     -  pointer to dmap to attempt to allocate blocks from.
- *      l2nb   -  log2 number of contiguous block desired.
- *      nblocks        -  actual number of contiguous block desired.
- *      results        -  on successful return, set to the starting block number
+ *     mp      -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap to attempt to allocate blocks from.
+ *     l2nb    -  log2 number of contiguous block desired.
+ *     nblocks -  actual number of contiguous block desired.
+ *     results -  on successful return, set to the starting block number
  *                of the newly allocated range.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient disk resources
- *      -EIO   - i/o error
+ *           - success
+ *     -ENOSPC - insufficient disk resources
+ *     -EIO    - i/o error
  *
  * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or
  *     IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
@@ -1933,7 +1926,7 @@ dbAllocDmapLev(struct bmap * bmp,
 /*
  * NAME:       dbAllocDmap()
  *
- * FUNCTION:    adjust the disk allocation map to reflect the allocation
+ * FUNCTION:   adjust the disk allocation map to reflect the allocation
  *             of a specified block range within a dmap.
  *
  *             this routine allocates the specified blocks from the dmap
@@ -1946,14 +1939,14 @@ dbAllocDmapLev(struct bmap * bmp,
  *             covers this dmap.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      dp     -  pointer to dmap to allocate the block range from.
- *      blkno  -  starting block number of the block to be allocated.
- *      nblocks        -  number of blocks to be allocated.
+ *     bmp     -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap to allocate the block range from.
+ *     blkno   -  starting block number of the block to be allocated.
+ *     nblocks -  number of blocks to be allocated.
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1989,7 +1982,7 @@ static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
 /*
  * NAME:       dbFreeDmap()
  *
- * FUNCTION:    adjust the disk allocation map to reflect the allocation
+ * FUNCTION:   adjust the disk allocation map to reflect the allocation
  *             of a specified block range within a dmap.
  *
  *             this routine frees the specified blocks from the dmap through
@@ -1997,18 +1990,18 @@ static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
  *             causes the maximum string of free blocks within the dmap to
  *             change (i.e. the value of the root of the dmap's dmtree), this
  *             routine will cause this change to be reflected up through the
- *             appropriate levels of the dmap control pages by a call to
+ *             appropriate levels of the dmap control pages by a call to
  *             dbAdjCtl() for the L0 dmap control page that covers this dmap.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      dp     -  pointer to dmap to free the block range from.
- *      blkno  -  starting block number of the block to be freed.
- *      nblocks        -  number of blocks to be freed.
+ *     bmp     -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap to free the block range from.
+ *     blkno   -  starting block number of the block to be freed.
+ *     nblocks -  number of blocks to be freed.
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -2055,7 +2048,7 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
 /*
  * NAME:       dbAllocBits()
  *
- * FUNCTION:    allocate a specified block range from a dmap.
+ * FUNCTION:   allocate a specified block range from a dmap.
  *
  *             this routine updates the dmap to reflect the working
  *             state allocation of the specified block range. it directly
@@ -2065,10 +2058,10 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
  *             dmap's dmtree, as a whole, to reflect the allocated range.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      dp     -  pointer to dmap to allocate bits from.
- *      blkno  -  starting block number of the bits to be allocated.
- *      nblocks        -  number of bits to be allocated.
+ *     bmp     -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap to allocate bits from.
+ *     blkno   -  starting block number of the bits to be allocated.
+ *     nblocks -  number of bits to be allocated.
  *
  * RETURN VALUES: none
  *
@@ -2149,7 +2142,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
                         * the allocated words.
                         */
                        for (; nwords > 0; nwords -= nw) {
-                               if (leaf[word] < BUDMIN) {
+                               if (leaf[word] < BUDMIN) {
                                        jfs_error(bmp->db_ipbmap->i_sb,
                                                  "dbAllocBits: leaf page "
                                                  "corrupt");
@@ -2202,7 +2195,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
 /*
  * NAME:       dbFreeBits()
  *
- * FUNCTION:    free a specified block range from a dmap.
+ * FUNCTION:   free a specified block range from a dmap.
  *
  *             this routine updates the dmap to reflect the working
  *             state allocation of the specified block range. it directly
@@ -2212,10 +2205,10 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
  *             dmtree, as a whole, to reflect the deallocated range.
  *
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      dp     -  pointer to dmap to free bits from.
- *      blkno  -  starting block number of the bits to be freed.
- *      nblocks        -  number of bits to be freed.
+ *     bmp     -  pointer to bmap descriptor
+ *     dp      -  pointer to dmap to free bits from.
+ *     blkno   -  starting block number of the bits to be freed.
+ *     nblocks -  number of bits to be freed.
  *
  * RETURN VALUES: 0 for success
  *
@@ -2388,19 +2381,19 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
  *             the new root value and the next dmap control page level to
  *             be adjusted.
  * PARAMETERS:
- *      bmp    -  pointer to bmap descriptor
- *      blkno  -  the first block of a block range within a dmap.  it is
+ *     bmp     -  pointer to bmap descriptor
+ *     blkno   -  the first block of a block range within a dmap.  it is
  *                the allocation or deallocation of this block range that
  *                requires the dmap control page to be adjusted.
- *      newval -  the new value of the lower level dmap or dmap control
+ *     newval  -  the new value of the lower level dmap or dmap control
  *                page root.
- *      alloc  -  'true' if adjustment is due to an allocation.
- *      level  -  current level of dmap control page (i.e. L0, L1, L2) to
+ *     alloc   -  'true' if adjustment is due to an allocation.
+ *     level   -  current level of dmap control page (i.e. L0, L1, L2) to
  *                be adjusted.
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -2544,16 +2537,16 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
 /*
  * NAME:       dbSplit()
  *
- * FUNCTION:    update the leaf of a dmtree with a new value, splitting
+ * FUNCTION:   update the leaf of a dmtree with a new value, splitting
  *             the leaf from the binary buddy system of the dmtree's
  *             leaves, as required.
  *
  * PARAMETERS:
- *      tp     - pointer to the tree containing the leaf.
- *      leafno - the number of the leaf to be updated.
- *      splitsz        - the size the binary buddy system starting at the leaf
+ *     tp      - pointer to the tree containing the leaf.
+ *     leafno  - the number of the leaf to be updated.
+ *     splitsz - the size the binary buddy system starting at the leaf
  *               must be split to, specified as the log2 number of blocks.
- *      newval - the new value for the leaf.
+ *     newval  - the new value for the leaf.
  *
  * RETURN VALUES: none
  *
@@ -2600,7 +2593,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
 /*
  * NAME:       dbBackSplit()
  *
- * FUNCTION:    back split the binary buddy system of dmtree leaves
+ * FUNCTION:   back split the binary buddy system of dmtree leaves
  *             that hold a specified leaf until the specified leaf
  *             starts its own binary buddy system.
  *
@@ -2617,8 +2610,8 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
  *             in which a previous join operation must be backed out.
  *
  * PARAMETERS:
- *      tp     - pointer to the tree containing the leaf.
- *      leafno - the number of the leaf to be updated.
+ *     tp      - pointer to the tree containing the leaf.
+ *     leafno  - the number of the leaf to be updated.
  *
  * RETURN VALUES: none
  *
@@ -2692,14 +2685,14 @@ static int dbBackSplit(dmtree_t * tp, int leafno)
 /*
  * NAME:       dbJoin()
  *
- * FUNCTION:    update the leaf of a dmtree with a new value, joining
+ * FUNCTION:   update the leaf of a dmtree with a new value, joining
  *             the leaf with other leaves of the dmtree into a multi-leaf
  *             binary buddy system, as required.
  *
  * PARAMETERS:
- *      tp     - pointer to the tree containing the leaf.
- *      leafno - the number of the leaf to be updated.
- *      newval - the new value for the leaf.
+ *     tp      - pointer to the tree containing the leaf.
+ *     leafno  - the number of the leaf to be updated.
+ *     newval  - the new value for the leaf.
  *
  * RETURN VALUES: none
  */
@@ -2785,15 +2778,15 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
 /*
  * NAME:       dbAdjTree()
  *
- * FUNCTION:    update a leaf of a dmtree with a new value, adjusting
+ * FUNCTION:   update a leaf of a dmtree with a new value, adjusting
  *             the dmtree, as required, to reflect the new leaf value.
  *             the combination of any buddies must already be done before
  *             this is called.
  *
  * PARAMETERS:
- *      tp     - pointer to the tree to be adjusted.
- *      leafno - the number of the leaf to be updated.
- *      newval - the new value for the leaf.
+ *     tp      - pointer to the tree to be adjusted.
+ *     leafno  - the number of the leaf to be updated.
+ *     newval  - the new value for the leaf.
  *
  * RETURN VALUES: none
  */
@@ -2852,7 +2845,7 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
 /*
  * NAME:       dbFindLeaf()
  *
- * FUNCTION:    search a dmtree_t for sufficient free blocks, returning
+ * FUNCTION:   search a dmtree_t for sufficient free blocks, returning
  *             the index of a leaf describing the free blocks if
  *             sufficient free blocks are found.
  *
@@ -2861,15 +2854,15 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
  *             free space.
  *
  * PARAMETERS:
- *      tp     - pointer to the tree to be searched.
- *      l2nb   - log2 number of free blocks to search for.
+ *     tp      - pointer to the tree to be searched.
+ *     l2nb    - log2 number of free blocks to search for.
  *     leafidx - return pointer to be set to the index of the leaf
  *               describing at least l2nb free blocks if sufficient
  *               free blocks are found.
  *
  * RETURN VALUES:
- *      0      - success
- *      -ENOSPC        - insufficient free blocks.
+ *           - success
+ *     -ENOSPC - insufficient free blocks.
  */
 static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
 {
@@ -2916,18 +2909,18 @@ static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
 /*
  * NAME:       dbFindBits()
  *
- * FUNCTION:    find a specified number of binary buddy free bits within a
+ * FUNCTION:   find a specified number of binary buddy free bits within a
  *             dmap bitmap word value.
  *
  *             this routine searches the bitmap value for (1 << l2nb) free
  *             bits at (1 << l2nb) alignments within the value.
  *
  * PARAMETERS:
- *      word   -  dmap bitmap word value.
- *      l2nb   -  number of free bits specified as a log2 number.
+ *     word    -  dmap bitmap word value.
+ *     l2nb    -  number of free bits specified as a log2 number.
  *
  * RETURN VALUES:
- *      starting bit number of free bits.
+ *     starting bit number of free bits.
  */
 static int dbFindBits(u32 word, int l2nb)
 {
@@ -2963,14 +2956,14 @@ static int dbFindBits(u32 word, int l2nb)
 /*
  * NAME:       dbMaxBud(u8 *cp)
  *
- * FUNCTION:    determine the largest binary buddy string of free
+ * FUNCTION:   determine the largest binary buddy string of free
  *             bits within 32-bits of the map.
  *
  * PARAMETERS:
- *      cp     -  pointer to the 32-bit value.
+ *     cp      -  pointer to the 32-bit value.
  *
  * RETURN VALUES:
- *      largest binary buddy of free bits within a dmap word.
+ *     largest binary buddy of free bits within a dmap word.
  */
 static int dbMaxBud(u8 * cp)
 {
@@ -3000,14 +2993,14 @@ static int dbMaxBud(u8 * cp)
 /*
  * NAME:       cnttz(uint word)
  *
- * FUNCTION:    determine the number of trailing zeros within a 32-bit
+ * FUNCTION:   determine the number of trailing zeros within a 32-bit
  *             value.
  *
  * PARAMETERS:
- *      value  -  32-bit value to be examined.
+ *     value   -  32-bit value to be examined.
  *
  * RETURN VALUES:
- *      count of trailing zeros
+ *     count of trailing zeros
  */
 static int cnttz(u32 word)
 {
@@ -3025,14 +3018,14 @@ static int cnttz(u32 word)
 /*
  * NAME:       cntlz(u32 value)
  *
- * FUNCTION:    determine the number of leading zeros within a 32-bit
+ * FUNCTION:   determine the number of leading zeros within a 32-bit
  *             value.
  *
  * PARAMETERS:
- *      value  -  32-bit value to be examined.
+ *     value   -  32-bit value to be examined.
  *
  * RETURN VALUES:
- *      count of leading zeros
+ *     count of leading zeros
  */
 static int cntlz(u32 value)
 {
@@ -3050,14 +3043,14 @@ static int cntlz(u32 value)
  * NAME:       blkstol2(s64 nb)
  *
  * FUNCTION:   convert a block count to its log2 value. if the block
- *             count is not a l2 multiple, it is rounded up to the next
+ *             count is not a l2 multiple, it is rounded up to the next
  *             larger l2 multiple.
  *
  * PARAMETERS:
- *      nb     -  number of blocks
+ *     nb      -  number of blocks
  *
  * RETURN VALUES:
- *      log2 number of blocks
+ *     log2 number of blocks
  */
 static int blkstol2(s64 nb)
 {
@@ -3099,13 +3092,13 @@ static int blkstol2(s64 nb)
  *             at a time.
  *
  * PARAMETERS:
- *      ip     -  pointer to in-core inode;
- *      blkno  -  starting block number to be freed.
- *      nblocks        -  number of blocks to be freed.
+ *     ip      -  pointer to in-core inode;
+ *     blkno   -  starting block number to be freed.
+ *     nblocks -  number of blocks to be freed.
  *
  * RETURN VALUES:
- *      0      - success
- *      -EIO   - i/o error
+ *           - success
+ *     -EIO    - i/o error
  */
 int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
 {
@@ -3278,10 +3271,10 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
  * L2
  *  |
  *   L1---------------------------------L1
- *    |                                  |
- *     L0---------L0---------L0           L0---------L0---------L0
- *      |          |          |            |          |          |
- *       d0,...,dn  d0,...,dn  d0,...,dn    d0,...,dn  d0,...,dn  d0,.,dm;
+ *    |                                         |
+ *     L0---------L0---------L0                  L0---------L0---------L0
+ *      |         |          |            |          |          |
+ *      d0,...,dn  d0,...,dn  d0,...,dn    d0,...,dn  d0,...,dn  d0,.,dm;
  * L2L1L0d0,...,dnL0d0,...,dnL0d0,...,dnL1L0d0,...,dnL0d0,...,dnL0d0,..dm
  *
  * <---old---><----------------------------extend----------------------->
@@ -3307,7 +3300,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno,   s64 nblocks)
                 (long long) blkno, (long long) nblocks, (long long) newsize);
 
        /*
-        *      initialize bmap control page.
+        *      initialize bmap control page.
         *
         * all the data in bmap control page should exclude
         * the mkfs hidden dmap page.
@@ -3330,7 +3323,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno,   s64 nblocks)
        bmp->db_numag += ((u32) newsize % (u32) bmp->db_agsize) ? 1 : 0;
 
        /*
-        *      reconfigure db_agfree[]
+        *      reconfigure db_agfree[]
         * from old AG configuration to new AG configuration;
         *
         * coalesce contiguous k (newAGSize/oldAGSize) AGs;
@@ -3362,7 +3355,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno,   s64 nblocks)
        bmp->db_maxag = bmp->db_maxag / k;
 
        /*
-        *      extend bmap
+        *      extend bmap
         *
         * update bit maps and corresponding level control pages;
         * global control page db_nfree, db_agfree[agno], db_maxfreebud;
@@ -3410,7 +3403,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno,   s64 nblocks)
                        /* compute start L0 */
                        j = 0;
                        l1leaf = l1dcp->stree + CTLLEAFIND;
-                       p += nbperpage; /* 1st L0 of L1.k  */
+                       p += nbperpage; /* 1st L0 of L1.k */
                }
 
                /*
@@ -3548,7 +3541,7 @@ errout:
        return -EIO;
 
        /*
-        *      finalize bmap control page
+        *      finalize bmap control page
         */
 finalize:
 
@@ -3567,7 +3560,7 @@ void dbFinalizeBmap(struct inode *ipbmap)
        int i, n;
 
        /*
-        *      finalize bmap control page
+        *      finalize bmap control page
         */
 //finalize:
        /*
@@ -3953,8 +3946,8 @@ static int dbGetL2AGSize(s64 nblocks)
  * convert number of map pages to the zero origin top dmapctl level
  */
 #define BMAPPGTOLEV(npages)    \
-       (((npages) <= 3 + MAXL0PAGES) ? 0 \
-       : ((npages) <= 2 + MAXL1PAGES) ? 1 : 2)
+       (((npages) <= 3 + MAXL0PAGES) ? 0 \
+        ((npages) <= 2 + MAXL1PAGES) ? 1 : 2)
 
 s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
 {
@@ -3981,8 +3974,8 @@ s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
                factor =
                    (i == 2) ? MAXL1PAGES : ((i == 1) ? MAXL0PAGES : 1);
                complete = (u32) npages / factor;
-               ndmaps += complete * ((i == 2) ? LPERCTL * LPERCTL
-                                     ((i == 1) ? LPERCTL : 1));
+               ndmaps += complete * ((i == 2) ? LPERCTL * LPERCTL :
+                                     ((i == 1) ? LPERCTL : 1));
 
                /* pages in last/incomplete child */
                npages = (u32) npages % factor;
index 45ea454c74bd03f615fac463793ace154d9a7b1f..11e6d471b364260e00ef7ebd672e106240799e7b 100644 (file)
@@ -83,7 +83,7 @@ static __inline signed char TREEMAX(signed char *cp)
  *     - 1 is added to account for the control page of the map.
  */
 #define BLKTODMAP(b,s)    \
-        ((((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) << (s))
+       ((((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) << (s))
 
 /*
  * convert disk block number to the logical block number of the LEVEL 0
@@ -98,7 +98,7 @@ static __inline signed char TREEMAX(signed char *cp)
  *     - 1 is added to account for the control page of the map.
  */
 #define BLKTOL0(b,s)      \
-        (((((b) >> 23) << 10) + ((b) >> 23) + ((b) >> 33) + 2 + 1) << (s))
+       (((((b) >> 23) << 10) + ((b) >> 23) + ((b) >> 33) + 2 + 1) << (s))
 
 /*
  * convert disk block number to the logical block number of the LEVEL 1
@@ -120,7 +120,7 @@ static __inline signed char TREEMAX(signed char *cp)
  * at the specified level which describes the disk block.
  */
 #define BLKTOCTL(b,s,l)   \
-        (((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))
+       (((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))
 
 /*
  * convert aggregate map size to the zero origin dmapctl level of the
@@ -145,27 +145,27 @@ static __inline signed char TREEMAX(signed char *cp)
  * dmaptree must be consistent with dmapctl.
  */
 struct dmaptree {
-       __le32 nleafs;          /* 4: number of tree leafs      */
-       __le32 l2nleafs;        /* 4: l2 number of tree leafs   */
-       __le32 leafidx;         /* 4: index of first tree leaf  */
-       __le32 height;          /* 4: height of the tree        */
+       __le32 nleafs;          /* 4: number of tree leafs      */
+       __le32 l2nleafs;        /* 4: l2 number of tree leafs   */
+       __le32 leafidx;         /* 4: index of first tree leaf  */
+       __le32 height;          /* 4: height of the tree        */
        s8 budmin;              /* 1: min l2 tree leaf value to combine */
-       s8 stree[TREESIZE];     /* TREESIZE: tree               */
-       u8 pad[2];              /* 2: pad to word boundary      */
-};                             /* - 360 -                      */
+       s8 stree[TREESIZE];     /* TREESIZE: tree               */
+       u8 pad[2];              /* 2: pad to word boundary      */
+};                             /* - 360 -                      */
 
 /*
  *     dmap page per 8K blocks bitmap
  */
 struct dmap {
-       __le32 nblocks;         /* 4: num blks covered by this dmap     */
-       __le32 nfree;           /* 4: num of free blks in this dmap     */
-       __le64 start;           /* 8: starting blkno for this dmap      */
-       struct dmaptree tree;   /* 360: dmap tree                       */
-       u8 pad[1672];           /* 1672: pad to 2048 bytes              */
-       __le32 wmap[LPERDMAP];  /* 1024: bits of the working map        */
-       __le32 pmap[LPERDMAP];  /* 1024: bits of the persistent map     */
-};                             /* - 4096 -                             */
+       __le32 nblocks;         /* 4: num blks covered by this dmap     */
+       __le32 nfree;           /* 4: num of free blks in this dmap     */
+       __le64 start;           /* 8: starting blkno for this dmap      */
+       struct dmaptree tree;   /* 360: dmap tree                       */
+       u8 pad[1672];           /* 1672: pad to 2048 bytes              */
+       __le32 wmap[LPERDMAP];  /* 1024: bits of the working map        */
+       __le32 pmap[LPERDMAP];  /* 1024: bits of the persistent map     */
+};                             /* - 4096 -                             */
 
 /*
  *     disk map control page per level.
@@ -173,14 +173,14 @@ struct dmap {
  * dmapctl must be consistent with dmaptree.
  */
 struct dmapctl {
-       __le32 nleafs;          /* 4: number of tree leafs      */
-       __le32 l2nleafs;        /* 4: l2 number of tree leafs   */
-       __le32 leafidx;         /* 4: index of the first tree leaf      */
-       __le32 height;          /* 4: height of tree            */
-       s8 budmin;              /* 1: minimum l2 tree leaf value        */
-       s8 stree[CTLTREESIZE];  /* CTLTREESIZE: dmapctl tree    */
-       u8 pad[2714];           /* 2714: pad to 4096            */
-};                             /* - 4096 -                     */
+       __le32 nleafs;          /* 4: number of tree leafs      */
+       __le32 l2nleafs;        /* 4: l2 number of tree leafs   */
+       __le32 leafidx;         /* 4: index of the first tree leaf      */
+       __le32 height;          /* 4: height of tree            */
+       s8 budmin;              /* 1: minimum l2 tree leaf value        */
+       s8 stree[CTLTREESIZE];  /* CTLTREESIZE: dmapctl tree    */
+       u8 pad[2714];           /* 2714: pad to 4096            */
+};                             /* - 4096 -                     */
 
 /*
  *     common definition for dmaptree within dmap and dmapctl
@@ -202,41 +202,41 @@ typedef union dmtree {
  *     on-disk aggregate disk allocation map descriptor.
  */
 struct dbmap_disk {
-       __le64 dn_mapsize;      /* 8: number of blocks in aggregate     */
-       __le64 dn_nfree;        /* 8: num free blks in aggregate map    */
-       __le32 dn_l2nbperpage;  /* 4: number of blks per page           */
-       __le32 dn_numag;        /* 4: total number of ags               */
-       __le32 dn_maxlevel;     /* 4: number of active ags              */
-       __le32 dn_maxag;        /* 4: max active alloc group number     */
-       __le32 dn_agpref;       /* 4: preferred alloc group (hint)      */
-       __le32 dn_aglevel;      /* 4: dmapctl level holding the AG      */
-       __le32 dn_agheigth;     /* 4: height in dmapctl of the AG       */
-       __le32 dn_agwidth;      /* 4: width in dmapctl of the AG        */
-       __le32 dn_agstart;      /* 4: start tree index at AG height     */
-       __le32 dn_agl2size;     /* 4: l2 num of blks per alloc group    */
-       __le64 dn_agfree[MAXAG];/* 8*MAXAG: per AG free count           */
-       __le64 dn_agsize;       /* 8: num of blks per alloc group       */
-       s8 dn_maxfreebud;       /* 1: max free buddy system             */
-       u8 pad[3007];           /* 3007: pad to 4096                    */
-};                             /* - 4096 -                             */
+       __le64 dn_mapsize;      /* 8: number of blocks in aggregate     */
+       __le64 dn_nfree;        /* 8: num free blks in aggregate map    */
+       __le32 dn_l2nbperpage;  /* 4: number of blks per page           */
+       __le32 dn_numag;        /* 4: total number of ags               */
+       __le32 dn_maxlevel;     /* 4: number of active ags              */
+       __le32 dn_maxag;        /* 4: max active alloc group number     */
+       __le32 dn_agpref;       /* 4: preferred alloc group (hint)      */
+       __le32 dn_aglevel;      /* 4: dmapctl level holding the AG      */
+       __le32 dn_agheigth;     /* 4: height in dmapctl of the AG       */
+       __le32 dn_agwidth;      /* 4: width in dmapctl of the AG        */
+       __le32 dn_agstart;      /* 4: start tree index at AG height     */
+       __le32 dn_agl2size;     /* 4: l2 num of blks per alloc group    */
+       __le64 dn_agfree[MAXAG];/* 8*MAXAG: per AG free count           */
+       __le64 dn_agsize;       /* 8: num of blks per alloc group       */
+       s8 dn_maxfreebud;       /* 1: max free buddy system             */
+       u8 pad[3007];           /* 3007: pad to 4096                    */
+};                             /* - 4096 -                             */
 
 struct dbmap {
-       s64 dn_mapsize;         /* number of blocks in aggregate     */
-       s64 dn_nfree;           /* num free blks in aggregate map    */
-       int dn_l2nbperpage;     /* number of blks per page           */
-       int dn_numag;           /* total number of ags               */
-       int dn_maxlevel;        /* number of active ags              */
-       int dn_maxag;           /* max active alloc group number     */
-       int dn_agpref;          /* preferred alloc group (hint)      */
-       int dn_aglevel;         /* dmapctl level holding the AG      */
-       int dn_agheigth;        /* height in dmapctl of the AG       */
-       int dn_agwidth;         /* width in dmapctl of the AG        */
-       int dn_agstart;         /* start tree index at AG height     */
-       int dn_agl2size;        /* l2 num of blks per alloc group    */
-       s64 dn_agfree[MAXAG];   /* per AG free count           */
-       s64 dn_agsize;          /* num of blks per alloc group       */
-       signed char dn_maxfreebud;      /* max free buddy system             */
-};                             /* - 4096 -                             */
+       s64 dn_mapsize;         /* number of blocks in aggregate        */
+       s64 dn_nfree;           /* num free blks in aggregate map       */
+       int dn_l2nbperpage;     /* number of blks per page              */
+       int dn_numag;           /* total number of ags                  */
+       int dn_maxlevel;        /* number of active ags                 */
+       int dn_maxag;           /* max active alloc group number        */
+       int dn_agpref;          /* preferred alloc group (hint)         */
+       int dn_aglevel;         /* dmapctl level holding the AG         */
+       int dn_agheigth;        /* height in dmapctl of the AG          */
+       int dn_agwidth;         /* width in dmapctl of the AG           */
+       int dn_agstart;         /* start tree index at AG height        */
+       int dn_agl2size;        /* l2 num of blks per alloc group       */
+       s64 dn_agfree[MAXAG];   /* per AG free count                    */
+       s64 dn_agsize;          /* num of blks per alloc group          */
+       signed char dn_maxfreebud;      /* max free buddy system        */
+};                             /* - 4096 -                             */
 /*
  *     in-memory aggregate disk allocation map descriptor.
  */
index 6d62f3222892cd1fd6c74ce679c724f941e0bda2..c14ba3cfa8189f04910b02ebb305601ffef0a853 100644 (file)
@@ -315,8 +315,8 @@ static inline void lock_index(tid_t tid, struct inode *ip, struct metapage * mp,
        lv = &llck->lv[llck->index];
 
        /*
-        *      Linelock slot size is twice the size of directory table
-        *      slot size.  512 entries per page.
+        *      Linelock slot size is twice the size of directory table
+        *      slot size.  512 entries per page.
         */
        lv->offset = ((index - 2) & 511) >> 1;
        lv->length = 1;
@@ -615,7 +615,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
        btstack->nsplit = 1;
 
        /*
-        *      search down tree from root:
+        *      search down tree from root:
         *
         * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
         * internal page, child page Pi contains entry with k, Ki <= K < Kj.
@@ -659,7 +659,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
                        }
                        if (cmp == 0) {
                                /*
-                                *      search hit
+                                *      search hit
                                 */
                                /* search hit - leaf page:
                                 * return the entry found
@@ -723,7 +723,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
                }
 
                /*
-                *      search miss
+                *      search miss
                 *
                 * base is the smallest index with key (Kj) greater than
                 * search key (K) and may be zero or (maxindex + 1) index.
@@ -834,7 +834,7 @@ int dtInsert(tid_t tid, struct inode *ip,
        struct lv *lv;
 
        /*
-        *      retrieve search result
+        *      retrieve search result
         *
         * dtSearch() returns (leaf page pinned, index at which to insert).
         * n.b. dtSearch() may return index of (maxindex + 1) of
@@ -843,7 +843,7 @@ int dtInsert(tid_t tid, struct inode *ip,
        DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
 
        /*
-        *      insert entry for new key
+        *      insert entry for new key
         */
        if (DO_INDEX(ip)) {
                if (JFS_IP(ip)->next_index == DIREND) {
@@ -860,9 +860,9 @@ int dtInsert(tid_t tid, struct inode *ip,
        data.leaf.ino = *fsn;
 
        /*
-        *      leaf page does not have enough room for new entry:
+        *      leaf page does not have enough room for new entry:
         *
-        *      extend/split the leaf page;
+        *      extend/split the leaf page;
         *
         * dtSplitUp() will insert the entry and unpin the leaf page.
         */
@@ -877,9 +877,9 @@ int dtInsert(tid_t tid, struct inode *ip,
        }
 
        /*
-        *      leaf page does have enough room for new entry:
+        *      leaf page does have enough room for new entry:
         *
-        *      insert the new data entry into the leaf page;
+        *      insert the new data entry into the leaf page;
         */
        BT_MARK_DIRTY(mp, ip);
        /*
@@ -967,13 +967,13 @@ static int dtSplitUp(tid_t tid,
        }
 
        /*
-        *      split leaf page
+        *      split leaf page
         *
         * The split routines insert the new entry, and
         * acquire txLock as appropriate.
         */
        /*
-        *      split root leaf page:
+        *      split root leaf page:
         */
        if (sp->header.flag & BT_ROOT) {
                /*
@@ -1012,7 +1012,7 @@ static int dtSplitUp(tid_t tid,
        }
 
        /*
-        *      extend first leaf page
+        *      extend first leaf page
         *
         * extend the 1st extent if less than buffer page size
         * (dtExtendPage() reurns leaf page unpinned)
@@ -1068,7 +1068,7 @@ static int dtSplitUp(tid_t tid,
        }
 
        /*
-        *      split leaf page <sp> into <sp> and a new right page <rp>.
+        *      split leaf page <sp> into <sp> and a new right page <rp>.
         *
         * return <rp> pinned and its extent descriptor <rpxd>
         */
@@ -1433,7 +1433,7 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
        rp->header.freecnt = rp->header.maxslot - fsi;
 
        /*
-        *      sequential append at tail: append without split
+        *      sequential append at tail: append without split
         *
         * If splitting the last page on a level because of appending
         * a entry to it (skip is maxentry), it's likely that the access is
@@ -1467,7 +1467,7 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
        }
 
        /*
-        *      non-sequential insert (at possibly middle page)
+        *      non-sequential insert (at possibly middle page)
         */
 
        /*
@@ -1508,7 +1508,7 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
        left = 0;
 
        /*
-        *      compute fill factor for split pages
+        *      compute fill factor for split pages
         *
         * <nxt> traces the next entry to move to rp
         * <off> traces the next entry to stay in sp
@@ -1551,7 +1551,7 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
        /* <nxt> poins to the 1st entry to move */
 
        /*
-        *      move entries to right page
+        *      move entries to right page
         *
         * dtMoveEntry() initializes rp and reserves entry for insertion
         *
@@ -1677,7 +1677,7 @@ static int dtExtendPage(tid_t tid,
                return (rc);
 
        /*
-        *      extend the extent
+        *      extend the extent
         */
        pxdlist = split->pxdlist;
        pxd = &pxdlist->pxd[pxdlist->npxd];
@@ -1722,7 +1722,7 @@ static int dtExtendPage(tid_t tid,
        }
 
        /*
-        *      extend the page
+        *      extend the page
         */
        sp->header.self = *pxd;
 
@@ -1739,9 +1739,6 @@ static int dtExtendPage(tid_t tid,
        /* update buffer extent descriptor of extended page */
        xlen = lengthPXD(pxd);
        xsize = xlen << JFS_SBI(sb)->l2bsize;
-#ifdef _STILL_TO_PORT
-       bmSetXD(smp, xaddr, xsize);
-#endif                         /*  _STILL_TO_PORT */
 
        /*
         * copy old stbl to new stbl at start of extended area
@@ -1836,7 +1833,7 @@ static int dtExtendPage(tid_t tid,
        }
 
        /*
-        *      update parent entry on the parent/root page
+        *      update parent entry on the parent/root page
         */
        /*
         * acquire a transaction lock on the parent/root page
@@ -1904,7 +1901,7 @@ static int dtSplitRoot(tid_t tid,
        sp = &JFS_IP(ip)->i_dtroot;
 
        /*
-        *      allocate/initialize a single (right) child page
+        *      allocate/initialize a single (right) child page
         *
         * N.B. at first split, a one (or two) block to fit new entry
         * is allocated; at subsequent split, a full page is allocated;
@@ -1943,7 +1940,7 @@ static int dtSplitRoot(tid_t tid,
        rp->header.prev = 0;
 
        /*
-        *      move in-line root page into new right page extent
+        *      move in-line root page into new right page extent
         */
        /* linelock header + copied entries + new stbl (1st slot) in new page */
        ASSERT(dtlck->index == 0);
@@ -2016,7 +2013,7 @@ static int dtSplitRoot(tid_t tid,
        dtInsertEntry(rp, split->index, split->key, split->data, &dtlck);
 
        /*
-        *      reset parent/root page
+        *      reset parent/root page
         *
         * set the 1st entry offset to 0, which force the left-most key
         * at any level of the tree to be less than any search key.
@@ -2102,7 +2099,7 @@ int dtDelete(tid_t tid,
        dtpage_t *np;
 
        /*
-        *      search for the entry to delete:
+        *      search for the entry to delete:
         *
         * dtSearch() returns (leaf page pinned, index at which to delete).
         */
@@ -2253,7 +2250,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
        int i;
 
        /*
-        *      keep the root leaf page which has become empty
+        *      keep the root leaf page which has become empty
         */
        if (BT_IS_ROOT(fmp)) {
                /*
@@ -2269,7 +2266,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
        }
 
        /*
-        *      free the non-root leaf page
+        *      free the non-root leaf page
         */
        /*
         * acquire a transaction lock on the page
@@ -2299,7 +2296,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
        discard_metapage(fmp);
 
        /*
-        *      propagate page deletion up the directory tree
+        *      propagate page deletion up the directory tree
         *
         * If the delete from the parent page makes it empty,
         * continue all the way up the tree.
@@ -2440,10 +2437,10 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
 
 #ifdef _NOTYET
 /*
- * NAME:        dtRelocate()
+ * NAME:       dtRelocate()
  *
- * FUNCTION:    relocate dtpage (internal or leaf) of directory;
- *              This function is mainly used by defragfs utility.
+ * FUNCTION:   relocate dtpage (internal or leaf) of directory;
+ *             This function is mainly used by defragfs utility.
  */
 int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
               s64 nxaddr)
@@ -2471,8 +2468,8 @@ int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
                   xlen);
 
        /*
-        *      1. get the internal parent dtpage covering
-        *      router entry for the tartget page to be relocated;
+        *      1. get the internal parent dtpage covering
+        *      router entry for the tartget page to be relocated;
         */
        rc = dtSearchNode(ip, lmxaddr, opxd, &btstack);
        if (rc)
@@ -2483,7 +2480,7 @@ int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
        jfs_info("dtRelocate: parent router entry validated.");
 
        /*
-        *      2. relocate the target dtpage
+        *      2. relocate the target dtpage
         */
        /* read in the target page from src extent */
        DT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc);
@@ -2581,9 +2578,7 @@ int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
 
        /* update the buffer extent descriptor of the dtpage */
        xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize;
-#ifdef _STILL_TO_PORT
-       bmSetXD(mp, nxaddr, xsize);
-#endif /* _STILL_TO_PORT */
+
        /* unpin the relocated page */
        DT_PUTPAGE(mp);
        jfs_info("dtRelocate: target dtpage relocated.");
@@ -2594,7 +2589,7 @@ int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
         */
 
        /*
-        *      3. acquire maplock for the source extent to be freed;
+        *      3. acquire maplock for the source extent to be freed;
         */
        /* for dtpage relocation, write a LOG_NOREDOPAGE record
         * for the source dtpage (logredo() will init NoRedoPage
@@ -2609,7 +2604,7 @@ int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
        pxdlock->index = 1;
 
        /*
-        *      4. update the parent router entry for relocation;
+        *      4. update the parent router entry for relocation;
         *
         * acquire tlck for the parent entry covering the target dtpage;
         * write LOG_REDOPAGE to apply after image only;
@@ -2637,7 +2632,7 @@ int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
  * NAME:       dtSearchNode()
  *
  * FUNCTION:   Search for an dtpage containing a specified address
- *              This function is mainly used by defragfs utility.
+ *             This function is mainly used by defragfs utility.
  *
  * NOTE:       Search result on stack, the found page is pinned at exit.
  *             The result page must be an internal dtpage.
@@ -2660,7 +2655,7 @@ static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd,
        BT_CLR(btstack);        /* reset stack */
 
        /*
-        *      descend tree to the level with specified leftmost page
+        *      descend tree to the level with specified leftmost page
         *
         *  by convention, root bn = 0.
         */
@@ -2699,7 +2694,7 @@ static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd,
        }
 
        /*
-        *      search each page at the current levevl
+        *      search each page at the current levevl
         */
       loop:
        stbl = DT_GETSTBL(p);
@@ -3044,9 +3039,9 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        if (DO_INDEX(ip)) {
                /*
                 * persistent index is stored in directory entries.
-                * Special cases:        0 = .
-                *                       1 = ..
-                *                      -1 = End of directory
+                * Special cases:        0 = .
+                *                       1 = ..
+                *                      -1 = End of directory
                 */
                do_index = 1;
 
@@ -3128,10 +3123,10 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                /*
                 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
                 *
-                * pn = index = 0:      First entry "."
-                * pn = 0; index = 1:   Second entry ".."
-                * pn > 0:              Real entries, pn=1 -> leftmost page
-                * pn = index = -1:     No more entries
+                * pn = index = 0:      First entry "."
+                * pn = 0; index = 1:   Second entry ".."
+                * pn > 0:              Real entries, pn=1 -> leftmost page
+                * pn = index = -1:     No more entries
                 */
                dtpos = filp->f_pos;
                if (dtpos == 0) {
@@ -3351,7 +3346,7 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack)
        BT_CLR(btstack);        /* reset stack */
 
        /*
-        *      descend leftmost path of the tree
+        *      descend leftmost path of the tree
         *
         * by convention, root bn = 0.
         */
@@ -4531,7 +4526,7 @@ int dtModify(tid_t tid, struct inode *ip,
        struct ldtentry *entry;
 
        /*
-        *      search for the entry to modify:
+        *      search for the entry to modify:
         *
         * dtSearch() returns (leaf page pinned, index at which to modify).
         */
index af8513f78648336f8bda39c8e5c271b943a43535..8561c6ecece096648a7ea054d013686f58ab7fd1 100644 (file)
@@ -35,7 +35,7 @@ typedef union {
 
 
 /*
- *      entry segment/slot
+ *     entry segment/slot
  *
  * an entry consists of type dependent head/only segment/slot and
  * additional segments/slots linked vi next field;
index a35bdca6a805b81b2fe2bf4b379a27d55c02dd5f..7ae1e3281de938b85432417863aa341f7483af54 100644 (file)
@@ -34,8 +34,8 @@ static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *);
 #endif
 static s64 extRoundDown(s64 nb);
 
-#define DPD(a)          (printk("(a): %d\n",(a)))
-#define DPC(a)          (printk("(a): %c\n",(a)))
+#define DPD(a)         (printk("(a): %d\n",(a)))
+#define DPC(a)         (printk("(a): %c\n",(a)))
 #define DPL1(a)                                        \
 {                                              \
        if ((a) >> 32)                          \
@@ -51,19 +51,19 @@ static s64 extRoundDown(s64 nb);
                printk("(a): %x\n",(a) << 32);  \
 }
 
-#define DPD1(a)         (printk("(a): %d  ",(a)))
-#define DPX(a)          (printk("(a): %08x\n",(a)))
-#define DPX1(a)         (printk("(a): %08x  ",(a)))
-#define DPS(a)          (printk("%s\n",(a)))
-#define DPE(a)          (printk("\nENTERING: %s\n",(a)))
-#define DPE1(a)          (printk("\nENTERING: %s",(a)))
-#define DPS1(a)         (printk("  %s  ",(a)))
+#define DPD1(a)                (printk("(a): %d  ",(a)))
+#define DPX(a)         (printk("(a): %08x\n",(a)))
+#define DPX1(a)                (printk("(a): %08x  ",(a)))
+#define DPS(a)         (printk("%s\n",(a)))
+#define DPE(a)         (printk("\nENTERING: %s\n",(a)))
+#define DPE1(a)                (printk("\nENTERING: %s",(a)))
+#define DPS1(a)                (printk("  %s  ",(a)))
 
 
 /*
  * NAME:       extAlloc()
  *
- * FUNCTION:    allocate an extent for a specified page range within a
+ * FUNCTION:   allocate an extent for a specified page range within a
  *             file.
  *
  * PARAMETERS:
@@ -78,9 +78,9 @@ static s64 extRoundDown(s64 nb);
  *               should be marked as allocated but not recorded.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOSPC        - insufficient disk resources.
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOSPC - insufficient disk resources.
  */
 int
 extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
@@ -192,9 +192,9 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
 
 #ifdef _NOTYET
 /*
- * NAME:        extRealloc()
+ * NAME:       extRealloc()
  *
- * FUNCTION:    extend the allocation of a file extent containing a
+ * FUNCTION:   extend the allocation of a file extent containing a
  *             partial back last page.
  *
  * PARAMETERS:
@@ -207,9 +207,9 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
  *               should be marked as allocated but not recorded.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOSPC        - insufficient disk resources.
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOSPC - insufficient disk resources.
  */
 int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
 {
@@ -345,9 +345,9 @@ exit:
 
 
 /*
- * NAME:        extHint()
+ * NAME:       extHint()
  *
- * FUNCTION:    produce an extent allocation hint for a file offset.
+ * FUNCTION:   produce an extent allocation hint for a file offset.
  *
  * PARAMETERS:
  *     ip      - the inode of the file.
@@ -356,8 +356,8 @@ exit:
  *               the hint.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
+ *     0       - success
+ *     -EIO    - i/o error.
  */
 int extHint(struct inode *ip, s64 offset, xad_t * xp)
 {
@@ -387,7 +387,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
        lxdl.nlxd = 1;
        lxdl.lxd = &lxd;
        LXDoffset(&lxd, prev)
-           LXDlength(&lxd, nbperpage);
+       LXDlength(&lxd, nbperpage);
 
        xadl.maxnxad = 1;
        xadl.nxad = 0;
@@ -397,11 +397,11 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
        if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
                return (rc);
 
-       /* check if not extent exists for the previous page.
+       /* check if no extent exists for the previous page.
         * this is possible for sparse files.
         */
        if (xadl.nxad == 0) {
-//              assert(ISSPARSE(ip));
+//             assert(ISSPARSE(ip));
                return (0);
        }
 
@@ -410,28 +410,28 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
         */
        xp->flag &= XAD_NOTRECORDED;
 
-        if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
+       if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
                jfs_error(ip->i_sb, "extHint: corrupt xtree");
                return -EIO;
-        }
+       }
 
        return (0);
 }
 
 
 /*
- * NAME:        extRecord()
+ * NAME:       extRecord()
  *
- * FUNCTION:    change a page with a file from not recorded to recorded.
+ * FUNCTION:   change a page with a file from not recorded to recorded.
  *
  * PARAMETERS:
  *     ip      - inode of the file.
  *     cp      - cbuf of the file page.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOSPC        - insufficient disk resources.
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOSPC - insufficient disk resources.
  */
 int extRecord(struct inode *ip, xad_t * xp)
 {
@@ -451,9 +451,9 @@ int extRecord(struct inode *ip, xad_t * xp)
 
 #ifdef _NOTYET
 /*
- * NAME:        extFill()
+ * NAME:       extFill()
  *
- * FUNCTION:    allocate disk space for a file page that represents
+ * FUNCTION:   allocate disk space for a file page that represents
  *             a file hole.
  *
  * PARAMETERS:
@@ -461,16 +461,16 @@ int extRecord(struct inode *ip, xad_t * xp)
  *     cp      - cbuf of the file page represent the hole.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOSPC        - insufficient disk resources.
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOSPC - insufficient disk resources.
  */
 int extFill(struct inode *ip, xad_t * xp)
 {
        int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
        s64 blkno = offsetXAD(xp) >> ip->i_blkbits;
 
-//      assert(ISSPARSE(ip));
+//     assert(ISSPARSE(ip));
 
        /* initialize the extent allocation hint */
        XADaddress(xp, 0);
@@ -489,7 +489,7 @@ int extFill(struct inode *ip, xad_t * xp)
 /*
  * NAME:       extBalloc()
  *
- * FUNCTION:    allocate disk blocks to form an extent.
+ * FUNCTION:   allocate disk blocks to form an extent.
  *
  *             initially, we will try to allocate disk blocks for the
  *             requested size (nblocks).  if this fails (nblocks
@@ -513,9 +513,9 @@ int extFill(struct inode *ip, xad_t * xp)
  *                allocated block range.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOSPC        - insufficient disk resources.
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOSPC - insufficient disk resources.
  */
 static int
 extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
@@ -580,7 +580,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
 /*
  * NAME:       extBrealloc()
  *
- * FUNCTION:    attempt to extend an extent's allocation.
+ * FUNCTION:   attempt to extend an extent's allocation.
  *
  *             Initially, we will try to extend the extent's allocation
  *             in place.  If this fails, we'll try to move the extent
@@ -597,8 +597,8 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
  *
  * PARAMETERS:
  *     ip       - the inode of the file.
- *     blkno    - starting block number of the extents current allocation.
- *     nblks    - number of blocks within the extents current allocation.
+ *     blkno    - starting block number of the extents current allocation.
+ *     nblks    - number of blocks within the extents current allocation.
  *     newnblks - pointer to a s64 value.  on entry, this value is the
  *                the new desired extent size (number of blocks).  on
  *                successful exit, this value is set to the extent's actual
@@ -606,9 +606,9 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
  *     newblkno - the starting block number of the extents new allocation.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOSPC        - insufficient disk resources.
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOSPC - insufficient disk resources.
  */
 static int
 extBrealloc(struct inode *ip,
@@ -634,16 +634,16 @@ extBrealloc(struct inode *ip,
 
 
 /*
- * NAME:        extRoundDown()
+ * NAME:       extRoundDown()
  *
- * FUNCTION:    round down a specified number of blocks to the next
+ * FUNCTION:   round down a specified number of blocks to the next
  *             smallest power of 2 number.
  *
  * PARAMETERS:
  *     nb      - the inode of the file.
  *
  * RETURN VALUES:
- *      next smallest power of 2 number.
+ *     next smallest power of 2 number.
  */
 static s64 extRoundDown(s64 nb)
 {
index 38f70ac03becfacda7fff453c58d750f1df4f861..b3f5463fbe5233a4c5cd45a411bf10bea3843d4a 100644 (file)
@@ -34,9 +34,9 @@
 #define JFS_UNICODE    0x00000001      /* unicode name */
 
 /* mount time flags for error handling */
-#define JFS_ERR_REMOUNT_RO 0x00000002   /* remount read-only */
-#define JFS_ERR_CONTINUE   0x00000004   /* continue */
-#define JFS_ERR_PANIC      0x00000008   /* panic */
+#define JFS_ERR_REMOUNT_RO 0x00000002  /* remount read-only */
+#define JFS_ERR_CONTINUE   0x00000004  /* continue */
+#define JFS_ERR_PANIC      0x00000008  /* panic */
 
 /* Quota support */
 #define        JFS_USRQUOTA    0x00000010
@@ -83,7 +83,6 @@
 /*     case-insensitive name/directory support */
 
 #define JFS_AIX                0x80000000      /* AIX support */
-/*     POSIX name/directory  support - Never implemented*/
 
 /*
  *     buffer cache configuration
 #define IDATASIZE      256     /* inode inline data size */
 #define        IXATTRSIZE      128     /* inode inline extended attribute size */
 
-#define XTPAGE_SIZE     4096
-#define log2_PAGESIZE     12
+#define XTPAGE_SIZE    4096
+#define log2_PAGESIZE  12
 
-#define IAG_SIZE        4096
+#define IAG_SIZE       4096
 #define IAG_EXTENT_SIZE 4096
 #define        INOSPERIAG      4096    /* number of disk inodes per iag */
 #define        L2INOSPERIAG    12      /* l2 number of disk inodes per iag */
index c6530227cda66d10b2e18816c419a8f391b0a764..3870ba8b9086b8f2c1c481eaf6a1eb2c79497238 100644 (file)
@@ -93,21 +93,21 @@ static int copy_from_dinode(struct dinode *, struct inode *);
 static void copy_to_dinode(struct dinode *, struct inode *);
 
 /*
- * NAME:        diMount()
+ * NAME:       diMount()
  *
- * FUNCTION:    initialize the incore inode map control structures for
+ * FUNCTION:   initialize the incore inode map control structures for
  *             a fileset or aggregate init time.
  *
- *              the inode map's control structure (dinomap) is
- *              brought in from disk and placed in virtual memory.
+ *             the inode map's control structure (dinomap) is
+ *             brought in from disk and placed in virtual memory.
  *
  * PARAMETERS:
- *      ipimap  - pointer to inode map inode for the aggregate or fileset.
+ *     ipimap  - pointer to inode map inode for the aggregate or fileset.
  *
  * RETURN VALUES:
- *      0       - success
- *      -ENOMEM  - insufficient free virtual memory.
- *      -EIO   - i/o error.
+ *     0       - success
+ *     -ENOMEM - insufficient free virtual memory.
+ *     -EIO    - i/o error.
  */
 int diMount(struct inode *ipimap)
 {
@@ -180,18 +180,18 @@ int diMount(struct inode *ipimap)
 
 
 /*
- * NAME:        diUnmount()
+ * NAME:       diUnmount()
  *
- * FUNCTION:    write to disk the incore inode map control structures for
+ * FUNCTION:   write to disk the incore inode map control structures for
  *             a fileset or aggregate at unmount time.
  *
  * PARAMETERS:
- *      ipimap  - pointer to inode map inode for the aggregate or fileset.
+ *     ipimap  - pointer to inode map inode for the aggregate or fileset.
  *
  * RETURN VALUES:
- *      0       - success
- *      -ENOMEM  - insufficient free virtual memory.
- *      -EIO   - i/o error.
+ *     0       - success
+ *     -ENOMEM - insufficient free virtual memory.
+ *     -EIO    - i/o error.
  */
 int diUnmount(struct inode *ipimap, int mounterror)
 {
@@ -274,9 +274,9 @@ int diSync(struct inode *ipimap)
 
 
 /*
- * NAME:        diRead()
+ * NAME:       diRead()
  *
- * FUNCTION:    initialize an incore inode from disk.
+ * FUNCTION:   initialize an incore inode from disk.
  *
  *             on entry, the specifed incore inode should itself
  *             specify the disk inode number corresponding to the
@@ -285,7 +285,7 @@ int diSync(struct inode *ipimap)
  *             this routine handles incore inode initialization for
  *             both "special" and "regular" inodes.  special inodes
  *             are those required early in the mount process and
- *             require special handling since much of the file system
+ *             require special handling since much of the file system
  *             is not yet initialized.  these "special" inodes are
  *             identified by a NULL inode map inode pointer and are
  *             actually initialized by a call to diReadSpecial().
@@ -298,12 +298,12 @@ int diSync(struct inode *ipimap)
  *             incore inode.
  *
  * PARAMETERS:
- *      ip  -  pointer to incore inode to be initialized from disk.
+ *     ip      -  pointer to incore inode to be initialized from disk.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
- *      -ENOMEM        - insufficient memory
+ *     0       - success
+ *     -EIO    - i/o error.
+ *     -ENOMEM - insufficient memory
  *
  */
 int diRead(struct inode *ip)
@@ -410,26 +410,26 @@ int diRead(struct inode *ip)
 
 
 /*
- * NAME:        diReadSpecial()
+ * NAME:       diReadSpecial()
  *
- * FUNCTION:    initialize a 'special' inode from disk.
+ * FUNCTION:   initialize a 'special' inode from disk.
  *
  *             this routines handles aggregate level inodes.  The
  *             inode cache cannot differentiate between the
  *             aggregate inodes and the filesystem inodes, so we
  *             handle these here.  We don't actually use the aggregate
- *             inode map, since these inodes are at a fixed location
+ *             inode map, since these inodes are at a fixed location
  *             and in some cases the aggregate inode map isn't initialized
  *             yet.
  *
  * PARAMETERS:
- *      sb - filesystem superblock
+ *     sb - filesystem superblock
  *     inum - aggregate inode number
  *     secondary - 1 if secondary aggregate inode table
  *
  * RETURN VALUES:
- *      new inode      - success
- *      NULL           - i/o error.
+ *     new inode       - success
+ *     NULL            - i/o error.
  */
 struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
 {
@@ -502,12 +502,12 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
 }
 
 /*
- * NAME:        diWriteSpecial()
+ * NAME:       diWriteSpecial()
  *
- * FUNCTION:    Write the special inode to disk
+ * FUNCTION:   Write the special inode to disk
  *
  * PARAMETERS:
- *      ip - special inode
+ *     ip - special inode
  *     secondary - 1 if secondary aggregate inode table
  *
  * RETURN VALUES: none
@@ -554,9 +554,9 @@ void diWriteSpecial(struct inode *ip, int secondary)
 }
 
 /*
- * NAME:        diFreeSpecial()
+ * NAME:       diFreeSpecial()
  *
- * FUNCTION:    Free allocated space for special inode
+ * FUNCTION:   Free allocated space for special inode
  */
 void diFreeSpecial(struct inode *ip)
 {
@@ -572,9 +572,9 @@ void diFreeSpecial(struct inode *ip)
 
 
 /*
- * NAME:        diWrite()
+ * NAME:       diWrite()
  *
- * FUNCTION:    write the on-disk inode portion of the in-memory inode
+ * FUNCTION:   write the on-disk inode portion of the in-memory inode
  *             to its corresponding on-disk inode.
  *
  *             on entry, the specifed incore inode should itself
@@ -589,11 +589,11 @@ void diFreeSpecial(struct inode *ip)
  *
  * PARAMETERS:
  *     tid -  transacation id
- *      ip  -  pointer to incore inode to be written to the inode extent.
+ *     ip  -  pointer to incore inode to be written to the inode extent.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
+ *     0       - success
+ *     -EIO    - i/o error.
  */
 int diWrite(tid_t tid, struct inode *ip)
 {
@@ -730,7 +730,7 @@ int diWrite(tid_t tid, struct inode *ip)
        ilinelock = (struct linelock *) & tlck->lock;
 
        /*
-        *      regular file: 16 byte (XAD slot) granularity
+        *      regular file: 16 byte (XAD slot) granularity
         */
        if (type & tlckXTREE) {
                xtpage_t *p, *xp;
@@ -755,7 +755,7 @@ int diWrite(tid_t tid, struct inode *ip)
                                xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
        }
        /*
-        *      directory: 32 byte (directory entry slot) granularity
+        *      directory: 32 byte (directory entry slot) granularity
         */
        else if (type & tlckDTREE) {
                dtpage_t *p, *xp;
@@ -800,9 +800,8 @@ int diWrite(tid_t tid, struct inode *ip)
        }
 
        /*
-        *      lock/copy inode base: 128 byte slot granularity
+        *      lock/copy inode base: 128 byte slot granularity
         */
-// baseDinode:
        lv = & dilinelock->lv[dilinelock->index];
        lv->offset = dioffset >> L2INODESLOTSIZE;
        copy_to_dinode(dp, ip);
@@ -813,17 +812,6 @@ int diWrite(tid_t tid, struct inode *ip)
                lv->length = 1;
        dilinelock->index++;
 
-#ifdef _JFS_FASTDASD
-       /*
-        * We aren't logging changes to the DASD used in directory inodes,
-        * but we need to write them to disk.  If we don't unmount cleanly,
-        * mount will recalculate the DASD used.
-        */
-       if (S_ISDIR(ip->i_mode)
-           && (ip->i_ipmnt->i_mntflag & JFS_DASD_ENABLED))
-               memcpy(&dp->di_DASD, &ip->i_DASD, sizeof(struct dasd));
-#endif                         /*  _JFS_FASTDASD */
-
        /* release the buffer holding the updated on-disk inode.
         * the buffer will be later written by commit processing.
         */
@@ -834,9 +822,9 @@ int diWrite(tid_t tid, struct inode *ip)
 
 
 /*
- * NAME:        diFree(ip)
+ * NAME:       diFree(ip)
  *
- * FUNCTION:    free a specified inode from the inode working map
+ * FUNCTION:   free a specified inode from the inode working map
  *             for a fileset or aggregate.
  *
  *             if the inode to be freed represents the first (only)
@@ -865,11 +853,11 @@ int diWrite(tid_t tid, struct inode *ip)
  *             any updates and are held until all updates are complete.
  *
  * PARAMETERS:
- *      ip     - inode to be freed.
+ *     ip      - inode to be freed.
  *
  * RETURN VALUES:
- *      0       - success
- *      -EIO   - i/o error.
+ *     0       - success
+ *     -EIO    - i/o error.
  */
 int diFree(struct inode *ip)
 {
@@ -902,7 +890,8 @@ int diFree(struct inode *ip)
         * the map.
         */
        if (iagno >= imap->im_nextiag) {
-               dump_mem("imap", imap, 32);
+               print_hex_dump(KERN_ERR, "imap: ", DUMP_PREFIX_ADDRESS, 16, 4,
+                              imap, 32, 0);
                jfs_error(ip->i_sb,
                          "diFree: inum = %d, iagno = %d, nextiag = %d",
                          (uint) inum, iagno, imap->im_nextiag);
@@ -964,8 +953,8 @@ int diFree(struct inode *ip)
                return -EIO;
        }
        /*
-        *      inode extent still has some inodes or below low water mark:
-        *      keep the inode extent;
+        *      inode extent still has some inodes or below low water mark:
+        *      keep the inode extent;
         */
        if (bitmap ||
            imap->im_agctl[agno].numfree < 96 ||
@@ -1047,12 +1036,12 @@ int diFree(struct inode *ip)
 
 
        /*
-        *      inode extent has become free and above low water mark:
-        *      free the inode extent;
+        *      inode extent has become free and above low water mark:
+        *      free the inode extent;
         */
 
        /*
-        *      prepare to update iag list(s) (careful update step 1)
+        *      prepare to update iag list(s) (careful update step 1)
         */
        amp = bmp = cmp = dmp = NULL;
        fwd = back = -1;
@@ -1152,7 +1141,7 @@ int diFree(struct inode *ip)
        invalidate_pxd_metapages(ip, freepxd);
 
        /*
-        *      update iag list(s) (careful update step 2)
+        *      update iag list(s) (careful update step 2)
         */
        /* add the iag to the ag extent free list if this is the
         * first free extent for the iag.
@@ -1338,20 +1327,20 @@ diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
 
 
 /*
- * NAME:        diAlloc(pip,dir,ip)
+ * NAME:       diAlloc(pip,dir,ip)
  *
- * FUNCTION:    allocate a disk inode from the inode working map
+ * FUNCTION:   allocate a disk inode from the inode working map
  *             for a fileset or aggregate.
  *
  * PARAMETERS:
- *      pip    - pointer to incore inode for the parent inode.
- *      dir    - 'true' if the new disk inode is for a directory.
- *      ip     - pointer to a new inode
+ *     pip     - pointer to incore inode for the parent inode.
+ *     dir     - 'true' if the new disk inode is for a directory.
+ *     ip      - pointer to a new inode
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 int diAlloc(struct inode *pip, bool dir, struct inode *ip)
 {
@@ -1433,7 +1422,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
        addext = (imap->im_agctl[agno].numfree < 32 && iagp->nfreeexts);
 
        /*
-        *      try to allocate from the IAG
+        *      try to allocate from the IAG
         */
        /* check if the inode may be allocated from the iag
         * (i.e. the inode has free inodes or new extent can be added).
@@ -1633,9 +1622,9 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
 
 
 /*
- * NAME:        diAllocAG(imap,agno,dir,ip)
+ * NAME:       diAllocAG(imap,agno,dir,ip)
  *
- * FUNCTION:    allocate a disk inode from the allocation group.
+ * FUNCTION:   allocate a disk inode from the allocation group.
  *
  *             this routine first determines if a new extent of free
  *             inodes should be added for the allocation group, with
@@ -1649,17 +1638,17 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
  * PRE CONDITION: Already have the AG lock for this AG.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      agno   - allocation group to allocate from.
- *      dir    - 'true' if the new disk inode is for a directory.
- *      ip     - pointer to the new inode to be filled in on successful return
+ *     imap    - pointer to inode map control structure.
+ *     agno    - allocation group to allocate from.
+ *     dir     - 'true' if the new disk inode is for a directory.
+ *     ip      - pointer to the new inode to be filled in on successful return
  *               with the disk inode number allocated, its extent address
  *               and the start of the ag.
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 static int
 diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
@@ -1709,9 +1698,9 @@ diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
 
 
 /*
- * NAME:        diAllocAny(imap,agno,dir,iap)
+ * NAME:       diAllocAny(imap,agno,dir,iap)
  *
- * FUNCTION:    allocate a disk inode from any other allocation group.
+ * FUNCTION:   allocate a disk inode from any other allocation group.
  *
  *             this routine is called when an allocation attempt within
  *             the primary allocation group has failed. if attempts to
@@ -1719,17 +1708,17 @@ diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
  *             specified primary group.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      agno   - primary allocation group (to avoid).
- *      dir    - 'true' if the new disk inode is for a directory.
- *      ip     - pointer to a new inode to be filled in on successful return
+ *     imap    - pointer to inode map control structure.
+ *     agno    - primary allocation group (to avoid).
+ *     dir     - 'true' if the new disk inode is for a directory.
+ *     ip      - pointer to a new inode to be filled in on successful return
  *               with the disk inode number allocated, its extent address
  *               and the start of the ag.
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 static int
 diAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip)
@@ -1772,9 +1761,9 @@ diAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip)
 
 
 /*
- * NAME:        diAllocIno(imap,agno,ip)
+ * NAME:       diAllocIno(imap,agno,ip)
  *
- * FUNCTION:    allocate a disk inode from the allocation group's free
+ * FUNCTION:   allocate a disk inode from the allocation group's free
  *             inode list, returning an error if this free list is
  *             empty (i.e. no iags on the list).
  *
@@ -1785,16 +1774,16 @@ diAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip)
  * PRE CONDITION: Already have AG lock for this AG.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      agno   - allocation group.
- *      ip     - pointer to new inode to be filled in on successful return
+ *     imap    - pointer to inode map control structure.
+ *     agno    - allocation group.
+ *     ip      - pointer to new inode to be filled in on successful return
  *               with the disk inode number allocated, its extent address
  *               and the start of the ag.
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
 {
@@ -1890,7 +1879,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
 
 
 /*
- * NAME:        diAllocExt(imap,agno,ip)
+ * NAME:       diAllocExt(imap,agno,ip)
  *
  * FUNCTION:   add a new extent of free inodes to an iag, allocating
  *             an inode from this extent to satisfy the current allocation
@@ -1910,16 +1899,16 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
  *             for the purpose of satisfying this request.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      agno   - allocation group number.
- *      ip     - pointer to new inode to be filled in on successful return
+ *     imap    - pointer to inode map control structure.
+ *     agno    - allocation group number.
+ *     ip      - pointer to new inode to be filled in on successful return
  *               with the disk inode number allocated, its extent address
  *               and the start of the ag.
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
 {
@@ -2010,7 +1999,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
 
 
 /*
- * NAME:        diAllocBit(imap,iagp,ino)
+ * NAME:       diAllocBit(imap,iagp,ino)
  *
  * FUNCTION:   allocate a backed inode from an iag.
  *
@@ -2030,14 +2019,14 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
  *     this AG.  Must have read lock on imap inode.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      iagp   - pointer to iag.
- *      ino    - inode number to be allocated within the iag.
+ *     imap    - pointer to inode map control structure.
+ *     iagp    - pointer to iag.
+ *     ino     - inode number to be allocated within the iag.
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
 {
@@ -2144,11 +2133,11 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
 
 
 /*
- * NAME:        diNewExt(imap,iagp,extno)
+ * NAME:       diNewExt(imap,iagp,extno)
  *
- * FUNCTION:    initialize a new extent of inodes for an iag, allocating
- *             the first inode of the extent for use for the current
- *             allocation request.
+ * FUNCTION:   initialize a new extent of inodes for an iag, allocating
+ *             the first inode of the extent for use for the current
+ *             allocation request.
  *
  *             disk resources are allocated for the new extent of inodes
  *             and the inodes themselves are initialized to reflect their
@@ -2177,14 +2166,14 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
  *     this AG.  Must have read lock on imap inode.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      iagp   - pointer to iag.
- *      extno  - extent number.
+ *     imap    - pointer to inode map control structure.
+ *     iagp    - pointer to iag.
+ *     extno   - extent number.
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  */
 static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
 {
@@ -2430,7 +2419,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
 
 
 /*
- * NAME:        diNewIAG(imap,iagnop,agno)
+ * NAME:       diNewIAG(imap,iagnop,agno)
  *
  * FUNCTION:   allocate a new iag for an allocation group.
  *
@@ -2443,16 +2432,16 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
  *             and returned to satisfy the request.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      iagnop - pointer to an iag number set with the number of the
+ *     imap    - pointer to inode map control structure.
+ *     iagnop  - pointer to an iag number set with the number of the
  *               newly allocated iag upon successful return.
- *      agno   - allocation group number.
+ *     agno    - allocation group number.
  *     bpp     - Buffer pointer to be filled in with new IAG's buffer
  *
  * RETURN VALUES:
- *      0       - success.
- *      -ENOSPC        - insufficient disk resources.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -ENOSPC - insufficient disk resources.
+ *     -EIO    - i/o error.
  *
  * serialization:
  *     AG lock held on entry/exit;
@@ -2461,7 +2450,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
  *
  * note: new iag transaction:
  * . synchronously write iag;
- * . write log of xtree and inode  of imap;
+ * . write log of xtree and inode of imap;
  * . commit;
  * . synchronous write of xtree (right to left, bottom to top);
  * . at start of logredo(): init in-memory imap with one additional iag page;
@@ -2481,9 +2470,6 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
        s64 xaddr = 0;
        s64 blkno;
        tid_t tid;
-#ifdef _STILL_TO_PORT
-       xad_t xad;
-#endif                         /*  _STILL_TO_PORT */
        struct inode *iplist[1];
 
        /* pick up pointers to the inode map and mount inodes */
@@ -2674,15 +2660,15 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
 }
 
 /*
- * NAME:        diIAGRead()
+ * NAME:       diIAGRead()
  *
- * FUNCTION:    get the buffer for the specified iag within a fileset
+ * FUNCTION:   get the buffer for the specified iag within a fileset
  *             or aggregate inode map.
  *
  * PARAMETERS:
- *      imap   - pointer to inode map control structure.
- *      iagno  - iag number.
- *      bpp    - point to buffer pointer to be filled in on successful
+ *     imap    - pointer to inode map control structure.
+ *     iagno   - iag number.
+ *     bpp     - point to buffer pointer to be filled in on successful
  *               exit.
  *
  * SERIALIZATION:
@@ -2691,8 +2677,8 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
  *      the read lock is unnecessary.)
  *
  * RETURN VALUES:
- *      0       - success.
- *      -EIO   - i/o error.
+ *     0       - success.
+ *     -EIO    - i/o error.
  */
 static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
 {
@@ -2712,17 +2698,17 @@ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
 }
 
 /*
- * NAME:        diFindFree()
+ * NAME:       diFindFree()
  *
- * FUNCTION:    find the first free bit in a word starting at
+ * FUNCTION:   find the first free bit in a word starting at
  *             the specified bit position.
  *
  * PARAMETERS:
- *      word   - word to be examined.
- *      start  - starting bit position.
+ *     word    - word to be examined.
+ *     start   - starting bit position.
  *
  * RETURN VALUES:
- *      bit position of first free bit in the word or 32 if
+ *     bit position of first free bit in the word or 32 if
  *     no free bits were found.
  */
 static int diFindFree(u32 word, int start)
@@ -2897,7 +2883,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
                   atomic_read(&imap->im_numfree));
 
        /*
-        *      reconstruct imap
+        *      reconstruct imap
         *
         * coalesce contiguous k (newAGSize/oldAGSize) AGs;
         * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
@@ -2913,7 +2899,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
        }
 
        /*
-        *      process each iag page of the map.
+        *      process each iag page of the map.
         *
         * rebuild AG Free Inode List, AG Free Inode Extent List;
         */
@@ -2932,7 +2918,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
 
                /* leave free iag in the free iag list */
                if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
-                       release_metapage(bp);
+                       release_metapage(bp);
                        continue;
                }
 
@@ -3063,13 +3049,13 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
 }
 
 /*
- * NAME:        copy_from_dinode()
+ * NAME:       copy_from_dinode()
  *
- * FUNCTION:    Copies inode info from disk inode to in-memory inode
+ * FUNCTION:   Copies inode info from disk inode to in-memory inode
  *
  * RETURN VALUES:
- *      0       - success
- *      -ENOMEM        - insufficient memory
+ *     0       - success
+ *     -ENOMEM - insufficient memory
  */
 static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 {
@@ -3151,9 +3137,9 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 }
 
 /*
- * NAME:        copy_to_dinode()
+ * NAME:       copy_to_dinode()
  *
- * FUNCTION:    Copies inode info from in-memory inode to disk inode
+ * FUNCTION:   Copies inode info from in-memory inode to disk inode
  */
 static void copy_to_dinode(struct dinode * dip, struct inode *ip)
 {
index 4f9c346ed49868eaa6f9546a3be6299bdac0c294..610a0e9d8941ad955e9f6c8bf6df1eceb5e126d5 100644 (file)
  *     jfs_imap.h: disk inode manager
  */
 
-#define        EXTSPERIAG      128     /* number of disk inode extent per iag  */
-#define IMAPBLKNO      0       /* lblkno of dinomap within inode map   */
-#define SMAPSZ         4       /* number of words per summary map      */
+#define        EXTSPERIAG      128     /* number of disk inode extent per iag  */
+#define IMAPBLKNO      0       /* lblkno of dinomap within inode map   */
+#define SMAPSZ         4       /* number of words per summary map      */
 #define        EXTSPERSUM      32      /* number of extents per summary map entry */
 #define        L2EXTSPERSUM    5       /* l2 number of extents per summary map */
 #define        PGSPERIEXT      4       /* number of 4K pages per dinode extent */
-#define        MAXIAGS         ((1<<20)-1)     /* maximum number of iags       */
-#define        MAXAG           128     /* maximum number of allocation groups  */
+#define        MAXIAGS         ((1<<20)-1)     /* maximum number of iags       */
+#define        MAXAG           128     /* maximum number of allocation groups  */
 
-#define AMAPSIZE      512      /* bytes in the IAG allocation maps */
-#define SMAPSIZE      16       /* bytes in the IAG summary maps */
+#define AMAPSIZE       512     /* bytes in the IAG allocation maps */
+#define SMAPSIZE       16      /* bytes in the IAG summary maps */
 
 /* convert inode number to iag number */
 #define        INOTOIAG(ino)   ((ino) >> L2INOSPERIAG)
  *     inode allocation group page (per 4096 inodes of an AG)
  */
 struct iag {
-       __le64 agstart;         /* 8: starting block of ag              */
-       __le32 iagnum;          /* 4: inode allocation group number     */
-       __le32 inofreefwd;      /* 4: ag inode free list forward        */
-       __le32 inofreeback;     /* 4: ag inode free list back           */
-       __le32 extfreefwd;      /* 4: ag inode extent free list forward */
-       __le32 extfreeback;     /* 4: ag inode extent free list back    */
-       __le32 iagfree;         /* 4: iag free list                     */
+       __le64 agstart;         /* 8: starting block of ag              */
+       __le32 iagnum;          /* 4: inode allocation group number     */
+       __le32 inofreefwd;      /* 4: ag inode free list forward        */
+       __le32 inofreeback;     /* 4: ag inode free list back           */
+       __le32 extfreefwd;      /* 4: ag inode extent free list forward */
+       __le32 extfreeback;     /* 4: ag inode extent free list back    */
+       __le32 iagfree;         /* 4: iag free list                     */
 
        /* summary map: 1 bit per inode extent */
        __le32 inosmap[SMAPSZ]; /* 16: sum map of mapwords w/ free inodes;
-                                *      note: this indicates free and backed
-                                *      inodes, if the extent is not backed the
-                                *      value will be 1.  if the extent is
-                                *      backed but all inodes are being used the
-                                *      value will be 1.  if the extent is
-                                *      backed but at least one of the inodes is
-                                *      free the value will be 0.
+                                *      note: this indicates free and backed
+                                *      inodes, if the extent is not backed the
+                                *      value will be 1.  if the extent is
+                                *      backed but all inodes are being used the
+                                *      value will be 1.  if the extent is
+                                *      backed but at least one of the inodes is
+                                *      free the value will be 0.
                                 */
        __le32 extsmap[SMAPSZ]; /* 16: sum map of mapwords w/ free extents */
-       __le32 nfreeinos;               /* 4: number of free inodes             */
-       __le32 nfreeexts;               /* 4: number of free extents            */
+       __le32 nfreeinos;       /* 4: number of free inodes             */
+       __le32 nfreeexts;       /* 4: number of free extents            */
        /* (72) */
        u8 pad[1976];           /* 1976: pad to 2048 bytes */
        /* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
-       __le32 wmap[EXTSPERIAG];        /* 512: working allocation map  */
+       __le32 wmap[EXTSPERIAG];        /* 512: working allocation map */
        __le32 pmap[EXTSPERIAG];        /* 512: persistent allocation map */
        pxd_t inoext[EXTSPERIAG];       /* 1024: inode extent addresses */
 };                             /* (4096) */
@@ -93,44 +93,44 @@ struct iag {
  *     per AG control information (in inode map control page)
  */
 struct iagctl_disk {
-       __le32 inofree;         /* 4: free inode list anchor            */
-       __le32 extfree;         /* 4: free extent list anchor           */
-       __le32 numinos;         /* 4: number of backed inodes           */
-       __le32 numfree;         /* 4: number of free inodes             */
+       __le32 inofree;         /* 4: free inode list anchor            */
+       __le32 extfree;         /* 4: free extent list anchor           */
+       __le32 numinos;         /* 4: number of backed inodes           */
+       __le32 numfree;         /* 4: number of free inodes             */
 };                             /* (16) */
 
 struct iagctl {
-       int inofree;            /* free inode list anchor            */
-       int extfree;            /* free extent list anchor           */
-       int numinos;            /* number of backed inodes           */
-       int numfree;            /* number of free inodes             */
+       int inofree;            /* free inode list anchor               */
+       int extfree;            /* free extent list anchor              */
+       int numinos;            /* number of backed inodes              */
+       int numfree;            /* number of free inodes                */
 };
 
 /*
  *     per fileset/aggregate inode map control page
  */
 struct dinomap_disk {
-       __le32 in_freeiag;      /* 4: free iag list anchor     */
-       __le32 in_nextiag;      /* 4: next free iag number     */
-       __le32 in_numinos;      /* 4: num of backed inodes */
+       __le32 in_freeiag;      /* 4: free iag list anchor      */
+       __le32 in_nextiag;      /* 4: next free iag number      */
+       __le32 in_numinos;      /* 4: num of backed inodes      */
        __le32 in_numfree;      /* 4: num of free backed inodes */
        __le32 in_nbperiext;    /* 4: num of blocks per inode extent */
-       __le32 in_l2nbperiext;  /* 4: l2 of in_nbperiext */
-       __le32 in_diskblock;    /* 4: for standalone test driver  */
-       __le32 in_maxag;        /* 4: for standalone test driver  */
-       u8 pad[2016];           /* 2016: pad to 2048 */
+       __le32 in_l2nbperiext;  /* 4: l2 of in_nbperiext        */
+       __le32 in_diskblock;    /* 4: for standalone test driver */
+       __le32 in_maxag;        /* 4: for standalone test driver */
+       u8 pad[2016];           /* 2016: pad to 2048            */
        struct iagctl_disk in_agctl[MAXAG]; /* 2048: AG control information */
 };                             /* (4096) */
 
 struct dinomap {
-       int in_freeiag;         /* free iag list anchor     */
-       int in_nextiag;         /* next free iag number     */
-       int in_numinos;         /* num of backed inodes */
-       int in_numfree;         /* num of free backed inodes */
+       int in_freeiag;         /* free iag list anchor         */
+       int in_nextiag;         /* next free iag number         */
+       int in_numinos;         /* num of backed inodes         */
+       int in_numfree;         /* num of free backed inodes    */
        int in_nbperiext;       /* num of blocks per inode extent */
-       int in_l2nbperiext;     /* l2 of in_nbperiext */
-       int in_diskblock;       /* for standalone test driver  */
-       int in_maxag;           /* for standalone test driver  */
+       int in_l2nbperiext;     /* l2 of in_nbperiext           */
+       int in_diskblock;       /* for standalone test driver   */
+       int in_maxag;           /* for standalone test driver   */
        struct iagctl in_agctl[MAXAG];  /* AG control information */
 };
 
@@ -139,9 +139,9 @@ struct dinomap {
  */
 struct inomap {
        struct dinomap im_imap;         /* 4096: inode allocation control */
-       struct inode *im_ipimap;        /* 4: ptr to inode for imap   */
-       struct mutex im_freelock;       /* 4: iag free list lock      */
-       struct mutex im_aglock[MAXAG];  /* 512: per AG locks          */
+       struct inode *im_ipimap;        /* 4: ptr to inode for imap     */
+       struct mutex im_freelock;       /* 4: iag free list lock        */
+       struct mutex im_aglock[MAXAG];  /* 512: per AG locks            */
        u32 *im_DBGdimap;
        atomic_t im_numinos;    /* num of backed inodes */
        atomic_t im_numfree;    /* num of free backed inodes */
index 8f453eff3c838a974da6178861716673745a66ff..cb8f30985ad160e38f244e3cb45ab9b377240865 100644 (file)
@@ -40,7 +40,7 @@ struct jfs_inode_info {
        uint    mode2;          /* jfs-specific mode            */
        uint    saved_uid;      /* saved for uid mount option */
        uint    saved_gid;      /* saved for gid mount option */
-       pxd_t   ixpxd;          /* inode extent descriptor      */
+       pxd_t   ixpxd;          /* inode extent descriptor      */
        dxd_t   acl;            /* dxd describing acl   */
        dxd_t   ea;             /* dxd describing ea    */
        time_t  otime;          /* time created */
@@ -190,7 +190,7 @@ struct jfs_sb_info {
        uint            gengen;         /* inode generation generator*/
        uint            inostamp;       /* shows inode belongs to fileset*/
 
-        /* Formerly in ipbmap */
+       /* Formerly in ipbmap */
        struct bmap     *bmap;          /* incore bmap descriptor       */
        struct nls_table *nls_tab;      /* current codepage             */
        struct inode *direct_inode;     /* metadata inode */
index 44a2f33cb98d5d7e3e81ebe7cb0f7c2a12270d29..de3e4a506dbcb7e88623fadac976756382b2c3b2 100644 (file)
@@ -244,7 +244,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                goto writeRecord;
 
        /*
-        *      initialize/update page/transaction recovery lsn
+        *      initialize/update page/transaction recovery lsn
         */
        lsn = log->lsn;
 
@@ -263,7 +263,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        }
 
        /*
-        *      initialize/update lsn of tblock of the page
+        *      initialize/update lsn of tblock of the page
         *
         * transaction inherits oldest lsn of pages associated
         * with allocation/deallocation of resources (their
@@ -307,7 +307,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        LOGSYNC_UNLOCK(log, flags);
 
        /*
-        *      write the log record
+        *      write the log record
         */
       writeRecord:
        lsn = lmWriteRecord(log, tblk, lrd, tlck);
@@ -372,7 +372,7 @@ lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                goto moveLrd;
 
        /*
-        *      move log record data
+        *      move log record data
         */
        /* retrieve source meta-data page to log */
        if (tlck->flag & tlckPAGELOCK) {
@@ -465,7 +465,7 @@ lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        }
 
        /*
-        *      move log record descriptor
+        *      move log record descriptor
         */
       moveLrd:
        lrd->length = cpu_to_le16(len);
@@ -574,7 +574,7 @@ static int lmNextPage(struct jfs_log * log)
        LOGGC_LOCK(log);
 
        /*
-        *      write or queue the full page at the tail of write queue
+        *      write or queue the full page at the tail of write queue
         */
        /* get the tail tblk on commit queue */
        if (list_empty(&log->cqueue))
@@ -625,7 +625,7 @@ static int lmNextPage(struct jfs_log * log)
        LOGGC_UNLOCK(log);
 
        /*
-        *      allocate/initialize next page
+        *      allocate/initialize next page
         */
        /* if log wraps, the first data page of log is 2
         * (0 never used, 1 is superblock).
@@ -953,7 +953,7 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
                }
 
        /*
-        *      forward syncpt
+        *      forward syncpt
         */
        /* if last sync is same as last syncpt,
         * invoke sync point forward processing to update sync.
@@ -989,7 +989,7 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
                lsn = log->lsn;
 
        /*
-        *      setup next syncpt trigger (SWAG)
+        *      setup next syncpt trigger (SWAG)
         */
        logsize = log->logsize;
 
@@ -1000,11 +1000,11 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
        if (more < 2 * LOGPSIZE) {
                jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n");
                /*
-                *      log wrapping
+                *      log wrapping
                 *
                 * option 1 - panic ? No.!
                 * option 2 - shutdown file systems
-                *            associated with log ?
+                *            associated with log ?
                 * option 3 - extend log ?
                 */
                /*
@@ -1062,7 +1062,7 @@ void jfs_syncpt(struct jfs_log *log, int hard_sync)
 /*
  * NAME:       lmLogOpen()
  *
- * FUNCTION:    open the log on first open;
+ * FUNCTION:   open the log on first open;
  *     insert filesystem in the active list of the log.
  *
  * PARAMETER:  ipmnt   - file system mount inode
@@ -1113,7 +1113,7 @@ int lmLogOpen(struct super_block *sb)
        init_waitqueue_head(&log->syncwait);
 
        /*
-        *      external log as separate logical volume
+        *      external log as separate logical volume
         *
         * file systems to log may have n-to-1 relationship;
         */
@@ -1155,7 +1155,7 @@ journal_found:
        return 0;
 
        /*
-        *      unwind on error
+        *      unwind on error
         */
       shutdown:                /* unwind lbmLogInit() */
        list_del(&log->journal_list);
@@ -1427,7 +1427,7 @@ int lmLogInit(struct jfs_log * log)
        return 0;
 
        /*
-        *      unwind on error
+        *      unwind on error
         */
       errout30:                /* release log page */
        log->wqueue = NULL;
@@ -1480,7 +1480,7 @@ int lmLogClose(struct super_block *sb)
 
        if (test_bit(log_INLINELOG, &log->flag)) {
                /*
-                *      in-line log in host file system
+                *      in-line log in host file system
                 */
                rc = lmLogShutdown(log);
                kfree(log);
@@ -1504,7 +1504,7 @@ int lmLogClose(struct super_block *sb)
                goto out;
 
        /*
-        *      external log as separate logical volume
+        *      external log as separate logical volume
         */
        list_del(&log->journal_list);
        bdev = log->bdev;
@@ -1622,20 +1622,26 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
        if (!list_empty(&log->synclist)) {
                struct logsyncblk *lp;
 
+               printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
                list_for_each_entry(lp, &log->synclist, synclist) {
                        if (lp->xflag & COMMIT_PAGE) {
                                struct metapage *mp = (struct metapage *)lp;
-                               dump_mem("orphan metapage", lp,
-                                        sizeof(struct metapage));
-                               dump_mem("page", mp->page, sizeof(struct page));
-                       }
-                       else
-                               dump_mem("orphan tblock", lp,
-                                        sizeof(struct tblock));
+                               print_hex_dump(KERN_ERR, "metapage: ",
+                                              DUMP_PREFIX_ADDRESS, 16, 4,
+                                              mp, sizeof(struct metapage), 0);
+                               print_hex_dump(KERN_ERR, "page: ",
+                                              DUMP_PREFIX_ADDRESS, 16,
+                                              sizeof(long), mp->page,
+                                              sizeof(struct page), 0);
+                       } else
+                               print_hex_dump(KERN_ERR, "tblock:",
+                                              DUMP_PREFIX_ADDRESS, 16, 4,
+                                              lp, sizeof(struct tblock), 0);
                }
        }
+#else
+       WARN_ON(!list_empty(&log->synclist));
 #endif
-       //assert(list_empty(&log->synclist));
        clear_bit(log_FLUSH, &log->flag);
 }
 
@@ -1723,7 +1729,7 @@ int lmLogShutdown(struct jfs_log * log)
  *
  * PARAMETE:   log     - pointer to logs inode.
  *             fsdev   - kdev_t of filesystem.
- *             serial  - pointer to returned log serial number
+ *             serial  - pointer to returned log serial number
  *             activate - insert/remove device from active list.
  *
  * RETURN:     0       - success
@@ -1963,7 +1969,7 @@ static void lbmfree(struct lbuf * bp)
  * FUNCTION:   add a log buffer to the log redrive list
  *
  * PARAMETER:
- *     bp      - log buffer
+ *     bp      - log buffer
  *
  * NOTES:
  *     Takes log_redrive_lock.
@@ -2054,7 +2060,7 @@ static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag,
        bp->l_flag = flag;
 
        /*
-        *      insert bp at tail of write queue associated with log
+        *      insert bp at tail of write queue associated with log
         *
         * (request is either for bp already/currently at head of queue
         * or new bp to be inserted at tail)
@@ -2117,7 +2123,7 @@ static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
            log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
 
        /*
-        *      initiate pageout of the page
+        *      initiate pageout of the page
         */
        lbmStartIO(bp);
 }
@@ -2128,7 +2134,7 @@ static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
  *
  * FUNCTION:   Interface to DD strategy routine
  *
- * RETURN:      none
+ * RETURN:     none
  *
  * serialization: LCACHE_LOCK() is NOT held during log i/o;
  */
@@ -2222,7 +2228,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
        bio_put(bio);
 
        /*
-        *      pagein completion
+        *      pagein completion
         */
        if (bp->l_flag & lbmREAD) {
                bp->l_flag &= ~lbmREAD;
@@ -2236,7 +2242,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
        }
 
        /*
-        *      pageout completion
+        *      pageout completion
         *
         * the bp at the head of write queue has completed pageout.
         *
@@ -2302,7 +2308,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
        }
 
        /*
-        *      synchronous pageout:
+        *      synchronous pageout:
         *
         * buffer has not necessarily been removed from write queue
         * (e.g., synchronous write of partial-page with COMMIT):
@@ -2316,7 +2322,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
        }
 
        /*
-        *      Group Commit pageout:
+        *      Group Commit pageout:
         */
        else if (bp->l_flag & lbmGC) {
                LCACHE_UNLOCK(flags);
@@ -2324,7 +2330,7 @@ static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
        }
 
        /*
-        *      asynchronous pageout:
+        *      asynchronous pageout:
         *
         * buffer must have been removed from write queue:
         * insert buffer at head of freelist where it can be recycled
@@ -2375,7 +2381,7 @@ int jfsIOWait(void *arg)
  * FUNCTION:   format file system log
  *
  * PARAMETERS:
- *      log    - volume log
+ *     log     - volume log
  *     logAddress - start address of log space in FS block
  *     logSize - length of log space in FS block;
  *
@@ -2407,16 +2413,16 @@ int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
        npages = logSize >> sbi->l2nbperpage;
 
        /*
-        *      log space:
+        *      log space:
         *
         * page 0 - reserved;
         * page 1 - log superblock;
         * page 2 - log data page: A SYNC log record is written
-        *          into this page at logform time;
+        *          into this page at logform time;
         * pages 3-N - log data page: set to empty log data pages;
         */
        /*
-        *      init log superblock: log page 1
+        *      init log superblock: log page 1
         */
        logsuper = (struct logsuper *) bp->l_ldata;
 
@@ -2436,7 +2442,7 @@ int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
                goto exit;
 
        /*
-        *      init pages 2 to npages-1 as log data pages:
+        *      init pages 2 to npages-1 as log data pages:
         *
         * log page sequence number (lpsn) initialization:
         *
@@ -2479,7 +2485,7 @@ int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
                goto exit;
 
        /*
-        *      initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
+        *      initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
         */
        for (lspn = 0; lspn < npages - 3; lspn++) {
                lp->h.page = lp->t.page = cpu_to_le32(lspn);
@@ -2495,7 +2501,7 @@ int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
        rc = 0;
 exit:
        /*
-        *      finalize log
+        *      finalize log
         */
        /* release the buffer */
        lbmFree(bp);
index a53fb17ea219eeb8bc6e0bd903954b0fa0e724f6..1f85ef0ec0456afbe937be2b03ac215473ceb3fa 100644 (file)
@@ -144,7 +144,7 @@ struct logpage {
  *
  * (this comment should be rewritten !)
  * jfs uses only "after" log records (only a single writer is allowed
- * in a  page, pages are written to temporary paging space if
+ * in a page, pages are written to temporary paging space if
  * if they must be written to disk before commit, and i/o is
  * scheduled for modified pages to their home location after
  * the log records containing the after values and the commit
@@ -153,7 +153,7 @@ struct logpage {
  *
  * a log record consists of a data area of variable length followed by
  * a descriptor of fixed size LOGRDSIZE bytes.
- * the  data area is rounded up to an integral number of 4-bytes and
+ * the data area is rounded up to an integral number of 4-bytes and
  * must be no longer than LOGPSIZE.
  * the descriptor is of size of multiple of 4-bytes and aligned on a
  * 4-byte boundary.
@@ -215,13 +215,13 @@ struct lrd {
        union {
 
                /*
-                *      COMMIT: commit
+                *      COMMIT: commit
                 *
                 * transaction commit: no type-dependent information;
                 */
 
                /*
-                *      REDOPAGE: after-image
+                *      REDOPAGE: after-image
                 *
                 * apply after-image;
                 *
@@ -236,7 +236,7 @@ struct lrd {
                } redopage;     /* (20) */
 
                /*
-                *      NOREDOPAGE: the page is freed
+                *      NOREDOPAGE: the page is freed
                 *
                 * do not apply after-image records which precede this record
                 * in the log with the same page block number to this page.
@@ -252,7 +252,7 @@ struct lrd {
                } noredopage;   /* (20) */
 
                /*
-                *      UPDATEMAP: update block allocation map
+                *      UPDATEMAP: update block allocation map
                 *
                 * either in-line PXD,
                 * or     out-of-line  XADLIST;
@@ -268,7 +268,7 @@ struct lrd {
                } updatemap;    /* (20) */
 
                /*
-                *      NOREDOINOEXT: the inode extent is freed
+                *      NOREDOINOEXT: the inode extent is freed
                 *
                 * do not apply after-image records which precede this
                 * record in the log with the any of the 4 page block
@@ -286,7 +286,7 @@ struct lrd {
                } noredoinoext; /* (20) */
 
                /*
-                *      SYNCPT: log sync point
+                *      SYNCPT: log sync point
                 *
                 * replay log upto syncpt address specified;
                 */
@@ -295,13 +295,13 @@ struct lrd {
                } syncpt;
 
                /*
-                *      MOUNT: file system mount
+                *      MOUNT: file system mount
                 *
                 * file system mount: no type-dependent information;
                 */
 
                /*
-                *      ? FREEXTENT: free specified extent(s)
+                *      ? FREEXTENT: free specified extent(s)
                 *
                 * free specified extent(s) from block allocation map
                 * N.B.: nextents should be length of data/sizeof(xad_t)
@@ -314,7 +314,7 @@ struct lrd {
                } freextent;
 
                /*
-                *      ? NOREDOFILE: this file is freed
+                *      ? NOREDOFILE: this file is freed
                 *
                 * do not apply records which precede this record in the log
                 * with the same inode number.
@@ -330,7 +330,7 @@ struct lrd {
                } noredofile;
 
                /*
-                *      ? NEWPAGE:
+                *      ? NEWPAGE:
                 *
                 * metadata type dependent
                 */
@@ -342,7 +342,7 @@ struct lrd {
                } newpage;
 
                /*
-                *      ? DUMMY: filler
+                *      ? DUMMY: filler
                 *
                 * no type-dependent information
                 */
index 43d4f69afbeca923878a45d77fa68d4eb53a55f9..77c7f1129dde636e734f6e354218c72eff5ed0d9 100644 (file)
@@ -472,7 +472,8 @@ add_failed:
        printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
        goto skip;
 dump_bio:
-       dump_mem("bio", bio, sizeof(*bio));
+       print_hex_dump(KERN_ERR, "JFS: dump of bio: ", DUMP_PREFIX_ADDRESS, 16,
+                      4, bio, sizeof(*bio), 0);
 skip:
        bio_put(bio);
        unlock_page(page);
index 4dd479834897be20d7e8ee4d5b7b66eccf1d0137..644429acb8c05d92d49e2129df8d155d37792c4b 100644 (file)
@@ -80,7 +80,7 @@ static int logMOUNT(struct super_block *sb);
  */
 int jfs_mount(struct super_block *sb)
 {
-       int rc = 0;             /* Return code          */
+       int rc = 0;             /* Return code */
        struct jfs_sb_info *sbi = JFS_SBI(sb);
        struct inode *ipaimap = NULL;
        struct inode *ipaimap2 = NULL;
@@ -169,7 +169,7 @@ int jfs_mount(struct super_block *sb)
                sbi->ipaimap2 = NULL;
 
        /*
-        *      mount (the only/single) fileset
+        *      mount (the only/single) fileset
         */
        /*
         * open fileset inode allocation map (aka fileset inode)
@@ -195,7 +195,7 @@ int jfs_mount(struct super_block *sb)
        goto out;
 
        /*
-        *      unwind on error
+        *      unwind on error
         */
       errout41:                /* close fileset inode allocation map inode */
        diFreeSpecial(ipimap);
index 25430d0b0d593a4576cbe9028a5c7c8bdb353d8c..7aa1f7004eaf9f54aded2f394e8e0bcda21057fe 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 /*
- *      jfs_txnmgr.c: transaction manager
+ *     jfs_txnmgr.c: transaction manager
  *
  * notes:
  * transaction starts with txBegin() and ends with txCommit()
@@ -60,7 +60,7 @@
 #include "jfs_debug.h"
 
 /*
- *      transaction management structures
+ *     transaction management structures
  */
 static struct {
        int freetid;            /* index of a free tid structure */
@@ -103,19 +103,19 @@ module_param(nTxLock, int, 0);
 MODULE_PARM_DESC(nTxLock,
                 "Number of transaction locks (max:65536)");
 
-struct tblock *TxBlock;                /* transaction block table */
-static int TxLockLWM;          /* Low water mark for number of txLocks used */
-static int TxLockHWM;          /* High water mark for number of txLocks used */
-static int TxLockVHWM;         /* Very High water mark */
-struct tlock *TxLock;           /* transaction lock table */
+struct tblock *TxBlock;        /* transaction block table */
+static int TxLockLWM;  /* Low water mark for number of txLocks used */
+static int TxLockHWM;  /* High water mark for number of txLocks used */
+static int TxLockVHWM; /* Very High water mark */
+struct tlock *TxLock;  /* transaction lock table */
 
 /*
- *      transaction management lock
+ *     transaction management lock
  */
 static DEFINE_SPINLOCK(jfsTxnLock);
 
-#define TXN_LOCK()              spin_lock(&jfsTxnLock)
-#define TXN_UNLOCK()            spin_unlock(&jfsTxnLock)
+#define TXN_LOCK()             spin_lock(&jfsTxnLock)
+#define TXN_UNLOCK()           spin_unlock(&jfsTxnLock)
 
 #define LAZY_LOCK_INIT()       spin_lock_init(&TxAnchor.LazyLock);
 #define LAZY_LOCK(flags)       spin_lock_irqsave(&TxAnchor.LazyLock, flags)
@@ -148,7 +148,7 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
 #define TXN_WAKEUP(event) wake_up_all(event)
 
 /*
- *      statistics
+ *     statistics
  */
 static struct {
        tid_t maxtid;           /* 4: biggest tid ever used */
@@ -181,8 +181,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 static void LogSyncRelease(struct metapage * mp);
 
 /*
- *              transaction block/lock management
- *              ---------------------------------
+ *             transaction block/lock management
+ *             ---------------------------------
  */
 
 /*
@@ -227,9 +227,9 @@ static void txLockFree(lid_t lid)
 }
 
 /*
- * NAME:        txInit()
+ * NAME:       txInit()
  *
- * FUNCTION:    initialize transaction management structures
+ * FUNCTION:   initialize transaction management structures
  *
  * RETURN:
  *
@@ -333,9 +333,9 @@ int txInit(void)
 }
 
 /*
- * NAME:        txExit()
+ * NAME:       txExit()
  *
- * FUNCTION:    clean up when module is unloaded
+ * FUNCTION:   clean up when module is unloaded
  */
 void txExit(void)
 {
@@ -346,12 +346,12 @@ void txExit(void)
 }
 
 /*
- * NAME:        txBegin()
+ * NAME:       txBegin()
  *
- * FUNCTION:    start a transaction.
+ * FUNCTION:   start a transaction.
  *
- * PARAMETER:   sb     - superblock
- *              flag   - force for nested tx;
+ * PARAMETER:  sb      - superblock
+ *             flag    - force for nested tx;
  *
  * RETURN:     tid     - transaction id
  *
@@ -447,13 +447,13 @@ tid_t txBegin(struct super_block *sb, int flag)
 }
 
 /*
- * NAME:        txBeginAnon()
+ * NAME:       txBeginAnon()
  *
- * FUNCTION:    start an anonymous transaction.
+ * FUNCTION:   start an anonymous transaction.
  *             Blocks if logsync or available tlocks are low to prevent
  *             anonymous tlocks from depleting supply.
  *
- * PARAMETER:   sb     - superblock
+ * PARAMETER:  sb      - superblock
  *
  * RETURN:     none
  */
@@ -489,11 +489,11 @@ void txBeginAnon(struct super_block *sb)
 }
 
 /*
- *      txEnd()
+ *     txEnd()
  *
  * function: free specified transaction block.
  *
- *      logsync barrier processing:
+ *     logsync barrier processing:
  *
  * serialization:
  */
@@ -577,13 +577,13 @@ wakeup:
 }
 
 /*
- *      txLock()
+ *     txLock()
  *
  * function: acquire a transaction lock on the specified <mp>
  *
  * parameter:
  *
- * return:      transaction lock id
+ * return:     transaction lock id
  *
  * serialization:
  */
@@ -829,12 +829,16 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
        /* Only locks on ipimap or ipaimap should reach here */
        /* assert(jfs_ip->fileset == AGGREGATE_I); */
        if (jfs_ip->fileset != AGGREGATE_I) {
-               jfs_err("txLock: trying to lock locked page!");
-               dump_mem("ip", ip, sizeof(struct inode));
-               dump_mem("mp", mp, sizeof(struct metapage));
-               dump_mem("Locker's tblk", tid_to_tblock(tid),
-                        sizeof(struct tblock));
-               dump_mem("Tlock", tlck, sizeof(struct tlock));
+               printk(KERN_ERR "txLock: trying to lock locked page!");
+               print_hex_dump(KERN_ERR, "ip: ", DUMP_PREFIX_ADDRESS, 16, 4,
+                              ip, sizeof(*ip), 0);
+               print_hex_dump(KERN_ERR, "mp: ", DUMP_PREFIX_ADDRESS, 16, 4,
+                              mp, sizeof(*mp), 0);
+               print_hex_dump(KERN_ERR, "Locker's tblock: ",
+                              DUMP_PREFIX_ADDRESS, 16, 4, tid_to_tblock(tid),
+                              sizeof(struct tblock), 0);
+               print_hex_dump(KERN_ERR, "Tlock: ", DUMP_PREFIX_ADDRESS, 16, 4,
+                              tlck, sizeof(*tlck), 0);
                BUG();
        }
        INCREMENT(stattx.waitlock);     /* statistics */
@@ -857,17 +861,17 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
 }
 
 /*
- * NAME:        txRelease()
+ * NAME:       txRelease()
  *
- * FUNCTION:    Release buffers associated with transaction locks, but don't
+ * FUNCTION:   Release buffers associated with transaction locks, but don't
  *             mark homeok yet.  The allows other transactions to modify
  *             buffers, but won't let them go to disk until commit record
  *             actually gets written.
  *
  * PARAMETER:
- *              tblk    -
+ *             tblk    -
  *
- * RETURN:      Errors from subroutines.
+ * RETURN:     Errors from subroutines.
  */
 static void txRelease(struct tblock * tblk)
 {
@@ -896,10 +900,10 @@ static void txRelease(struct tblock * tblk)
 }
 
 /*
- * NAME:        txUnlock()
+ * NAME:       txUnlock()
  *
- * FUNCTION:    Initiates pageout of pages modified by tid in journalled
- *              objects and frees their lockwords.
+ * FUNCTION:   Initiates pageout of pages modified by tid in journalled
+ *             objects and frees their lockwords.
  */
 static void txUnlock(struct tblock * tblk)
 {
@@ -983,10 +987,10 @@ static void txUnlock(struct tblock * tblk)
 }
 
 /*
- *      txMaplock()
+ *     txMaplock()
  *
  * function: allocate a transaction lock for freed page/entry;
- *      for freed page, maplock is used as xtlock/dtlock type;
+ *     for freed page, maplock is used as xtlock/dtlock type;
  */
 struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
 {
@@ -1057,7 +1061,7 @@ struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
 }
 
 /*
- *      txLinelock()
+ *     txLinelock()
  *
  * function: allocate a transaction lock for log vector list
  */
@@ -1092,39 +1096,39 @@ struct linelock *txLinelock(struct linelock * tlock)
 }
 
 /*
- *              transaction commit management
- *              -----------------------------
+ *             transaction commit management
+ *             -----------------------------
  */
 
 /*
- * NAME:        txCommit()
- *
- * FUNCTION:    commit the changes to the objects specified in
- *              clist.  For journalled segments only the
- *              changes of the caller are committed, ie by tid.
- *              for non-journalled segments the data are flushed to
- *              disk and then the change to the disk inode and indirect
- *              blocks committed (so blocks newly allocated to the
- *              segment will be made a part of the segment atomically).
- *
- *              all of the segments specified in clist must be in
- *              one file system. no more than 6 segments are needed
- *              to handle all unix svcs.
- *
- *              if the i_nlink field (i.e. disk inode link count)
- *              is zero, and the type of inode is a regular file or
- *              directory, or symbolic link , the inode is truncated
- *              to zero length. the truncation is committed but the
- *              VM resources are unaffected until it is closed (see
- *              iput and iclose).
+ * NAME:       txCommit()
+ *
+ * FUNCTION:   commit the changes to the objects specified in
+ *             clist.  For journalled segments only the
+ *             changes of the caller are committed, ie by tid.
+ *             for non-journalled segments the data are flushed to
+ *             disk and then the change to the disk inode and indirect
+ *             blocks committed (so blocks newly allocated to the
+ *             segment will be made a part of the segment atomically).
+ *
+ *             all of the segments specified in clist must be in
+ *             one file system. no more than 6 segments are needed
+ *             to handle all unix svcs.
+ *
+ *             if the i_nlink field (i.e. disk inode link count)
+ *             is zero, and the type of inode is a regular file or
+ *             directory, or symbolic link , the inode is truncated
+ *             to zero length. the truncation is committed but the
+ *             VM resources are unaffected until it is closed (see
+ *             iput and iclose).
  *
  * PARAMETER:
  *
  * RETURN:
  *
  * serialization:
- *              on entry the inode lock on each segment is assumed
- *              to be held.
+ *             on entry the inode lock on each segment is assumed
+ *             to be held.
  *
  * i/o error:
  */
@@ -1175,7 +1179,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
        if ((flag & (COMMIT_FORCE | COMMIT_SYNC)) == 0)
                tblk->xflag |= COMMIT_LAZY;
        /*
-        *      prepare non-journaled objects for commit
+        *      prepare non-journaled objects for commit
         *
         * flush data pages of non-journaled file
         * to prevent the file getting non-initialized disk blocks
@@ -1186,7 +1190,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
        cd.nip = nip;
 
        /*
-        *      acquire transaction lock on (on-disk) inodes
+        *      acquire transaction lock on (on-disk) inodes
         *
         * update on-disk inode from in-memory inode
         * acquiring transaction locks for AFTER records
@@ -1262,7 +1266,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
        }
 
        /*
-        *      write log records from transaction locks
+        *      write log records from transaction locks
         *
         * txUpdateMap() resets XAD_NEW in XAD.
         */
@@ -1294,7 +1298,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
                !test_cflag(COMMIT_Nolink, tblk->u.ip)));
 
        /*
-        *      write COMMIT log record
+        *      write COMMIT log record
         */
        lrd->type = cpu_to_le16(LOG_COMMIT);
        lrd->length = 0;
@@ -1303,7 +1307,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
        lmGroupCommit(log, tblk);
 
        /*
-        *      - transaction is now committed -
+        *      - transaction is now committed -
         */
 
        /*
@@ -1314,11 +1318,11 @@ int txCommit(tid_t tid,         /* transaction identifier */
                txForce(tblk);
 
        /*
-        *      update allocation map.
+        *      update allocation map.
         *
         * update inode allocation map and inode:
         * free pager lock on memory object of inode if any.
-        * update  block allocation map.
+        * update block allocation map.
         *
         * txUpdateMap() resets XAD_NEW in XAD.
         */
@@ -1326,7 +1330,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
                txUpdateMap(tblk);
 
        /*
-        *      free transaction locks and pageout/free pages
+        *      free transaction locks and pageout/free pages
         */
        txRelease(tblk);
 
@@ -1335,7 +1339,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
 
 
        /*
-        *      reset in-memory object state
+        *      reset in-memory object state
         */
        for (k = 0; k < cd.nip; k++) {
                ip = cd.iplist[k];
@@ -1358,11 +1362,11 @@ int txCommit(tid_t tid,         /* transaction identifier */
 }
 
 /*
- * NAME:        txLog()
+ * NAME:       txLog()
  *
- * FUNCTION:    Writes AFTER log records for all lines modified
- *              by tid for segments specified by inodes in comdata.
- *              Code assumes only WRITELOCKS are recorded in lockwords.
+ * FUNCTION:   Writes AFTER log records for all lines modified
+ *             by tid for segments specified by inodes in comdata.
+ *             Code assumes only WRITELOCKS are recorded in lockwords.
  *
  * PARAMETERS:
  *
@@ -1421,12 +1425,12 @@ static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd)
 }
 
 /*
- *      diLog()
+ *     diLog()
  *
- * function:    log inode tlock and format maplock to update bmap;
+ * function:   log inode tlock and format maplock to update bmap;
  */
 static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
-         struct tlock * tlck, struct commit * cd)
+                struct tlock * tlck, struct commit * cd)
 {
        int rc = 0;
        struct metapage *mp;
@@ -1442,7 +1446,7 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        pxd = &lrd->log.redopage.pxd;
 
        /*
-        *      inode after image
+        *      inode after image
         */
        if (tlck->type & tlckENTRY) {
                /* log after-image for logredo(): */
@@ -1456,7 +1460,7 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                tlck->flag |= tlckWRITEPAGE;
        } else if (tlck->type & tlckFREE) {
                /*
-                *      free inode extent
+                *      free inode extent
                 *
                 * (pages of the freed inode extent have been invalidated and
                 * a maplock for free of the extent has been formatted at
@@ -1498,7 +1502,7 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                jfs_err("diLog: UFO type tlck:0x%p", tlck);
 #ifdef  _JFS_WIP
        /*
-        *      alloc/free external EA extent
+        *      alloc/free external EA extent
         *
         * a maplock for txUpdateMap() to update bPWMAP for alloc/free
         * of the extent has been formatted at txLock() time;
@@ -1534,9 +1538,9 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 }
 
 /*
- *      dataLog()
+ *     dataLog()
  *
- * function:    log data tlock
+ * function:   log data tlock
  */
 static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
            struct tlock * tlck)
@@ -1580,9 +1584,9 @@ static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 }
 
 /*
- *      dtLog()
+ *     dtLog()
  *
- * function:    log dtree tlock and format maplock to update bmap;
+ * function:   log dtree tlock and format maplock to update bmap;
  */
 static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
           struct tlock * tlck)
@@ -1603,10 +1607,10 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
 
        /*
-        *      page extension via relocation: entry insertion;
-        *      page extension in-place: entry insertion;
-        *      new right page from page split, reinitialized in-line
-        *      root from root page split: entry insertion;
+        *      page extension via relocation: entry insertion;
+        *      page extension in-place: entry insertion;
+        *      new right page from page split, reinitialized in-line
+        *      root from root page split: entry insertion;
         */
        if (tlck->type & (tlckNEW | tlckEXTEND)) {
                /* log after-image of the new page for logredo():
@@ -1641,8 +1645,8 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        }
 
        /*
-        *      entry insertion/deletion,
-        *      sibling page link update (old right page before split);
+        *      entry insertion/deletion,
+        *      sibling page link update (old right page before split);
         */
        if (tlck->type & (tlckENTRY | tlckRELINK)) {
                /* log after-image for logredo(): */
@@ -1658,11 +1662,11 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        }
 
        /*
-        *      page deletion: page has been invalidated
-        *      page relocation: source extent
+        *      page deletion: page has been invalidated
+        *      page relocation: source extent
         *
-        *      a maplock for free of the page has been formatted
-        *      at txLock() time);
+        *      a maplock for free of the page has been formatted
+        *      at txLock() time);
         */
        if (tlck->type & (tlckFREE | tlckRELOCATE)) {
                /* log LOG_NOREDOPAGE of the deleted page for logredo()
@@ -1683,9 +1687,9 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 }
 
 /*
- *      xtLog()
+ *     xtLog()
  *
- * function:    log xtree tlock and format maplock to update bmap;
+ * function:   log xtree tlock and format maplock to update bmap;
  */
 static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
           struct tlock * tlck)
@@ -1725,8 +1729,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        xadlock = (struct xdlistlock *) maplock;
 
        /*
-        *      entry insertion/extension;
-        *      sibling page link update (old right page before split);
+        *      entry insertion/extension;
+        *      sibling page link update (old right page before split);
         */
        if (tlck->type & (tlckNEW | tlckGROW | tlckRELINK)) {
                /* log after-image for logredo():
@@ -1801,7 +1805,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        }
 
        /*
-        *      page deletion: file deletion/truncation (ref. xtTruncate())
+        *      page deletion: file deletion/truncation (ref. xtTruncate())
         *
         * (page will be invalidated after log is written and bmap
         * is updated from the page);
@@ -1908,13 +1912,13 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        }
 
        /*
-        *      page/entry truncation: file truncation (ref. xtTruncate())
+        *      page/entry truncation: file truncation (ref. xtTruncate())
         *
-        *     |----------+------+------+---------------|
-        *                |      |      |
-        *                |      |     hwm - hwm before truncation
-        *                |     next - truncation point
-        *               lwm - lwm before truncation
+        *      |----------+------+------+---------------|
+        *                 |      |      |
+        *                 |      |     hwm - hwm before truncation
+        *                 |     next - truncation point
+        *                lwm - lwm before truncation
         * header ?
         */
        if (tlck->type & tlckTRUNCATE) {
@@ -1937,7 +1941,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                twm = xtlck->twm.offset;
 
                /*
-                *      write log records
+                *      write log records
                 */
                /* log after-image for logredo():
                 *
@@ -1997,7 +2001,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                }
 
                /*
-                *      format maplock(s) for txUpdateMap() to update bmap
+                *      format maplock(s) for txUpdateMap() to update bmap
                 */
                maplock->index = 0;
 
@@ -2069,9 +2073,9 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 }
 
 /*
- *      mapLog()
+ *     mapLog()
  *
- * function:    log from maplock of freed data extents;
+ * function:   log from maplock of freed data extents;
  */
 static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
                   struct tlock * tlck)
@@ -2081,7 +2085,7 @@ static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
        pxd_t *pxd;
 
        /*
-        *      page relocation: free the source page extent
+        *      page relocation: free the source page extent
         *
         * a maplock for txUpdateMap() for free of the page
         * has been formatted at txLock() time saving the src
@@ -2155,10 +2159,10 @@ static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 }
 
 /*
- *      txEA()
+ *     txEA()
  *
- * function:    acquire maplock for EA/ACL extents or
- *              set COMMIT_INLINE flag;
+ * function:   acquire maplock for EA/ACL extents or
+ *             set COMMIT_INLINE flag;
  */
 void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
 {
@@ -2207,10 +2211,10 @@ void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
 }
 
 /*
- *      txForce()
+ *     txForce()
  *
  * function: synchronously write pages locked by transaction
- *              after txLog() but before txUpdateMap();
+ *          after txLog() but before txUpdateMap();
  */
 static void txForce(struct tblock * tblk)
 {
@@ -2273,10 +2277,10 @@ static void txForce(struct tblock * tblk)
 }
 
 /*
- *      txUpdateMap()
+ *     txUpdateMap()
  *
- * function:    update persistent allocation map (and working map
- *              if appropriate);
+ * function:   update persistent allocation map (and working map
+ *             if appropriate);
  *
  * parameter:
  */
@@ -2298,7 +2302,7 @@ static void txUpdateMap(struct tblock * tblk)
 
 
        /*
-        *      update block allocation map
+        *      update block allocation map
         *
         * update allocation state in pmap (and wmap) and
         * update lsn of the pmap page;
@@ -2382,7 +2386,7 @@ static void txUpdateMap(struct tblock * tblk)
                }
        }
        /*
-        *      update inode allocation map
+        *      update inode allocation map
         *
         * update allocation state in pmap and
         * update lsn of the pmap page;
@@ -2407,24 +2411,24 @@ static void txUpdateMap(struct tblock * tblk)
 }
 
 /*
- *      txAllocPMap()
+ *     txAllocPMap()
  *
  * function: allocate from persistent map;
  *
  * parameter:
- *      ipbmap  -
- *      malock -
- *              xad list:
- *              pxd:
- *
- *      maptype -
- *              allocate from persistent map;
- *              free from persistent map;
- *              (e.g., tmp file - free from working map at releae
- *               of last reference);
- *              free from persistent and working map;
- *
- *      lsn     - log sequence number;
+ *     ipbmap  -
+ *     malock  -
+ *             xad list:
+ *             pxd:
+ *
+ *     maptype -
+ *             allocate from persistent map;
+ *             free from persistent map;
+ *             (e.g., tmp file - free from working map at releae
+ *              of last reference);
+ *             free from persistent and working map;
+ *
+ *     lsn     - log sequence number;
  */
 static void txAllocPMap(struct inode *ip, struct maplock * maplock,
                        struct tblock * tblk)
@@ -2478,9 +2482,9 @@ static void txAllocPMap(struct inode *ip, struct maplock * maplock,
 }
 
 /*
- *      txFreeMap()
+ *     txFreeMap()
  *
- * function:    free from persistent and/or working map;
+ * function:   free from persistent and/or working map;
  *
  * todo: optimization
  */
@@ -2579,9 +2583,9 @@ void txFreeMap(struct inode *ip,
 }
 
 /*
- *      txFreelock()
+ *     txFreelock()
  *
- * function:    remove tlock from inode anonymous locklist
+ * function:   remove tlock from inode anonymous locklist
  */
 void txFreelock(struct inode *ip)
 {
@@ -2619,7 +2623,7 @@ void txFreelock(struct inode *ip)
 }
 
 /*
- *      txAbort()
+ *     txAbort()
  *
  * function: abort tx before commit;
  *
@@ -2679,7 +2683,7 @@ void txAbort(tid_t tid, int dirty)
 }
 
 /*
- *      txLazyCommit(void)
+ *     txLazyCommit(void)
  *
  *     All transactions except those changing ipimap (COMMIT_FORCE) are
  *     processed by this routine.  This insures that the inode and block
@@ -2728,7 +2732,7 @@ static void txLazyCommit(struct tblock * tblk)
 }
 
 /*
- *      jfs_lazycommit(void)
+ *     jfs_lazycommit(void)
  *
  *     To be run as a kernel daemon.  If lbmIODone is called in an interrupt
  *     context, or where blocking is not wanted, this routine will process
@@ -2913,7 +2917,7 @@ void txResume(struct super_block *sb)
 }
 
 /*
- *      jfs_sync(void)
+ *     jfs_sync(void)
  *
  *     To be run as a kernel daemon.  This is awakened when tlocks run low.
  *     We write any inodes that have anonymous tlocks so they will become
index 7863cf21afcac82ef586c97541697f14d2640eaa..ab7288937019c7b718acbd9c19957d7131c0427b 100644 (file)
@@ -94,7 +94,7 @@ extern struct tblock *TxBlock;        /* transaction block table */
  */
 struct tlock {
        lid_t next;             /* 2: index next lockword on tid locklist
-                                *          next lockword on freelist
+                                *          next lockword on freelist
                                 */
        tid_t tid;              /* 2: transaction id holding lock */
 
index 09b2529586874159c550978ea46410285738035a..649f9817accd05f5899e54dca2ecb0dcb406c6d6 100644 (file)
@@ -21,7 +21,7 @@
 /*
  *     jfs_types.h:
  *
- * basic type/utility  definitions
+ * basic type/utility definitions
  *
  * note: this header file must be the 1st include file
  * of JFS include list in all JFS .c file.
@@ -54,8 +54,8 @@ struct timestruc_t {
  */
 
 #define LEFTMOSTONE    0x80000000
-#define        HIGHORDER       0x80000000u     /* high order bit on            */
-#define        ONES            0xffffffffu     /* all bit on                   */
+#define        HIGHORDER       0x80000000u     /* high order bit on    */
+#define        ONES            0xffffffffu     /* all bit on           */
 
 /*
  *     logical xd (lxd)
@@ -148,7 +148,7 @@ typedef struct {
 #define sizeDXD(dxd)   le32_to_cpu((dxd)->size)
 
 /*
- *      directory entry argument
+ *     directory entry argument
  */
 struct component_name {
        int namlen;
@@ -160,14 +160,14 @@ struct component_name {
  *     DASD limit information - stored in directory inode
  */
 struct dasd {
-       u8 thresh;              /* Alert Threshold (in percent) */
-       u8 delta;               /* Alert Threshold delta (in percent)   */
+       u8 thresh;              /* Alert Threshold (in percent)         */
+       u8 delta;               /* Alert Threshold delta (in percent)   */
        u8 rsrvd1;
-       u8 limit_hi;            /* DASD limit (in logical blocks)       */
-       __le32 limit_lo;        /* DASD limit (in logical blocks)       */
+       u8 limit_hi;            /* DASD limit (in logical blocks)       */
+       __le32 limit_lo;        /* DASD limit (in logical blocks)       */
        u8 rsrvd2[3];
-       u8 used_hi;             /* DASD usage (in logical blocks)       */
-       __le32 used_lo;         /* DASD usage (in logical blocks)       */
+       u8 used_hi;             /* DASD usage (in logical blocks)       */
+       __le32 used_lo;         /* DASD usage (in logical blocks)       */
 };
 
 #define DASDLIMIT(dasdp) \
index a386f48c73fcb5270bfcf90ac067d172792280f6..7971f37534a359e0dcfed248cb56e56a14c7fac7 100644 (file)
@@ -60,7 +60,7 @@ int jfs_umount(struct super_block *sb)
        jfs_info("UnMount JFS: sb:0x%p", sb);
 
        /*
-        *      update superblock and close log
+        *      update superblock and close log
         *
         * if mounted read-write and log based recovery was enabled
         */
index acc97c46d8a4096125ce4e2355a12e779d7aa376..1543906a2e0dd29ac7008ac1204c490b765ba14b 100644 (file)
@@ -16,7 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 /*
- *      jfs_xtree.c: extent allocation descriptor B+-tree manager
+ *     jfs_xtree.c: extent allocation descriptor B+-tree manager
  */
 
 #include <linux/fs.h>
 /*
  * xtree local flag
  */
-#define XT_INSERT       0x00000001
+#define XT_INSERT      0x00000001
 
 /*
- *       xtree key/entry comparison: extent offset
+ *     xtree key/entry comparison: extent offset
  *
  * return:
- *      -1: k < start of extent
- *       0: start_of_extent <= k <= end_of_extent
- *       1: k > end_of_extent
+ *     -1: k < start of extent
+ *      0: start_of_extent <= k <= end_of_extent
+ *      1: k > end_of_extent
  */
 #define XT_CMP(CMP, K, X, OFFSET64)\
 {\
-        OFFSET64 = offsetXAD(X);\
-        (CMP) = ((K) >= OFFSET64 + lengthXAD(X)) ? 1 :\
-              ((K) < OFFSET64) ? -1 : 0;\
+       OFFSET64 = offsetXAD(X);\
+       (CMP) = ((K) >= OFFSET64 + lengthXAD(X)) ? 1 :\
+               ((K) < OFFSET64) ? -1 : 0;\
 }
 
 /* write a xad entry */
 #define XT_PUTENTRY(XAD, FLAG, OFF, LEN, ADDR)\
 {\
-        (XAD)->flag = (FLAG);\
-        XADoffset((XAD), (OFF));\
-        XADlength((XAD), (LEN));\
-        XADaddress((XAD), (ADDR));\
+       (XAD)->flag = (FLAG);\
+       XADoffset((XAD), (OFF));\
+       XADlength((XAD), (LEN));\
+       XADaddress((XAD), (ADDR));\
 }
 
 #define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot)
                        MP = NULL;\
                        RC = -EIO;\
                }\
-        }\
+       }\
 }
 
 /* for consistency */
 #define XT_PUTPAGE(MP) BT_PUTPAGE(MP)
 
-#define XT_GETSEARCH(IP, LEAF, BN, MP,  P, INDEX) \
+#define XT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \
        BT_GETSEARCH(IP, LEAF, BN, MP, xtpage_t, P, INDEX, i_xtroot)
 /* xtree entry parameter descriptor */
 struct xtsplit {
@@ -97,7 +97,7 @@ struct xtsplit {
 
 
 /*
- *      statistics
+ *     statistics
  */
 #ifdef CONFIG_JFS_STATISTICS
 static struct {
@@ -136,7 +136,7 @@ static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * fp);
 #endif                         /*  _STILL_TO_PORT */
 
 /*
- *      xtLookup()
+ *     xtLookup()
  *
  * function: map a single page into a physical extent;
  */
@@ -179,7 +179,7 @@ int xtLookup(struct inode *ip, s64 lstart,
        }
 
        /*
-        *      compute the physical extent covering logical extent
+        *      compute the physical extent covering logical extent
         *
         * N.B. search may have failed (e.g., hole in sparse file),
         * and returned the index of the next entry.
@@ -220,27 +220,27 @@ int xtLookup(struct inode *ip, s64 lstart,
 
 
 /*
- *      xtLookupList()
+ *     xtLookupList()
  *
  * function: map a single logical extent into a list of physical extent;
  *
  * parameter:
- *      struct inode    *ip,
- *      struct lxdlist  *lxdlist,       lxd list (in)
- *      struct xadlist  *xadlist,       xad list (in/out)
- *      int            flag)
+ *     struct inode    *ip,
+ *     struct lxdlist  *lxdlist,       lxd list (in)
+ *     struct xadlist  *xadlist,       xad list (in/out)
+ *     int             flag)
  *
  * coverage of lxd by xad under assumption of
  * . lxd's are ordered and disjoint.
  * . xad's are ordered and disjoint.
  *
  * return:
- *      0:      success
+ *     0:      success
  *
  * note: a page being written (even a single byte) is backed fully,
- *      except the last page which is only backed with blocks
- *      required to cover the last byte;
- *      the extent backing a page is fully contained within an xad;
+ *     except the last page which is only backed with blocks
+ *     required to cover the last byte;
+ *     the extent backing a page is fully contained within an xad;
  */
 int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
                 struct xadlist * xadlist, int flag)
@@ -284,7 +284,7 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
                return rc;
 
        /*
-        *      compute the physical extent covering logical extent
+        *      compute the physical extent covering logical extent
         *
         * N.B. search may have failed (e.g., hole in sparse file),
         * and returned the index of the next entry.
@@ -343,7 +343,7 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
                if (lstart >= size)
                        goto mapend;
 
-               /* compare with the current xad  */
+               /* compare with the current xad */
                goto compare1;
        }
        /* lxd is covered by xad */
@@ -430,7 +430,7 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
        /*
         * lxd is partially covered by xad
         */
-       else {                  /* (xend < lend)  */
+       else {                  /* (xend < lend) */
 
                /*
                 * get next xad
@@ -477,22 +477,22 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
 
 
 /*
- *      xtSearch()
+ *     xtSearch()
  *
- * function:    search for the xad entry covering specified offset.
+ * function:   search for the xad entry covering specified offset.
  *
  * parameters:
- *      ip      - file object;
- *      xoff    - extent offset;
- *      nextp  - address of next extent (if any) for search miss
- *      cmpp    - comparison result:
- *      btstack - traverse stack;
- *      flag    - search process flag (XT_INSERT);
+ *     ip      - file object;
+ *     xoff    - extent offset;
+ *     nextp   - address of next extent (if any) for search miss
+ *     cmpp    - comparison result:
+ *     btstack - traverse stack;
+ *     flag    - search process flag (XT_INSERT);
  *
  * returns:
- *      btstack contains (bn, index) of search path traversed to the entry.
- *      *cmpp is set to result of comparison with the entry returned.
- *      the page containing the entry is pinned at exit.
+ *     btstack contains (bn, index) of search path traversed to the entry.
+ *     *cmpp is set to result of comparison with the entry returned.
+ *     the page containing the entry is pinned at exit.
  */
 static int xtSearch(struct inode *ip, s64 xoff,        s64 *nextp,
                    int *cmpp, struct btstack * btstack, int flag)
@@ -517,7 +517,7 @@ static int xtSearch(struct inode *ip, s64 xoff,     s64 *nextp,
        btstack->nsplit = 0;
 
        /*
-        *      search down tree from root:
+        *      search down tree from root:
         *
         * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
         * internal page, child page Pi contains entry with k, Ki <= K < Kj.
@@ -642,7 +642,7 @@ static int xtSearch(struct inode *ip, s64 xoff,     s64 *nextp,
                        XT_CMP(cmp, xoff, &p->xad[index], t64);
                        if (cmp == 0) {
                                /*
-                                *      search hit
+                                *      search hit
                                 */
                                /* search hit - leaf page:
                                 * return the entry found
@@ -692,7 +692,7 @@ static int xtSearch(struct inode *ip, s64 xoff,     s64 *nextp,
                }
 
                /*
-                *      search miss
+                *      search miss
                 *
                 * base is the smallest index with key (Kj) greater than
                 * search key (K) and may be zero or maxentry index.
@@ -773,22 +773,22 @@ static int xtSearch(struct inode *ip, s64 xoff,   s64 *nextp,
 }
 
 /*
- *      xtInsert()
+ *     xtInsert()
  *
  * function:
  *
  * parameter:
- *      tid     - transaction id;
- *      ip      - file object;
- *      xflag   - extent flag (XAD_NOTRECORDED):
- *      xoff    - extent offset;
- *      xlen    - extent length;
- *      xaddrp  - extent address pointer (in/out):
- *              if (*xaddrp)
- *                      caller allocated data extent at *xaddrp;
- *              else
- *                      allocate data extent and return its xaddr;
- *      flag    -
+ *     tid     - transaction id;
+ *     ip      - file object;
+ *     xflag   - extent flag (XAD_NOTRECORDED):
+ *     xoff    - extent offset;
+ *     xlen    - extent length;
+ *     xaddrp  - extent address pointer (in/out):
+ *             if (*xaddrp)
+ *                     caller allocated data extent at *xaddrp;
+ *             else
+ *                     allocate data extent and return its xaddr;
+ *     flag    -
  *
  * return:
  */
@@ -813,7 +813,7 @@ int xtInsert(tid_t tid,             /* transaction id */
        jfs_info("xtInsert: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
 
        /*
-        *      search for the entry location at which to insert:
+        *      search for the entry location at which to insert:
         *
         * xtFastSearch() and xtSearch() both returns (leaf page
         * pinned, index at which to insert).
@@ -853,13 +853,13 @@ int xtInsert(tid_t tid,           /* transaction id */
        }
 
        /*
-        *      insert entry for new extent
+        *      insert entry for new extent
         */
        xflag |= XAD_NEW;
 
        /*
-        *      if the leaf page is full, split the page and
-        *      propagate up the router entry for the new page from split
+        *      if the leaf page is full, split the page and
+        *      propagate up the router entry for the new page from split
         *
         * The xtSplitUp() will insert the entry and unpin the leaf page.
         */
@@ -886,7 +886,7 @@ int xtInsert(tid_t tid,             /* transaction id */
        }
 
        /*
-        *      insert the new entry into the leaf page
+        *      insert the new entry into the leaf page
         */
        /*
         * acquire a transaction lock on the leaf page;
@@ -930,16 +930,16 @@ int xtInsert(tid_t tid,           /* transaction id */
 
 
 /*
- *      xtSplitUp()
+ *     xtSplitUp()
  *
  * function:
- *      split full pages as propagating insertion up the tree
+ *     split full pages as propagating insertion up the tree
  *
  * parameter:
- *      tid     - transaction id;
- *      ip      - file object;
- *      split   - entry parameter descriptor;
- *      btstack - traverse stack from xtSearch()
+ *     tid     - transaction id;
+ *     ip      - file object;
+ *     split   - entry parameter descriptor;
+ *     btstack - traverse stack from xtSearch()
  *
  * return:
  */
@@ -1199,22 +1199,22 @@ xtSplitUp(tid_t tid,
 
 
 /*
- *      xtSplitPage()
+ *     xtSplitPage()
  *
  * function:
- *      split a full non-root page into
- *      original/split/left page and new right page
- *      i.e., the original/split page remains as left page.
+ *     split a full non-root page into
+ *     original/split/left page and new right page
+ *     i.e., the original/split page remains as left page.
  *
  * parameter:
- *      int            tid,
- *      struct inode    *ip,
- *      struct xtsplit  *split,
- *      struct metapage        **rmpp,
- *      u64            *rbnp,
+ *     int             tid,
+ *     struct inode    *ip,
+ *     struct xtsplit  *split,
+ *     struct metapage **rmpp,
+ *     u64             *rbnp,
  *
  * return:
- *      Pointer to page in which to insert or NULL on error.
+ *     Pointer to page in which to insert or NULL on error.
  */
 static int
 xtSplitPage(tid_t tid, struct inode *ip,
@@ -1248,9 +1248,9 @@ xtSplitPage(tid_t tid, struct inode *ip,
        rbn = addressPXD(pxd);
 
        /* Allocate blocks to quota. */
-       if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
-              rc = -EDQUOT;
-              goto clean_up;
+       if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
+               rc = -EDQUOT;
+               goto clean_up;
        }
 
        quota_allocation += lengthPXD(pxd);
@@ -1304,7 +1304,7 @@ xtSplitPage(tid_t tid, struct inode *ip,
        skip = split->index;
 
        /*
-        *      sequential append at tail (after last entry of last page)
+        *      sequential append at tail (after last entry of last page)
         *
         * if splitting the last page on a level because of appending
         * a entry to it (skip is maxentry), it's likely that the access is
@@ -1342,7 +1342,7 @@ xtSplitPage(tid_t tid, struct inode *ip,
        }
 
        /*
-        *      non-sequential insert (at possibly middle page)
+        *      non-sequential insert (at possibly middle page)
         */
 
        /*
@@ -1465,25 +1465,24 @@ xtSplitPage(tid_t tid, struct inode *ip,
 
 
 /*
- *      xtSplitRoot()
+ *     xtSplitRoot()
  *
  * function:
- *      split the full root page into
- *      original/root/split page and new right page
- *      i.e., root remains fixed in tree anchor (inode) and
- *      the root is copied to a single new right child page
- *      since root page << non-root page, and
- *      the split root page contains a single entry for the
- *      new right child page.
+ *     split the full root page into original/root/split page and new
+ *     right page
+ *     i.e., root remains fixed in tree anchor (inode) and the root is
+ *     copied to a single new right child page since root page <<
+ *     non-root page, and the split root page contains a single entry
+ *     for the new right child page.
  *
  * parameter:
- *      int            tid,
- *      struct inode    *ip,
- *      struct xtsplit  *split,
- *      struct metapage        **rmpp)
+ *     int             tid,
+ *     struct inode    *ip,
+ *     struct xtsplit  *split,
+ *     struct metapage **rmpp)
  *
  * return:
- *      Pointer to page in which to insert or NULL on error.
+ *     Pointer to page in which to insert or NULL on error.
  */
 static int
 xtSplitRoot(tid_t tid,
@@ -1505,7 +1504,7 @@ xtSplitRoot(tid_t tid,
        INCREMENT(xtStat.split);
 
        /*
-        *      allocate a single (right) child page
+        *      allocate a single (right) child page
         */
        pxdlist = split->pxdlist;
        pxd = &pxdlist->pxd[pxdlist->npxd];
@@ -1573,7 +1572,7 @@ xtSplitRoot(tid_t tid,
        }
 
        /*
-        *      reset the root
+        *      reset the root
         *
         * init root with the single entry for the new right page
         * set the 1st entry offset to 0, which force the left-most key
@@ -1610,7 +1609,7 @@ xtSplitRoot(tid_t tid,
 
 
 /*
- *      xtExtend()
+ *     xtExtend()
  *
  * function: extend in-place;
  *
@@ -1677,7 +1676,7 @@ int xtExtend(tid_t tid,           /* transaction id */
                goto extendOld;
 
        /*
-        *      extent overflow: insert entry for new extent
+        *      extent overflow: insert entry for new extent
         */
 //insertNew:
        xoff = offsetXAD(xad) + MAXXLEN;
@@ -1685,8 +1684,8 @@ int xtExtend(tid_t tid,           /* transaction id */
        nextindex = le16_to_cpu(p->header.nextindex);
 
        /*
-        *      if the leaf page is full, insert the new entry and
-        *      propagate up the router entry for the new page from split
+        *      if the leaf page is full, insert the new entry and
+        *      propagate up the router entry for the new page from split
         *
         * The xtSplitUp() will insert the entry and unpin the leaf page.
         */
@@ -1731,7 +1730,7 @@ int xtExtend(tid_t tid,           /* transaction id */
                }
        }
        /*
-        *      insert the new entry into the leaf page
+        *      insert the new entry into the leaf page
         */
        else {
                /* insert the new entry: mark the entry NEW */
@@ -1771,11 +1770,11 @@ int xtExtend(tid_t tid,         /* transaction id */
 
 #ifdef _NOTYET
 /*
- *      xtTailgate()
+ *     xtTailgate()
  *
  * function: split existing 'tail' extent
- *      (split offset >= start offset of tail extent), and
- *      relocate and extend the split tail half;
+ *     (split offset >= start offset of tail extent), and
+ *     relocate and extend the split tail half;
  *
  * note: existing extent may or may not have been committed.
  * caller is responsible for pager buffer cache update, and
@@ -1804,7 +1803,7 @@ int xtTailgate(tid_t tid,         /* transaction id */
 
 /*
 printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
-        (ulong)xoff, xlen, (ulong)xaddr);
+       (ulong)xoff, xlen, (ulong)xaddr);
 */
 
        /* there must exist extent to be tailgated */
@@ -1842,18 +1841,18 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
        xad = &p->xad[index];
 /*
 printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
-        (ulong)offsetXAD(xad), lengthXAD(xad), (ulong)addressXAD(xad));
+       (ulong)offsetXAD(xad), lengthXAD(xad), (ulong)addressXAD(xad));
 */
        if ((llen = xoff - offsetXAD(xad)) == 0)
                goto updateOld;
 
        /*
-        *      partially replace extent: insert entry for new extent
+        *      partially replace extent: insert entry for new extent
         */
 //insertNew:
        /*
-        *      if the leaf page is full, insert the new entry and
-        *      propagate up the router entry for the new page from split
+        *      if the leaf page is full, insert the new entry and
+        *      propagate up the router entry for the new page from split
         *
         * The xtSplitUp() will insert the entry and unpin the leaf page.
         */
@@ -1898,7 +1897,7 @@ printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
                }
        }
        /*
-        *      insert the new entry into the leaf page
+        *      insert the new entry into the leaf page
         */
        else {
                /* insert the new entry: mark the entry NEW */
@@ -1955,17 +1954,17 @@ printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
 #endif /* _NOTYET */
 
 /*
- *      xtUpdate()
+ *     xtUpdate()
  *
  * function: update XAD;
  *
- *      update extent for allocated_but_not_recorded or
- *      compressed extent;
+ *     update extent for allocated_but_not_recorded or
+ *     compressed extent;
  *
  * parameter:
- *      nxad    - new XAD;
- *                logical extent of the specified XAD must be completely
- *                contained by an existing XAD;
+ *     nxad    - new XAD;
+ *             logical extent of the specified XAD must be completely
+ *             contained by an existing XAD;
  */
 int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 {                              /* new XAD */
@@ -2416,19 +2415,19 @@ printf("xtUpdate.updateLeft.split p:0x%p\n", p);
 
 
 /*
- *      xtAppend()
+ *     xtAppend()
  *
  * function: grow in append mode from contiguous region specified ;
  *
  * parameter:
- *      tid             - transaction id;
- *      ip              - file object;
- *      xflag           - extent flag:
- *      xoff            - extent offset;
- *      maxblocks       - max extent length;
- *      xlen            - extent length (in/out);
- *      xaddrp          - extent address pointer (in/out):
- *      flag            -
+ *     tid             - transaction id;
+ *     ip              - file object;
+ *     xflag           - extent flag:
+ *     xoff            - extent offset;
+ *     maxblocks       - max extent length;
+ *     xlen            - extent length (in/out);
+ *     xaddrp          - extent address pointer (in/out):
+ *     flag            -
  *
  * return:
  */
@@ -2460,7 +2459,7 @@ int xtAppend(tid_t tid,           /* transaction id */
                 (ulong) xoff, maxblocks, xlen, (ulong) xaddr);
 
        /*
-        *      search for the entry location at which to insert:
+        *      search for the entry location at which to insert:
         *
         * xtFastSearch() and xtSearch() both returns (leaf page
         * pinned, index at which to insert).
@@ -2482,13 +2481,13 @@ int xtAppend(tid_t tid,         /* transaction id */
                xlen = min(xlen, (int)(next - xoff));
 //insert:
        /*
-        *      insert entry for new extent
+        *      insert entry for new extent
         */
        xflag |= XAD_NEW;
 
        /*
-        *      if the leaf page is full, split the page and
-        *      propagate up the router entry for the new page from split
+        *      if the leaf page is full, split the page and
+        *      propagate up the router entry for the new page from split
         *
         * The xtSplitUp() will insert the entry and unpin the leaf page.
         */
@@ -2545,7 +2544,7 @@ int xtAppend(tid_t tid,           /* transaction id */
        return 0;
 
        /*
-        *      insert the new entry into the leaf page
+        *      insert the new entry into the leaf page
         */
       insertLeaf:
        /*
@@ -2589,17 +2588,17 @@ int xtAppend(tid_t tid,         /* transaction id */
 
 /* - TBD for defragmentaion/reorganization -
  *
- *      xtDelete()
+ *     xtDelete()
  *
  * function:
- *      delete the entry with the specified key.
+ *     delete the entry with the specified key.
  *
- *      N.B.: whole extent of the entry is assumed to be deleted.
+ *     N.B.: whole extent of the entry is assumed to be deleted.
  *
  * parameter:
  *
  * return:
- *       ENOENT: if the entry is not found.
+ *     ENOENT: if the entry is not found.
  *
  * exception:
  */
@@ -2665,10 +2664,10 @@ int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag)
 
 /* - TBD for defragmentaion/reorganization -
  *
- *      xtDeleteUp()
+ *     xtDeleteUp()
  *
  * function:
- *      free empty pages as propagating deletion up the tree
+ *     free empty pages as propagating deletion up the tree
  *
  * parameter:
  *
@@ -2815,15 +2814,15 @@ xtDeleteUp(tid_t tid, struct inode *ip,
 
 
 /*
- * NAME:        xtRelocate()
+ * NAME:       xtRelocate()
  *
- * FUNCTION:    relocate xtpage or data extent of regular file;
- *              This function is mainly used by defragfs utility.
+ * FUNCTION:   relocate xtpage or data extent of regular file;
+ *             This function is mainly used by defragfs utility.
  *
- * NOTE:        This routine does not have the logic to handle
- *              uncommitted allocated extent. The caller should call
- *              txCommit() to commit all the allocation before call
- *              this routine.
+ * NOTE:       This routine does not have the logic to handle
+ *             uncommitted allocated extent. The caller should call
+ *             txCommit() to commit all the allocation before call
+ *             this routine.
  */
 int
 xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */
@@ -2865,8 +2864,8 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
                 xtype, (ulong) xoff, xlen, (ulong) oxaddr, (ulong) nxaddr);
 
        /*
-        *      1. get and validate the parent xtpage/xad entry
-        *      covering the source extent to be relocated;
+        *      1. get and validate the parent xtpage/xad entry
+        *      covering the source extent to be relocated;
         */
        if (xtype == DATAEXT) {
                /* search in leaf entry */
@@ -2910,7 +2909,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
        jfs_info("xtRelocate: parent xad entry validated.");
 
        /*
-        *      2. relocate the extent
+        *      2. relocate the extent
         */
        if (xtype == DATAEXT) {
                /* if the extent is allocated-but-not-recorded
@@ -2923,7 +2922,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
                        XT_PUTPAGE(pmp);
 
                /*
-                *      cmRelocate()
+                *      cmRelocate()
                 *
                 * copy target data pages to be relocated;
                 *
@@ -2945,8 +2944,8 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
                pno = offset >> CM_L2BSIZE;
                npages = (nbytes + (CM_BSIZE - 1)) >> CM_L2BSIZE;
 /*
-                npages = ((offset + nbytes - 1) >> CM_L2BSIZE) -
-                         (offset >> CM_L2BSIZE) + 1;
+               npages = ((offset + nbytes - 1) >> CM_L2BSIZE) -
+                         (offset >> CM_L2BSIZE) + 1;
 */
                sxaddr = oxaddr;
                dxaddr = nxaddr;
@@ -2981,7 +2980,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
 
                XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
                jfs_info("xtRelocate: target data extent relocated.");
-       } else {                /* (xtype  == XTPAGE) */
+       } else {                /* (xtype == XTPAGE) */
 
                /*
                 * read in the target xtpage from the source extent;
@@ -3026,16 +3025,14 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,  /* old XAD */
                 */
                if (lmp) {
                        BT_MARK_DIRTY(lmp, ip);
-                       tlck =
-                           txLock(tid, ip, lmp, tlckXTREE | tlckRELINK);
+                       tlck = txLock(tid, ip, lmp, tlckXTREE | tlckRELINK);
                        lp->header.next = cpu_to_le64(nxaddr);
                        XT_PUTPAGE(lmp);
                }
 
                if (rmp) {
                        BT_MARK_DIRTY(rmp, ip);
-                       tlck =
-                           txLock(tid, ip, rmp, tlckXTREE | tlckRELINK);
+                       tlck = txLock(tid, ip, rmp, tlckXTREE | tlckRELINK);
                        rp->header.prev = cpu_to_le64(nxaddr);
                        XT_PUTPAGE(rmp);
                }
@@ -3062,7 +3059,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
                 * scan may be skipped by commit() and logredo();
                 */
                BT_MARK_DIRTY(mp, ip);
-               /* tlckNEW init  xtlck->lwm.offset = XTENTRYSTART; */
+               /* tlckNEW init xtlck->lwm.offset = XTENTRYSTART; */
                tlck = txLock(tid, ip, mp, tlckXTREE | tlckNEW);
                xtlck = (struct xtlock *) & tlck->lock;
 
@@ -3084,7 +3081,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
        }
 
        /*
-        *      3. acquire maplock for the source extent to be freed;
+        *      3. acquire maplock for the source extent to be freed;
         *
         * acquire a maplock saving the src relocated extent address;
         * to free of the extent at commit time;
@@ -3105,7 +3102,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
         *      is no buffer associated with this lock since the buffer
         *      has been redirected to the target location.
         */
-       else                    /* (xtype  == XTPAGE) */
+       else                    /* (xtype == XTPAGE) */
                tlck = txMaplock(tid, ip, tlckMAP | tlckRELOCATE);
 
        pxdlock = (struct pxd_lock *) & tlck->lock;
@@ -3115,7 +3112,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,    /* old XAD */
        pxdlock->index = 1;
 
        /*
-        *      4. update the parent xad entry for relocation;
+        *      4. update the parent xad entry for relocation;
         *
         * acquire tlck for the parent entry with XAD_NEW as entry
         * update which will write LOG_REDOPAGE and update bmap for
@@ -3143,22 +3140,22 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,  /* old XAD */
 
 
 /*
- *      xtSearchNode()
+ *     xtSearchNode()
  *
- * function:    search for the internal xad entry covering specified extent.
- *              This function is mainly used by defragfs utility.
+ * function:   search for the internal xad entry covering specified extent.
+ *             This function is mainly used by defragfs utility.
  *
  * parameters:
- *      ip      - file object;
- *      xad     - extent to find;
- *      cmpp    - comparison result:
- *      btstack - traverse stack;
- *      flag    - search process flag;
+ *     ip      - file object;
+ *     xad     - extent to find;
+ *     cmpp    - comparison result:
+ *     btstack - traverse stack;
+ *     flag    - search process flag;
  *
  * returns:
- *      btstack contains (bn, index) of search path traversed to the entry.
- *      *cmpp is set to result of comparison with the entry returned.
- *      the page containing the entry is pinned at exit.
+ *     btstack contains (bn, index) of search path traversed to the entry.
+ *     *cmpp is set to result of comparison with the entry returned.
+ *     the page containing the entry is pinned at exit.
  */
 static int xtSearchNode(struct inode *ip, xad_t * xad, /* required XAD entry */
                        int *cmpp, struct btstack * btstack, int flag)
@@ -3181,7 +3178,7 @@ static int xtSearchNode(struct inode *ip, xad_t * xad,    /* required XAD entry */
        xaddr = addressXAD(xad);
 
        /*
-        *      search down tree from root:
+        *      search down tree from root:
         *
         * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
         * internal page, child page Pi contains entry with k, Ki <= K < Kj.
@@ -3217,7 +3214,7 @@ static int xtSearchNode(struct inode *ip, xad_t * xad,    /* required XAD entry */
                        XT_CMP(cmp, xoff, &p->xad[index], t64);
                        if (cmp == 0) {
                                /*
-                                *      search hit
+                                *      search hit
                                 *
                                 * verify for exact match;
                                 */
@@ -3245,7 +3242,7 @@ static int xtSearchNode(struct inode *ip, xad_t * xad,    /* required XAD entry */
                }
 
                /*
-                *      search miss - non-leaf page:
+                *      search miss - non-leaf page:
                 *
                 * base is the smallest index with key (Kj) greater than
                 * search key (K) and may be zero or maxentry index.
@@ -3268,15 +3265,15 @@ static int xtSearchNode(struct inode *ip, xad_t * xad,  /* required XAD entry */
 
 
 /*
- *      xtRelink()
+ *     xtRelink()
  *
  * function:
- *      link around a freed page.
+ *     link around a freed page.
  *
  * Parameter:
- *      int           tid,
- *      struct inode    *ip,
- *      xtpage_t        *p)
+ *     int             tid,
+ *     struct inode    *ip,
+ *     xtpage_t        *p)
  *
  * returns:
  */
@@ -3338,7 +3335,7 @@ static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * p)
 
 
 /*
- *      xtInitRoot()
+ *     xtInitRoot()
  *
  * initialize file root (inline in inode)
  */
@@ -3385,42 +3382,42 @@ void xtInitRoot(tid_t tid, struct inode *ip)
 #define MAX_TRUNCATE_LEAVES 50
 
 /*
- *      xtTruncate()
+ *     xtTruncate()
  *
  * function:
- *      traverse for truncation logging backward bottom up;
- *      terminate at the last extent entry at the current subtree
- *      root page covering new down size.
- *      truncation may occur within the last extent entry.
+ *     traverse for truncation logging backward bottom up;
+ *     terminate at the last extent entry at the current subtree
+ *     root page covering new down size.
+ *     truncation may occur within the last extent entry.
  *
  * parameter:
- *      int           tid,
- *      struct inode    *ip,
- *      s64           newsize,
- *      int           type)   {PWMAP, PMAP, WMAP; DELETE, TRUNCATE}
+ *     int             tid,
+ *     struct inode    *ip,
+ *     s64             newsize,
+ *     int             type)   {PWMAP, PMAP, WMAP; DELETE, TRUNCATE}
  *
  * return:
  *
  * note:
- *      PWMAP:
- *       1. truncate (non-COMMIT_NOLINK file)
- *          by jfs_truncate() or jfs_open(O_TRUNC):
- *          xtree is updated;
+ *     PWMAP:
+ *      1. truncate (non-COMMIT_NOLINK file)
+ *         by jfs_truncate() or jfs_open(O_TRUNC):
+ *         xtree is updated;
  *      2. truncate index table of directory when last entry removed
- *       map update via tlock at commit time;
- *      PMAP:
+ *     map update via tlock at commit time;
+ *     PMAP:
  *      Call xtTruncate_pmap instead
- *      WMAP:
- *       1. remove (free zero link count) on last reference release
- *          (pmap has been freed at commit zero link count);
- *       2. truncate (COMMIT_NOLINK file, i.e., tmp file):
- *          xtree is updated;
- *       map update directly at truncation time;
+ *     WMAP:
+ *      1. remove (free zero link count) on last reference release
+ *         (pmap has been freed at commit zero link count);
+ *      2. truncate (COMMIT_NOLINK file, i.e., tmp file):
+ *         xtree is updated;
+ *      map update directly at truncation time;
  *
- *      if (DELETE)
- *              no LOG_NOREDOPAGE is required (NOREDOFILE is sufficient);
- *      else if (TRUNCATE)
- *              must write LOG_NOREDOPAGE for deleted index page;
+ *     if (DELETE)
+ *             no LOG_NOREDOPAGE is required (NOREDOFILE is sufficient);
+ *     else if (TRUNCATE)
+ *             must write LOG_NOREDOPAGE for deleted index page;
  *
  * pages may already have been tlocked by anonymous transactions
  * during file growth (i.e., write) before truncation;
@@ -3493,7 +3490,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
         * retained in the new sized file.
         * if type is PMAP, the data and index pages are NOT
         * freed, and the data and index blocks are NOT freed
-        * from  working map.
+        * from working map.
         * (this will allow continued access of data/index of
         * temporary file (zerolink count file truncated to zero-length)).
         */
@@ -3542,7 +3539,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
                goto getChild;
 
        /*
-        *      leaf page
+        *      leaf page
         */
        freed = 0;
 
@@ -3916,7 +3913,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
        }
 
        /*
-        *      internal page: go down to child page of current entry
+        *      internal page: go down to child page of current entry
         */
       getChild:
        /* save current parent entry for the child page */
@@ -3965,7 +3962,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
 
 
 /*
- *      xtTruncate_pmap()
+ *     xtTruncate_pmap()
  *
  * function:
  *     Perform truncate to zero lenghth for deleted file, leaving the
@@ -3974,9 +3971,9 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
  *     is committed to disk.
  *
  * parameter:
- *      tid_t          tid,
- *      struct inode   *ip,
- *      s64            committed_size)
+ *     tid_t           tid,
+ *     struct inode    *ip,
+ *     s64             committed_size)
  *
  * return: new committed size
  *
@@ -4050,7 +4047,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
        }
 
        /*
-        *      leaf page
+        *      leaf page
         */
 
        if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
@@ -4062,7 +4059,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
                xoff = offsetXAD(xad);
                xlen = lengthXAD(xad);
                XT_PUTPAGE(mp);
-               return  (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
+               return (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
        }
        tlck = txLock(tid, ip, mp, tlckXTREE);
        tlck->type = tlckXTREE | tlckFREE;
@@ -4099,8 +4096,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
                 */
                tlck = txLock(tid, ip, mp, tlckXTREE);
                xtlck = (struct xtlock *) & tlck->lock;
-               xtlck->hwm.offset =
-                   le16_to_cpu(p->header.nextindex) - 1;
+               xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
                tlck->type = tlckXTREE | tlckFREE;
 
                XT_PUTPAGE(mp);
@@ -4118,7 +4114,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
        else
                index--;
        /*
-        *      internal page: go down to child page of current entry
+        *      internal page: go down to child page of current entry
         */
       getChild:
        /* save current parent entry for the child page */
index 164f6f2b10191055bdb10522e9d1ff17603f3df5..70815c8a3d6a9114c481e6276b5fe8d35aacbfb2 100644 (file)
 #define _H_JFS_XTREE
 
 /*
- *      jfs_xtree.h: extent allocation descriptor B+-tree manager
+ *     jfs_xtree.h: extent allocation descriptor B+-tree manager
  */
 
 #include "jfs_btree.h"
 
 
 /*
- *      extent allocation descriptor (xad)
+ *     extent allocation descriptor (xad)
  */
 typedef struct xad {
        unsigned flag:8;        /* 1: flag */
@@ -38,30 +38,30 @@ typedef struct xad {
        __le32 addr2;           /* 4: address in unit of fsblksize */
 } xad_t;                       /* (16) */
 
-#define MAXXLEN         ((1 << 24) - 1)
+#define MAXXLEN                ((1 << 24) - 1)
 
-#define XTSLOTSIZE      16
-#define L2XTSLOTSIZE    4
+#define XTSLOTSIZE     16
+#define L2XTSLOTSIZE   4
 
 /* xad_t field construction */
 #define XADoffset(xad, offset64)\
 {\
-        (xad)->off1 = ((u64)offset64) >> 32;\
-        (xad)->off2 = __cpu_to_le32((offset64) & 0xffffffff);\
+       (xad)->off1 = ((u64)offset64) >> 32;\
+       (xad)->off2 = __cpu_to_le32((offset64) & 0xffffffff);\
 }
 #define XADaddress(xad, address64)\
 {\
-        (xad)->addr1 = ((u64)address64) >> 32;\
-        (xad)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+       (xad)->addr1 = ((u64)address64) >> 32;\
+       (xad)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
 }
-#define XADlength(xad, length32)        (xad)->len = __cpu_to_le24(length32)
+#define XADlength(xad, length32)       (xad)->len = __cpu_to_le24(length32)
 
 /* xad_t field extraction */
 #define offsetXAD(xad)\
-        ( ((s64)((xad)->off1)) << 32 | __le32_to_cpu((xad)->off2))
+       ( ((s64)((xad)->off1)) << 32 | __le32_to_cpu((xad)->off2))
 #define addressXAD(xad)\
-        ( ((s64)((xad)->addr1)) << 32 | __le32_to_cpu((xad)->addr2))
-#define lengthXAD(xad)  __le24_to_cpu((xad)->len)
+       ( ((s64)((xad)->addr1)) << 32 | __le32_to_cpu((xad)->addr2))
+#define lengthXAD(xad) __le24_to_cpu((xad)->len)
 
 /* xad list */
 struct xadlist {
@@ -71,22 +71,22 @@ struct xadlist {
 };
 
 /* xad_t flags */
-#define XAD_NEW         0x01   /* new */
-#define XAD_EXTENDED    0x02   /* extended */
-#define XAD_COMPRESSED  0x04   /* compressed with recorded length */
+#define XAD_NEW                0x01    /* new */
+#define XAD_EXTENDED   0x02    /* extended */
+#define XAD_COMPRESSED 0x04    /* compressed with recorded length */
 #define XAD_NOTRECORDED 0x08   /* allocated but not recorded */
-#define XAD_COW         0x10   /* copy-on-write */
+#define XAD_COW                0x10    /* copy-on-write */
 
 
 /* possible values for maxentry */
-#define XTROOTINITSLOT_DIR  6
-#define XTROOTINITSLOT  10
-#define XTROOTMAXSLOT   18
-#define XTPAGEMAXSLOT   256
-#define XTENTRYSTART    2
+#define XTROOTINITSLOT_DIR 6
+#define XTROOTINITSLOT 10
+#define XTROOTMAXSLOT  18
+#define XTPAGEMAXSLOT  256
+#define XTENTRYSTART   2
 
 /*
- *      xtree page:
+ *     xtree page:
  */
 typedef union {
        struct xtheader {
@@ -106,7 +106,7 @@ typedef union {
 } xtpage_t;
 
 /*
- *      external declaration
+ *     external declaration
  */
 extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
                    int *pflag, s64 * paddr, int *plen, int flag);
index 41c20477126237384bcf4421a0a6ae42765adbe7..25161c4121e4ba4f677bd1ed73abc8dcbc003d3d 100644 (file)
@@ -328,7 +328,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
  *             dentry  - child directory dentry
  *
  * RETURN:     -EINVAL - if name is . or ..
- *             -EINVAL  - if . or .. exist but are invalid.
+ *             -EINVAL - if . or .. exist but are invalid.
  *             errors from subroutines
  *
  * note:
@@ -517,7 +517,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
        inode_dec_link_count(ip);
 
        /*
-        *      commit zero link count object
+        *      commit zero link count object
         */
        if (ip->i_nlink == 0) {
                assert(!test_cflag(COMMIT_Nolink, ip));
@@ -596,7 +596,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
 /*
  * NAME:       commitZeroLink()
  *
- * FUNCTION:    for non-directory, called by jfs_remove(),
+ * FUNCTION:   for non-directory, called by jfs_remove(),
  *             truncate a regular file, directory or symbolic
  *             link to zero length. return 0 if type is not
  *             one of these.
@@ -676,7 +676,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip)
 /*
  * NAME:       jfs_free_zero_link()
  *
- * FUNCTION:    for non-directory, called by iClose(),
+ * FUNCTION:   for non-directory, called by iClose(),
  *             free resources of a file from cache and WORKING map
  *             for a file previously committed with zero link count
  *             while associated with a pager object,
@@ -855,12 +855,12 @@ static int jfs_link(struct dentry *old_dentry,
  * NAME:       jfs_symlink(dip, dentry, name)
  *
  * FUNCTION:   creates a symbolic link to <symlink> by name <name>
- *                     in directory <dip>
+ *                     in directory <dip>
  *
- * PARAMETER:  dip         - parent directory vnode
- *                     dentry  - dentry of symbolic link
- *                     name    - the path name of the existing object
- *                                   that will be the source of the link
+ * PARAMETER:  dip     - parent directory vnode
+ *             dentry  - dentry of symbolic link
+ *             name    - the path name of the existing object
+ *                       that will be the source of the link
  *
  * RETURN:     errors from subroutines
  *
@@ -1052,9 +1052,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
 
 
 /*
- * NAME:        jfs_rename
+ * NAME:       jfs_rename
  *
- * FUNCTION:    rename a file or directory
+ * FUNCTION:   rename a file or directory
  */
 static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry)
@@ -1331,9 +1331,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 
 /*
- * NAME:        jfs_mknod
+ * NAME:       jfs_mknod
  *
- * FUNCTION:    Create a special file (device)
+ * FUNCTION:   Create a special file (device)
  */
 static int jfs_mknod(struct inode *dir, struct dentry *dentry,
                int mode, dev_t rdev)
index 79d625f3f7336f555acb604ca30966819b97e5d0..71984ee95346cd214cdab467e71a646cc496b279 100644 (file)
 #include "jfs_txnmgr.h"
 #include "jfs_debug.h"
 
-#define BITSPERPAGE     (PSIZE << 3)
-#define L2MEGABYTE      20
-#define MEGABYTE        (1 << L2MEGABYTE)
-#define MEGABYTE32     (MEGABYTE << 5)
+#define BITSPERPAGE    (PSIZE << 3)
+#define L2MEGABYTE     20
+#define MEGABYTE       (1 << L2MEGABYTE)
+#define MEGABYTE32     (MEGABYTE << 5)
 
 /* convert block number to bmap file page number */
 #define BLKTODMAPN(b)\
-        (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
+       (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
 
 /*
- *      jfs_extendfs()
+ *     jfs_extendfs()
  *
  * function: extend file system;
  *
@@ -48,9 +48,9 @@
  *                                   workspace  space
  *
  * input:
- *      new LVSize: in LV blocks (required)
- *      new LogSize: in LV blocks (optional)
- *      new FSSize: in LV blocks (optional)
+ *     new LVSize: in LV blocks (required)
+ *     new LogSize: in LV blocks (optional)
+ *     new FSSize: in LV blocks (optional)
  *
  * new configuration:
  * 1. set new LogSize as specified or default from new LVSize;
@@ -125,8 +125,8 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        }
 
        /*
-        *      reconfigure LV spaces
-        *      ---------------------
+        *      reconfigure LV spaces
+        *      ---------------------
         *
         * validate new size, or, if not specified, determine new size
         */
@@ -198,7 +198,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
                log_formatted = 1;
        }
        /*
-        *      quiesce file system
+        *      quiesce file system
         *
         * (prepare to move the inline log and to prevent map update)
         *
@@ -270,8 +270,8 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        }
 
        /*
-        *      extend block allocation map
-        *      ---------------------------
+        *      extend block allocation map
+        *      ---------------------------
         *
         * extendfs() for new extension, retry after crash recovery;
         *
@@ -283,7 +283,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
         *  s_size: aggregate size in physical blocks;
         */
        /*
-        *      compute the new block allocation map configuration
+        *      compute the new block allocation map configuration
         *
         * map dinode:
         *  di_size: map file size in byte;
@@ -301,7 +301,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        newNpages = BLKTODMAPN(t64) + 1;
 
        /*
-        *      extend map from current map (WITHOUT growing mapfile)
+        *      extend map from current map (WITHOUT growing mapfile)
         *
         * map new extension with unmapped part of the last partial
         * dmap page, if applicable, and extra page(s) allocated
@@ -341,8 +341,8 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        XSize -= nblocks;
 
        /*
-        *      grow map file to cover remaining extension
-        *      and/or one extra dmap page for next extendfs();
+        *      grow map file to cover remaining extension
+        *      and/or one extra dmap page for next extendfs();
         *
         * allocate new map pages and its backing blocks, and
         * update map file xtree
@@ -422,8 +422,8 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        dbFinalizeBmap(ipbmap);
 
        /*
-        *      update inode allocation map
-        *      ---------------------------
+        *      update inode allocation map
+        *      ---------------------------
         *
         * move iag lists from old to new iag;
         * agstart field is not updated for logredo() to reconstruct
@@ -442,8 +442,8 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        }
 
        /*
-        *      finalize
-        *      --------
+        *      finalize
+        *      --------
         *
         * extension is committed when on-disk super block is
         * updated with new descriptors: logredo will recover
@@ -480,7 +480,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        diFreeSpecial(ipbmap2);
 
        /*
-        *      update superblock
+        *      update superblock
         */
        if ((rc = readSuper(sb, &bh)))
                goto error_out;
@@ -530,7 +530,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
 
       resume:
        /*
-        *      resume file system transactions
+        *      resume file system transactions
         */
        txResume(sb);
 
index b753ba2164508a997763ae09d60d3e59a1725ce3..b2375f0774b72c89cb602358735a0fed289206f7 100644 (file)
@@ -63,9 +63,9 @@
  *
  *   On-disk:
  *
- *     FEALISTs are stored on disk using blocks allocated by dbAlloc() and
- *     written directly. An EA list may be in-lined in the inode if there is
- *     sufficient room available.
+ *     FEALISTs are stored on disk using blocks allocated by dbAlloc() and
+ *     written directly. An EA list may be in-lined in the inode if there is
+ *     sufficient room available.
  */
 
 struct ea_buffer {
@@ -590,7 +590,8 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
       size_check:
        if (EALIST_SIZE(ea_buf->xattr) != ea_size) {
                printk(KERN_ERR "ea_get: invalid extended attribute\n");
-               dump_mem("xattr", ea_buf->xattr, ea_size);
+               print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1,
+                                    ea_buf->xattr, ea_size, 1);
                ea_release(inode, ea_buf);
                rc = -EIO;
                goto clean_up;
index f92baa1d757053cd7f1b3964bf73cafcd74f7047..17765f697e50f68f7a29906b8f4aef36709abb29 100644 (file)
@@ -23,7 +23,7 @@ const struct file_operations minix_file_operations = {
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
        .fsync          = minix_sync_file,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 const struct inode_operations minix_file_inode_operations = {
index 9eb8eb4e4a08df9db62c8301d8c4622df45bf10c..8689b736fdd98cfa8b648f92e9922c52499a6fb3 100644 (file)
@@ -41,7 +41,9 @@ static int nfs_file_open(struct inode *, struct file *);
 static int nfs_file_release(struct inode *, struct file *);
 static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
 static int  nfs_file_mmap(struct file *, struct vm_area_struct *);
-static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
+static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos,
+                                       struct pipe_inode_info *pipe,
+                                       size_t count, unsigned int flags);
 static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
 static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
@@ -65,7 +67,7 @@ const struct file_operations nfs_file_operations = {
        .fsync          = nfs_fsync,
        .lock           = nfs_lock,
        .flock          = nfs_flock,
-       .sendfile       = nfs_file_sendfile,
+       .splice_read    = nfs_file_splice_read,
        .check_flags    = nfs_check_flags,
 };
 
@@ -224,20 +226,21 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
 }
 
 static ssize_t
-nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
-               read_actor_t actor, void *target)
+nfs_file_splice_read(struct file *filp, loff_t *ppos,
+                    struct pipe_inode_info *pipe, size_t count,
+                    unsigned int flags)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        ssize_t res;
 
-       dfprintk(VFS, "nfs: sendfile(%s/%s, %lu@%Lu)\n",
+       dfprintk(VFS, "nfs: splice_read(%s/%s, %lu@%Lu)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
                (unsigned long) count, (unsigned long long) *ppos);
 
        res = nfs_revalidate_mapping(inode, filp->f_mapping);
        if (!res)
-               res = generic_file_sendfile(filp, ppos, count, actor, target);
+               res = generic_file_splice_read(filp, ppos, pipe, count, flags);
        return res;
 }
 
index 7e6aa245b5d5f30b270c5336267eb77760be41ac..8604e35bd48e2d5966a244f1763f62def303dc0a 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/major.h>
-#include <linux/ext2_fs.h>
+#include <linux/splice.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -801,26 +801,32 @@ found:
 }
 
 /*
- * Grab and keep cached pages assosiated with a file in the svc_rqst
- * so that they can be passed to the netowork sendmsg/sendpage routines
- * directrly. They will be released after the sending has completed.
+ * Grab and keep cached pages associated with a file in the svc_rqst
+ * so that they can be passed to the network sendmsg/sendpage routines
+ * directly. They will be released after the sending has completed.
  */
 static int
-nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset , unsigned long size)
+nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+                 struct splice_desc *sd)
 {
-       unsigned long count = desc->count;
-       struct svc_rqst *rqstp = desc->arg.data;
+       struct svc_rqst *rqstp = sd->u.data;
        struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
+       struct page *page = buf->page;
+       size_t size;
+       int ret;
+
+       ret = buf->ops->confirm(pipe, buf);
+       if (unlikely(ret))
+               return ret;
 
-       if (size > count)
-               size = count;
+       size = sd->len;
 
        if (rqstp->rq_res.page_len == 0) {
                get_page(page);
                put_page(*pp);
                *pp = page;
                rqstp->rq_resused++;
-               rqstp->rq_res.page_base = offset;
+               rqstp->rq_res.page_base = buf->offset;
                rqstp->rq_res.page_len = size;
        } else if (page != pp[-1]) {
                get_page(page);
@@ -832,11 +838,15 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
        } else
                rqstp->rq_res.page_len += size;
 
-       desc->count = count - size;
-       desc->written += size;
        return size;
 }
 
+static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
+                                   struct splice_desc *sd)
+{
+       return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
+}
+
 static __be32
 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
               loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
@@ -861,10 +871,15 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        if (ra && ra->p_set)
                file->f_ra = ra->p_ra;
 
-       if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
-               rqstp->rq_resused = 1;
-               host_err = file->f_op->sendfile(file, &offset, *count,
-                                                nfsd_read_actor, rqstp);
+       if (file->f_op->splice_read && rqstp->rq_splice_ok) {
+               struct splice_desc sd = {
+                       .len            = 0,
+                       .total_len      = *count,
+                       .pos            = offset,
+                       .u.data         = rqstp,
+               };
+
+               host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
        } else {
                oldfs = get_fs();
                set_fs(KERNEL_DS);
index 7ed56390b5826798f3d67bded0781b7382fe25b3..ffcc504a1667be04daea41339c53cd16d7ca84e4 100644 (file)
@@ -2276,7 +2276,7 @@ const struct file_operations ntfs_file_ops = {
                                                    mounted filesystem. */
        .mmap           = generic_file_mmap,     /* Mmap file. */
        .open           = ntfs_file_open,        /* Open file. */
-       .sendfile       = generic_file_sendfile, /* Zero-copy data send with
+       .splice_read    = generic_file_splice_read /* Zero-copy data send with
                                                    the data source being on
                                                    the ntfs partition.  We do
                                                    not need to care about the
index ac6c96431bbcb3a7687b522465e456d68246c002..4979b667571734c151a88b2a03f01db5e2b8c761 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/pagemap.h>
 #include <linux/uio.h>
 #include <linux/sched.h>
-#include <linux/pipe_fs_i.h>
+#include <linux/splice.h>
 #include <linux/mount.h>
 #include <linux/writeback.h>
 
@@ -1583,7 +1583,7 @@ static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe,
        ssize_t copied = 0;
        struct ocfs2_splice_write_priv sp;
 
-       ret = buf->ops->pin(pipe, buf);
+       ret = buf->ops->confirm(pipe, buf);
        if (ret)
                goto out;
 
@@ -1604,7 +1604,7 @@ static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe,
                 * might enter ocfs2_buffered_write_cluster() more
                 * than once, so keep track of our progress here.
                 */
-               copied = ocfs2_buffered_write_cluster(sd->file,
+               copied = ocfs2_buffered_write_cluster(sd->u.file,
                                                      (loff_t)sd->pos + total,
                                                      count,
                                                      ocfs2_map_and_write_splice_data,
@@ -1636,9 +1636,14 @@ static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe,
        int ret, err;
        struct address_space *mapping = out->f_mapping;
        struct inode *inode = mapping->host;
-
-       ret = __splice_from_pipe(pipe, out, ppos, len, flags,
-                                ocfs2_splice_write_actor);
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+               .pos = *ppos,
+               .u.file = out,
+       };
+
+       ret = __splice_from_pipe(pipe, &sd, ocfs2_splice_write_actor);
        if (ret > 0) {
                *ppos += ret;
 
@@ -1817,7 +1822,6 @@ const struct inode_operations ocfs2_special_file_iops = {
 const struct file_operations ocfs2_fops = {
        .read           = do_sync_read,
        .write          = do_sync_write,
-       .sendfile       = generic_file_sendfile,
        .mmap           = ocfs2_mmap,
        .fsync          = ocfs2_sync_file,
        .release        = ocfs2_file_release,
index 3a89592bdf577930b4c1698c4811261aa467cbf2..d007830d9c870fabb4b887d3f81afcb8e7160642 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -164,6 +164,20 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
                page_cache_release(page);
 }
 
+/**
+ * generic_pipe_buf_map - virtually map a pipe buffer
+ * @pipe:      the pipe that the buffer belongs to
+ * @buf:       the buffer that should be mapped
+ * @atomic:    whether to use an atomic map
+ *
+ * Description:
+ *     This function returns a kernel virtual address mapping for the
+ *     passed in @pipe_buffer. If @atomic is set, an atomic map is provided
+ *     and the caller has to be careful not to fault before calling
+ *     the unmap function.
+ *
+ *     Note that this function occupies KM_USER0 if @atomic != 0.
+ */
 void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
                           struct pipe_buffer *buf, int atomic)
 {
@@ -175,6 +189,15 @@ void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
        return kmap(buf->page);
 }
 
+/**
+ * generic_pipe_buf_unmap - unmap a previously mapped pipe buffer
+ * @pipe:      the pipe that the buffer belongs to
+ * @buf:       the buffer that should be unmapped
+ * @map_data:  the data that the mapping function returned
+ *
+ * Description:
+ *     This function undoes the mapping that ->map() provided.
+ */
 void generic_pipe_buf_unmap(struct pipe_inode_info *pipe,
                            struct pipe_buffer *buf, void *map_data)
 {
@@ -185,11 +208,28 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe,
                kunmap(buf->page);
 }
 
+/**
+ * generic_pipe_buf_steal - attempt to take ownership of a @pipe_buffer
+ * @pipe:      the pipe that the buffer belongs to
+ * @buf:       the buffer to attempt to steal
+ *
+ * Description:
+ *     This function attempts to steal the @struct page attached to
+ *     @buf. If successful, this function returns 0 and returns with
+ *     the page locked. The caller may then reuse the page for whatever
+ *     he wishes, the typical use is insertion into a different file
+ *     page cache.
+ */
 int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
                           struct pipe_buffer *buf)
 {
        struct page *page = buf->page;
 
+       /*
+        * A reference of one is golden, that means that the owner of this
+        * page is the only one holding a reference to it. lock the page
+        * and return OK.
+        */
        if (page_count(page) == 1) {
                lock_page(page);
                return 0;
@@ -198,12 +238,32 @@ int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
        return 1;
 }
 
-void generic_pipe_buf_get(struct pipe_inode_info *info, struct pipe_buffer *buf)
+/**
+ * generic_pipe_buf_get - get a reference to a @struct pipe_buffer
+ * @pipe:      the pipe that the buffer belongs to
+ * @buf:       the buffer to get a reference to
+ *
+ * Description:
+ *     This function grabs an extra reference to @buf. It's used in
+ *     in the tee() system call, when we duplicate the buffers in one
+ *     pipe into another.
+ */
+void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
 {
        page_cache_get(buf->page);
 }
 
-int generic_pipe_buf_pin(struct pipe_inode_info *info, struct pipe_buffer *buf)
+/**
+ * generic_pipe_buf_confirm - verify contents of the pipe buffer
+ * @pipe:      the pipe that the buffer belongs to
+ * @buf:       the buffer to confirm
+ *
+ * Description:
+ *     This function does nothing, because the generic pipe code uses
+ *     pages that are always good when inserted into the pipe.
+ */
+int generic_pipe_buf_confirm(struct pipe_inode_info *info,
+                            struct pipe_buffer *buf)
 {
        return 0;
 }
@@ -212,7 +272,7 @@ static const struct pipe_buf_operations anon_pipe_buf_ops = {
        .can_merge = 1,
        .map = generic_pipe_buf_map,
        .unmap = generic_pipe_buf_unmap,
-       .pin = generic_pipe_buf_pin,
+       .confirm = generic_pipe_buf_confirm,
        .release = anon_pipe_buf_release,
        .steal = generic_pipe_buf_steal,
        .get = generic_pipe_buf_get,
@@ -252,7 +312,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
                        if (chars > total_len)
                                chars = total_len;
 
-                       error = ops->pin(pipe, buf);
+                       error = ops->confirm(pipe, buf);
                        if (error) {
                                if (!ret)
                                        error = ret;
@@ -373,7 +433,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov,
                        int error, atomic = 1;
                        void *addr;
 
-                       error = ops->pin(pipe, buf);
+                       error = ops->confirm(pipe, buf);
                        if (error)
                                goto out;
 
index 74f30e0c0381041d95fc3657077dd22ab3466105..98e78e2f18d66cb4331d394c8543c3e8db4445a4 100644 (file)
@@ -165,7 +165,6 @@ static inline char * task_state(struct task_struct *p, char *buffer)
        rcu_read_lock();
        buffer += sprintf(buffer,
                "State:\t%s\n"
-               "SleepAVG:\t%lu%%\n"
                "Tgid:\t%d\n"
                "Pid:\t%d\n"
                "PPid:\t%d\n"
@@ -173,7 +172,6 @@ static inline char * task_state(struct task_struct *p, char *buffer)
                "Uid:\t%d\t%d\t%d\t%d\n"
                "Gid:\t%d\t%d\t%d\t%d\n",
                get_task_state(p),
-               (p->sleep_avg/1024)*100/(1020000000/1024),
                p->tgid, p->pid,
                pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0,
                pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0,
@@ -312,6 +310,41 @@ int proc_pid_status(struct task_struct *task, char * buffer)
        return buffer - orig;
 }
 
+static clock_t task_utime(struct task_struct *p)
+{
+       clock_t utime = cputime_to_clock_t(p->utime),
+               total = utime + cputime_to_clock_t(p->stime);
+       u64 temp;
+
+       /*
+        * Use CFS's precise accounting:
+        */
+       temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);
+
+       if (total) {
+               temp *= utime;
+               do_div(temp, total);
+       }
+       utime = (clock_t)temp;
+
+       return utime;
+}
+
+static clock_t task_stime(struct task_struct *p)
+{
+       clock_t stime = cputime_to_clock_t(p->stime);
+
+       /*
+        * Use CFS's precise accounting. (we subtract utime from
+        * the total, to make sure the total observed by userspace
+        * grows monotonically - apps rely on that):
+        */
+       stime = nsec_to_clock_t(p->se.sum_exec_runtime) - task_utime(p);
+
+       return stime;
+}
+
+
 static int do_task_stat(struct task_struct *task, char * buffer, int whole)
 {
        unsigned long vsize, eip, esp, wchan = ~0UL;
@@ -326,7 +359,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
        unsigned long long start_time;
        unsigned long cmin_flt = 0, cmaj_flt = 0;
        unsigned long  min_flt = 0,  maj_flt = 0;
-       cputime_t cutime, cstime, utime, stime;
+       cputime_t cutime, cstime;
+       clock_t utime, stime;
        unsigned long rsslim = 0;
        char tcomm[sizeof(task->comm)];
        unsigned long flags;
@@ -344,7 +378,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
 
        sigemptyset(&sigign);
        sigemptyset(&sigcatch);
-       cutime = cstime = utime = stime = cputime_zero;
+       cutime = cstime = cputime_zero;
+       utime = stime = 0;
 
        rcu_read_lock();
        if (lock_task_sighand(task, &flags)) {
@@ -370,15 +405,15 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
                        do {
                                min_flt += t->min_flt;
                                maj_flt += t->maj_flt;
-                               utime = cputime_add(utime, t->utime);
-                               stime = cputime_add(stime, t->stime);
+                               utime += task_utime(t);
+                               stime += task_stime(t);
                                t = next_thread(t);
                        } while (t != task);
 
                        min_flt += sig->min_flt;
                        maj_flt += sig->maj_flt;
-                       utime = cputime_add(utime, sig->utime);
-                       stime = cputime_add(stime, sig->stime);
+                       utime += cputime_to_clock_t(sig->utime);
+                       stime += cputime_to_clock_t(sig->stime);
                }
 
                sid = signal_session(sig);
@@ -394,8 +429,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
        if (!whole) {
                min_flt = task->min_flt;
                maj_flt = task->maj_flt;
-               utime = task->utime;
-               stime = task->stime;
+               utime = task_utime(task);
+               stime = task_stime(task);
        }
 
        /* scale priority and nice values from timeslices to -20..20 */
@@ -426,8 +461,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
                cmin_flt,
                maj_flt,
                cmaj_flt,
-               cputime_to_clock_t(utime),
-               cputime_to_clock_t(stime),
+               utime,
+               stime,
                cputime_to_clock_t(cutime),
                cputime_to_clock_t(cstime),
                priority,
index a5fa1fdafc4e6df68df2cc87626f0d8d85bd95a6..46ea5d56e1bb9bd7a3cf60e163d2e9951832d50d 100644 (file)
@@ -296,7 +296,7 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
  */
 static int proc_pid_schedstat(struct task_struct *task, char *buffer)
 {
-       return sprintf(buffer, "%lu %lu %lu\n",
+       return sprintf(buffer, "%llu %llu %lu\n",
                        task->sched_info.cpu_time,
                        task->sched_info.run_delay,
                        task->sched_info.pcnt);
@@ -929,6 +929,69 @@ static const struct file_operations proc_fault_inject_operations = {
 };
 #endif
 
+#ifdef CONFIG_SCHED_DEBUG
+/*
+ * Print out various scheduling related per-task fields:
+ */
+static int sched_show(struct seq_file *m, void *v)
+{
+       struct inode *inode = m->private;
+       struct task_struct *p;
+
+       WARN_ON(!inode);
+
+       p = get_proc_task(inode);
+       if (!p)
+               return -ESRCH;
+       proc_sched_show_task(p, m);
+
+       put_task_struct(p);
+
+       return 0;
+}
+
+static ssize_t
+sched_write(struct file *file, const char __user *buf,
+           size_t count, loff_t *offset)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct task_struct *p;
+
+       WARN_ON(!inode);
+
+       p = get_proc_task(inode);
+       if (!p)
+               return -ESRCH;
+       proc_sched_set_task(p);
+
+       put_task_struct(p);
+
+       return count;
+}
+
+static int sched_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       ret = single_open(filp, sched_show, NULL);
+       if (!ret) {
+               struct seq_file *m = filp->private_data;
+
+               m->private = inode;
+       }
+       return ret;
+}
+
+static const struct file_operations proc_pid_sched_operations = {
+       .open           = sched_open,
+       .read           = seq_read,
+       .write          = sched_write,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+#endif
+
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
@@ -1963,6 +2026,9 @@ static const struct pid_entry tgid_base_stuff[] = {
        INF("environ",    S_IRUSR, pid_environ),
        INF("auxv",       S_IRUSR, pid_auxv),
        INF("status",     S_IRUGO, pid_status),
+#ifdef CONFIG_SCHED_DEBUG
+       REG("sched",      S_IRUGO|S_IWUSR, pid_sched),
+#endif
        INF("cmdline",    S_IRUGO, pid_cmdline),
        INF("stat",       S_IRUGO, tgid_stat),
        INF("statm",      S_IRUGO, pid_statm),
@@ -2247,6 +2313,9 @@ static const struct pid_entry tid_base_stuff[] = {
        INF("environ",   S_IRUSR, pid_environ),
        INF("auxv",      S_IRUSR, pid_auxv),
        INF("status",    S_IRUGO, pid_status),
+#ifdef CONFIG_SCHED_DEBUG
+       REG("sched",     S_IRUGO|S_IWUSR, pid_sched),
+#endif
        INF("cmdline",   S_IRUGO, pid_cmdline),
        INF("stat",      S_IRUGO, tid_stat),
        INF("statm",     S_IRUGO, pid_statm),
index 44649981bbc8b08b7c1830d903432bb3fb583701..867f42b02035dd6621f681a6730d90c2a3a3c4ae 100644 (file)
@@ -25,7 +25,7 @@ const struct file_operations qnx4_file_operations =
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .mmap           = generic_file_mmap,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 #ifdef CONFIG_QNX4FS_RW
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
index 2f14774a124fc05e5c995f1c9dd02926440de009..97bdc0b2f9d29b0d253048874dfaa388ae3ec830 100644 (file)
@@ -41,7 +41,7 @@ const struct file_operations ramfs_file_operations = {
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
        .fsync          = simple_sync_file,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
        .llseek         = generic_file_llseek,
 };
 
index 5d258c40a2fd9c59fead95c4d3d84d7a4092bce3..cad2b7ace63033bc4aa0e78393e07d3527f296c9 100644 (file)
@@ -42,7 +42,7 @@ const struct file_operations ramfs_file_operations = {
        .write                  = do_sync_write,
        .aio_write              = generic_file_aio_write,
        .fsync                  = simple_sync_file,
-       .sendfile               = generic_file_sendfile,
+       .splice_read            = generic_file_splice_read,
        .llseek                 = generic_file_llseek,
 };
 
index 4d03008f015b9ae6d2565cdbc179d034687c3d08..507ddff48a9a9e673d75d161d0fc8ad09c00faef 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/pagemap.h>
+#include <linux/splice.h>
 #include "read_write.h"
 
 #include <asm/uaccess.h>
@@ -25,7 +26,7 @@ const struct file_operations generic_ro_fops = {
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .mmap           = generic_file_readonly_mmap,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 EXPORT_SYMBOL(generic_ro_fops);
@@ -708,7 +709,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        struct inode * in_inode, * out_inode;
        loff_t pos;
        ssize_t retval;
-       int fput_needed_in, fput_needed_out;
+       int fput_needed_in, fput_needed_out, fl;
 
        /*
         * Get input file, and verify that it is ok..
@@ -723,7 +724,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        in_inode = in_file->f_path.dentry->d_inode;
        if (!in_inode)
                goto fput_in;
-       if (!in_file->f_op || !in_file->f_op->sendfile)
+       if (!in_file->f_op || !in_file->f_op->splice_read)
                goto fput_in;
        retval = -ESPIPE;
        if (!ppos)
@@ -776,7 +777,18 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                count = max - pos;
        }
 
-       retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
+       fl = 0;
+#if 0
+       /*
+        * We need to debate whether we can enable this or not. The
+        * man page documents EAGAIN return for the output at least,
+        * and the application is arguably buggy if it doesn't expect
+        * EAGAIN on a non-blocking file descriptor.
+        */
+       if (in_file->f_flags & O_NONBLOCK)
+               fl = SPLICE_F_NONBLOCK;
+#endif
+       retval = do_splice_direct(in_file, ppos, out_file, count, fl);
 
        if (retval > 0) {
                add_rchar(current, retval);
index 9e451a68580f6eef3ab4ba8c6eb729ae843d071b..30eebfb1b2d8d7e9cf26474329d28fd28f401665 100644 (file)
@@ -1531,7 +1531,6 @@ const struct file_operations reiserfs_file_operations = {
        .open = generic_file_open,
        .release = reiserfs_file_release,
        .fsync = reiserfs_sync_file,
-       .sendfile = generic_file_sendfile,
        .aio_read = generic_file_aio_read,
        .aio_write = generic_file_aio_write,
        .splice_read = generic_file_splice_read,
index aea3f8aa54c0911e80110937f9d26ef03694a9ee..c5d78a7e492b40b7dae9dde99b42698522485565 100644 (file)
@@ -262,8 +262,9 @@ out:
 }
 
 static ssize_t
-smb_file_sendfile(struct file *file, loff_t *ppos,
-                 size_t count, read_actor_t actor, void *target)
+smb_file_splice_read(struct file *file, loff_t *ppos,
+                    struct pipe_inode_info *pipe, size_t count,
+                    unsigned int flags)
 {
        struct dentry *dentry = file->f_path.dentry;
        ssize_t status;
@@ -277,7 +278,7 @@ smb_file_sendfile(struct file *file, loff_t *ppos,
                         DENTRY_PATH(dentry), status);
                goto out;
        }
-       status = generic_file_sendfile(file, ppos, count, actor, target);
+       status = generic_file_splice_read(file, ppos, pipe, count, flags);
 out:
        return status;
 }
@@ -416,7 +417,7 @@ const struct file_operations smb_file_operations =
        .open           = smb_file_open,
        .release        = smb_file_release,
        .fsync          = smb_fsync,
-       .sendfile       = smb_file_sendfile,
+       .splice_read    = smb_file_splice_read,
 };
 
 const struct inode_operations smb_file_inode_operations =
index e7d7080de2f9799860a475a4df50a7742561d09f..ed2ce995475c3f3cf6991de68cab9b38285ddc5d 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/pagemap.h>
-#include <linux/pipe_fs_i.h>
+#include <linux/splice.h>
 #include <linux/mm_inline.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
 #include <linux/syscalls.h>
 #include <linux/uio.h>
 
-struct partial_page {
-       unsigned int offset;
-       unsigned int len;
-};
-
-/*
- * Passed to splice_to_pipe
- */
-struct splice_pipe_desc {
-       struct page **pages;            /* page map */
-       struct partial_page *partial;   /* pages[] may not be contig */
-       int nr_pages;                   /* number of pages in map */
-       unsigned int flags;             /* splice flags */
-       const struct pipe_buf_operations *ops;/* ops associated with output pipe */
-};
-
 /*
  * Attempt to steal a page from a pipe buffer. This should perhaps go into
  * a vm helper function, it's already simplified quite a bit by the
@@ -101,8 +85,12 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
        buf->flags &= ~PIPE_BUF_FLAG_LRU;
 }
 
-static int page_cache_pipe_buf_pin(struct pipe_inode_info *pipe,
-                                  struct pipe_buffer *buf)
+/*
+ * Check whether the contents of buf is OK to access. Since the content
+ * is a page cache page, IO may be in flight.
+ */
+static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
+                                      struct pipe_buffer *buf)
 {
        struct page *page = buf->page;
        int err;
@@ -143,7 +131,7 @@ static const struct pipe_buf_operations page_cache_pipe_buf_ops = {
        .can_merge = 0,
        .map = generic_pipe_buf_map,
        .unmap = generic_pipe_buf_unmap,
-       .pin = page_cache_pipe_buf_pin,
+       .confirm = page_cache_pipe_buf_confirm,
        .release = page_cache_pipe_buf_release,
        .steal = page_cache_pipe_buf_steal,
        .get = generic_pipe_buf_get,
@@ -163,18 +151,25 @@ static const struct pipe_buf_operations user_page_pipe_buf_ops = {
        .can_merge = 0,
        .map = generic_pipe_buf_map,
        .unmap = generic_pipe_buf_unmap,
-       .pin = generic_pipe_buf_pin,
+       .confirm = generic_pipe_buf_confirm,
        .release = page_cache_pipe_buf_release,
        .steal = user_page_pipe_buf_steal,
        .get = generic_pipe_buf_get,
 };
 
-/*
- * Pipe output worker. This sets up our pipe format with the page cache
- * pipe buffer operations. Otherwise very similar to the regular pipe_writev().
+/**
+ * splice_to_pipe - fill passed data into a pipe
+ * @pipe:      pipe to fill
+ * @spd:       data to fill
+ *
+ * Description:
+ *    @spd contains a map of pages and len/offset tupples, a long with
+ *    the struct pipe_buf_operations associated with these pages. This
+ *    function will link that data to the pipe.
+ *
  */
-static ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
-                             struct splice_pipe_desc *spd)
+ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
+                      struct splice_pipe_desc *spd)
 {
        unsigned int spd_pages = spd->nr_pages;
        int ret, do_wakeup, page_nr;
@@ -201,6 +196,7 @@ static ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
                        buf->page = spd->pages[page_nr];
                        buf->offset = spd->partial[page_nr].offset;
                        buf->len = spd->partial[page_nr].len;
+                       buf->private = spd->partial[page_nr].private;
                        buf->ops = spd->ops;
                        if (spd->flags & SPLICE_F_GIFT)
                                buf->flags |= PIPE_BUF_FLAG_GIFT;
@@ -295,11 +291,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
         */
        page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
 
-       /*
-        * Now fill in the holes:
-        */
-       error = 0;
-
        /*
         * Lookup the (hopefully) full range of pages we need.
         */
@@ -307,8 +298,9 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 
        /*
         * If find_get_pages_contig() returned fewer pages than we needed,
-        * allocate the rest.
+        * allocate the rest and fill in the holes.
         */
+       error = 0;
        index += spd.nr_pages;
        while (spd.nr_pages < nr_pages) {
                /*
@@ -470,11 +462,16 @@ fill_it:
 /**
  * generic_file_splice_read - splice data from file to a pipe
  * @in:                file to splice from
+ * @ppos:      position in @in
  * @pipe:      pipe to splice to
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will read pages from given file and fill them into a pipe.
+ * Description:
+ *    Will read pages from given file and fill them into a pipe. Can be
+ *    used as long as the address_space operations for the source implements
+ *    a readpage() hook.
+ *
  */
 ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
                                 struct pipe_inode_info *pipe, size_t len,
@@ -528,11 +525,11 @@ EXPORT_SYMBOL(generic_file_splice_read);
 static int pipe_to_sendpage(struct pipe_inode_info *pipe,
                            struct pipe_buffer *buf, struct splice_desc *sd)
 {
-       struct file *file = sd->file;
+       struct file *file = sd->u.file;
        loff_t pos = sd->pos;
        int ret, more;
 
-       ret = buf->ops->pin(pipe, buf);
+       ret = buf->ops->confirm(pipe, buf);
        if (!ret) {
                more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
 
@@ -566,7 +563,7 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe,
 static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                        struct splice_desc *sd)
 {
-       struct file *file = sd->file;
+       struct file *file = sd->u.file;
        struct address_space *mapping = file->f_mapping;
        unsigned int offset, this_len;
        struct page *page;
@@ -576,7 +573,7 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
        /*
         * make sure the data in this buffer is uptodate
         */
-       ret = buf->ops->pin(pipe, buf);
+       ret = buf->ops->confirm(pipe, buf);
        if (unlikely(ret))
                return ret;
 
@@ -663,36 +660,37 @@ out_ret:
        return ret;
 }
 
-/*
- * Pipe input worker. Most of this logic works like a regular pipe, the
- * key here is the 'actor' worker passed in that actually moves the data
- * to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
+/**
+ * __splice_from_pipe - splice data from a pipe to given actor
+ * @pipe:      pipe to splice from
+ * @sd:                information to @actor
+ * @actor:     handler that splices the data
+ *
+ * Description:
+ *    This function does little more than loop over the pipe and call
+ *    @actor to do the actual moving of a single struct pipe_buffer to
+ *    the desired destination. See pipe_to_file, pipe_to_sendpage, or
+ *    pipe_to_user.
+ *
  */
-ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
-                          struct file *out, loff_t *ppos, size_t len,
-                          unsigned int flags, splice_actor *actor)
+ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
+                          splice_actor *actor)
 {
        int ret, do_wakeup, err;
-       struct splice_desc sd;
 
        ret = 0;
        do_wakeup = 0;
 
-       sd.total_len = len;
-       sd.flags = flags;
-       sd.file = out;
-       sd.pos = *ppos;
-
        for (;;) {
                if (pipe->nrbufs) {
                        struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
                        const struct pipe_buf_operations *ops = buf->ops;
 
-                       sd.len = buf->len;
-                       if (sd.len > sd.total_len)
-                               sd.len = sd.total_len;
+                       sd->len = buf->len;
+                       if (sd->len > sd->total_len)
+                               sd->len = sd->total_len;
 
-                       err = actor(pipe, buf, &sd);
+                       err = actor(pipe, buf, sd);
                        if (err <= 0) {
                                if (!ret && err != -ENODATA)
                                        ret = err;
@@ -704,10 +702,10 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
                        buf->offset += err;
                        buf->len -= err;
 
-                       sd.len -= err;
-                       sd.pos += err;
-                       sd.total_len -= err;
-                       if (sd.len)
+                       sd->len -= err;
+                       sd->pos += err;
+                       sd->total_len -= err;
+                       if (sd->len)
                                continue;
 
                        if (!buf->len) {
@@ -719,7 +717,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
                                        do_wakeup = 1;
                        }
 
-                       if (!sd.total_len)
+                       if (!sd->total_len)
                                break;
                }
 
@@ -732,7 +730,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
                                break;
                }
 
-               if (flags & SPLICE_F_NONBLOCK) {
+               if (sd->flags & SPLICE_F_NONBLOCK) {
                        if (!ret)
                                ret = -EAGAIN;
                        break;
@@ -766,12 +764,32 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
 }
 EXPORT_SYMBOL(__splice_from_pipe);
 
+/**
+ * splice_from_pipe - splice data from a pipe to a file
+ * @pipe:      pipe to splice from
+ * @out:       file to splice to
+ * @ppos:      position in @out
+ * @len:       how many bytes to splice
+ * @flags:     splice modifier flags
+ * @actor:     handler that splices the data
+ *
+ * Description:
+ *    See __splice_from_pipe. This function locks the input and output inodes,
+ *    otherwise it's identical to __splice_from_pipe().
+ *
+ */
 ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
                         loff_t *ppos, size_t len, unsigned int flags,
                         splice_actor *actor)
 {
        ssize_t ret;
        struct inode *inode = out->f_mapping->host;
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+               .pos = *ppos,
+               .u.file = out,
+       };
 
        /*
         * The actor worker might be calling ->prepare_write and
@@ -780,7 +798,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
         * pipe->inode, we have to order lock acquiry here.
         */
        inode_double_lock(inode, pipe->inode);
-       ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor);
+       ret = __splice_from_pipe(pipe, &sd, actor);
        inode_double_unlock(inode, pipe->inode);
 
        return ret;
@@ -790,12 +808,14 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
  * generic_file_splice_write_nolock - generic_file_splice_write without mutexes
  * @pipe:      pipe info
  * @out:       file to write to
+ * @ppos:      position in @out
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will either move or copy pages (determined by @flags options) from
- * the given pipe inode to the given file. The caller is responsible
- * for acquiring i_mutex on both inodes.
+ * Description:
+ *    Will either move or copy pages (determined by @flags options) from
+ *    the given pipe inode to the given file. The caller is responsible
+ *    for acquiring i_mutex on both inodes.
  *
  */
 ssize_t
@@ -804,6 +824,12 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
 {
        struct address_space *mapping = out->f_mapping;
        struct inode *inode = mapping->host;
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+               .pos = *ppos,
+               .u.file = out,
+       };
        ssize_t ret;
        int err;
 
@@ -811,7 +837,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
        if (unlikely(err))
                return err;
 
-       ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
+       ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
        if (ret > 0) {
                unsigned long nr_pages;
 
@@ -841,11 +867,13 @@ EXPORT_SYMBOL(generic_file_splice_write_nolock);
  * generic_file_splice_write - splice data from a pipe to a file
  * @pipe:      pipe info
  * @out:       file to write to
+ * @ppos:      position in @out
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will either move or copy pages (determined by @flags options) from
- * the given pipe inode to the given file.
+ * Description:
+ *    Will either move or copy pages (determined by @flags options) from
+ *    the given pipe inode to the given file.
  *
  */
 ssize_t
@@ -896,13 +924,15 @@ EXPORT_SYMBOL(generic_file_splice_write);
 
 /**
  * generic_splice_sendpage - splice data from a pipe to a socket
- * @inode:     pipe inode
+ * @pipe:      pipe to splice from
  * @out:       socket to write to
+ * @ppos:      position in @out
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will send @len bytes from the pipe to a network socket. No data copying
- * is involved.
+ * Description:
+ *    Will send @len bytes from the pipe to a network socket. No data copying
+ *    is involved.
  *
  */
 ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
@@ -956,14 +986,27 @@ static long do_splice_to(struct file *in, loff_t *ppos,
        return in->f_op->splice_read(in, ppos, pipe, len, flags);
 }
 
-long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
-                     size_t len, unsigned int flags)
+/**
+ * splice_direct_to_actor - splices data directly between two non-pipes
+ * @in:                file to splice from
+ * @sd:                actor information on where to splice to
+ * @actor:     handles the data splicing
+ *
+ * Description:
+ *    This is a special case helper to splice directly between two
+ *    points, without requiring an explicit pipe. Internally an allocated
+ *    pipe is cached in the process, and reused during the life time of
+ *    that process.
+ *
+ */
+ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+                              splice_direct_actor *actor)
 {
        struct pipe_inode_info *pipe;
        long ret, bytes;
-       loff_t out_off;
        umode_t i_mode;
-       int i;
+       size_t len;
+       int i, flags;
 
        /*
         * We require the input being a regular file, as we don't want to
@@ -999,7 +1042,13 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
         */
        ret = 0;
        bytes = 0;
-       out_off = 0;
+       len = sd->total_len;
+       flags = sd->flags;
+
+       /*
+        * Don't block on output, we have to drain the direct pipe.
+        */
+       sd->flags &= ~SPLICE_F_NONBLOCK;
 
        while (len) {
                size_t read_len, max_read_len;
@@ -1009,19 +1058,19 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
                 */
                max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE));
 
-               ret = do_splice_to(in, ppos, pipe, max_read_len, flags);
+               ret = do_splice_to(in, &sd->pos, pipe, max_read_len, flags);
                if (unlikely(ret < 0))
                        goto out_release;
 
                read_len = ret;
+               sd->total_len = read_len;
 
                /*
                 * NOTE: nonblocking mode only applies to the input. We
                 * must not do the output in nonblocking mode as then we
                 * could get stuck data in the internal pipe:
                 */
-               ret = do_splice_from(pipe, out, &out_off, read_len,
-                                    flags & ~SPLICE_F_NONBLOCK);
+               ret = actor(pipe, sd);
                if (unlikely(ret < 0))
                        goto out_release;
 
@@ -1066,6 +1115,48 @@ out_release:
                return bytes;
 
        return ret;
+
+}
+EXPORT_SYMBOL(splice_direct_to_actor);
+
+static int direct_splice_actor(struct pipe_inode_info *pipe,
+                              struct splice_desc *sd)
+{
+       struct file *file = sd->u.file;
+
+       return do_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags);
+}
+
+/**
+ * do_splice_direct - splices data directly between two files
+ * @in:                file to splice from
+ * @ppos:      input file offset
+ * @out:       file to splice to
+ * @len:       number of bytes to splice
+ * @flags:     splice modifier flags
+ *
+ * Description:
+ *    For use by do_sendfile(). splice can easily emulate sendfile, but
+ *    doing it in the application would incur an extra system call
+ *    (splice in + splice out, as compared to just sendfile()). So this helper
+ *    can splice directly through a process-private pipe.
+ *
+ */
+long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
+                     size_t len, unsigned int flags)
+{
+       struct splice_desc sd = {
+               .len            = len,
+               .total_len      = len,
+               .flags          = flags,
+               .pos            = *ppos,
+               .u.file         = out,
+       };
+       size_t ret;
+
+       ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
+       *ppos = sd.pos;
+       return ret;
 }
 
 /*
@@ -1248,28 +1339,131 @@ static int get_iovec_page_array(const struct iovec __user *iov,
        return error;
 }
 
+static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+                       struct splice_desc *sd)
+{
+       char *src;
+       int ret;
+
+       ret = buf->ops->confirm(pipe, buf);
+       if (unlikely(ret))
+               return ret;
+
+       /*
+        * See if we can use the atomic maps, by prefaulting in the
+        * pages and doing an atomic copy
+        */
+       if (!fault_in_pages_writeable(sd->u.userptr, sd->len)) {
+               src = buf->ops->map(pipe, buf, 1);
+               ret = __copy_to_user_inatomic(sd->u.userptr, src + buf->offset,
+                                                       sd->len);
+               buf->ops->unmap(pipe, buf, src);
+               if (!ret) {
+                       ret = sd->len;
+                       goto out;
+               }
+       }
+
+       /*
+        * No dice, use slow non-atomic map and copy
+        */
+       src = buf->ops->map(pipe, buf, 0);
+
+       ret = sd->len;
+       if (copy_to_user(sd->u.userptr, src + buf->offset, sd->len))
+               ret = -EFAULT;
+
+out:
+       if (ret > 0)
+               sd->u.userptr += ret;
+       buf->ops->unmap(pipe, buf, src);
+       return ret;
+}
+
+/*
+ * For lack of a better implementation, implement vmsplice() to userspace
+ * as a simple copy of the pipes pages to the user iov.
+ */
+static long vmsplice_to_user(struct file *file, const struct iovec __user *iov,
+                            unsigned long nr_segs, unsigned int flags)
+{
+       struct pipe_inode_info *pipe;
+       struct splice_desc sd;
+       ssize_t size;
+       int error;
+       long ret;
+
+       pipe = pipe_info(file->f_path.dentry->d_inode);
+       if (!pipe)
+               return -EBADF;
+
+       if (pipe->inode)
+               mutex_lock(&pipe->inode->i_mutex);
+
+       error = ret = 0;
+       while (nr_segs) {
+               void __user *base;
+               size_t len;
+
+               /*
+                * Get user address base and length for this iovec.
+                */
+               error = get_user(base, &iov->iov_base);
+               if (unlikely(error))
+                       break;
+               error = get_user(len, &iov->iov_len);
+               if (unlikely(error))
+                       break;
+
+               /*
+                * Sanity check this iovec. 0 read succeeds.
+                */
+               if (unlikely(!len))
+                       break;
+               if (unlikely(!base)) {
+                       error = -EFAULT;
+                       break;
+               }
+
+               sd.len = 0;
+               sd.total_len = len;
+               sd.flags = flags;
+               sd.u.userptr = base;
+               sd.pos = 0;
+
+               size = __splice_from_pipe(pipe, &sd, pipe_to_user);
+               if (size < 0) {
+                       if (!ret)
+                               ret = size;
+
+                       break;
+               }
+
+               ret += size;
+
+               if (size < len)
+                       break;
+
+               nr_segs--;
+               iov++;
+       }
+
+       if (pipe->inode)
+               mutex_unlock(&pipe->inode->i_mutex);
+
+       if (!ret)
+               ret = error;
+
+       return ret;
+}
+
 /*
  * vmsplice splices a user address range into a pipe. It can be thought of
  * as splice-from-memory, where the regular splice is splice-from-file (or
  * to file). In both cases the output is a pipe, naturally.
- *
- * Note that vmsplice only supports splicing _from_ user memory to a pipe,
- * not the other way around. Splicing from user memory is a simple operation
- * that can be supported without any funky alignment restrictions or nasty
- * vm tricks. We simply map in the user memory and fill them into a pipe.
- * The reverse isn't quite as easy, though. There are two possible solutions
- * for that:
- *
- *     - memcpy() the data internally, at which point we might as well just
- *       do a regular read() on the buffer anyway.
- *     - Lots of nasty vm tricks, that are neither fast nor flexible (it
- *       has restriction limitations on both ends of the pipe).
- *
- * Alas, it isn't here.
- *
  */
-static long do_vmsplice(struct file *file, const struct iovec __user *iov,
-                       unsigned long nr_segs, unsigned int flags)
+static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
+                            unsigned long nr_segs, unsigned int flags)
 {
        struct pipe_inode_info *pipe;
        struct page *pages[PIPE_BUFFERS];
@@ -1284,10 +1478,6 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov,
        pipe = pipe_info(file->f_path.dentry->d_inode);
        if (!pipe)
                return -EBADF;
-       if (unlikely(nr_segs > UIO_MAXIOV))
-               return -EINVAL;
-       else if (unlikely(!nr_segs))
-               return 0;
 
        spd.nr_pages = get_iovec_page_array(iov, nr_segs, pages, partial,
                                            flags & SPLICE_F_GIFT);
@@ -1297,6 +1487,22 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov,
        return splice_to_pipe(pipe, &spd);
 }
 
+/*
+ * Note that vmsplice only really supports true splicing _from_ user memory
+ * to a pipe, not the other way around. Splicing from user memory is a simple
+ * operation that can be supported without any funky alignment restrictions
+ * or nasty vm tricks. We simply map in the user memory and fill them into
+ * a pipe. The reverse isn't quite as easy, though. There are two possible
+ * solutions for that:
+ *
+ *     - memcpy() the data internally, at which point we might as well just
+ *       do a regular read() on the buffer anyway.
+ *     - Lots of nasty vm tricks, that are neither fast nor flexible (it
+ *       has restriction limitations on both ends of the pipe).
+ *
+ * Currently we punt and implement it as a normal copy, see pipe_to_user().
+ *
+ */
 asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov,
                             unsigned long nr_segs, unsigned int flags)
 {
@@ -1304,11 +1510,18 @@ asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov,
        long error;
        int fput;
 
+       if (unlikely(nr_segs > UIO_MAXIOV))
+               return -EINVAL;
+       else if (unlikely(!nr_segs))
+               return 0;
+
        error = -EBADF;
        file = fget_light(fd, &fput);
        if (file) {
                if (file->f_mode & FMODE_WRITE)
-                       error = do_vmsplice(file, iov, nr_segs, flags);
+                       error = vmsplice_to_pipe(file, iov, nr_segs, flags);
+               else if (file->f_mode & FMODE_READ)
+                       error = vmsplice_to_user(file, iov, nr_segs, flags);
 
                fput_light(file, fput);
        }
index 0732ddb9020beddba8e0c8caf0a71a43ed3c7eb8..589be21d884e362d17433f4e55999d73b537203a 100644 (file)
@@ -27,7 +27,7 @@ const struct file_operations sysv_file_operations = {
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
        .fsync          = sysv_sync_file,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
 
 const struct inode_operations sysv_file_inode_operations = {
index 51b5764685e777f5b3489c9c6e83aac898233559..df070bee8d4f83f3a6966c6fe2485541e217accc 100644 (file)
@@ -261,7 +261,7 @@ const struct file_operations udf_file_operations = {
        .aio_write              = udf_file_aio_write,
        .release                = udf_release_file,
        .fsync                  = udf_fsync_file,
-       .sendfile               = generic_file_sendfile,
+       .splice_read            = generic_file_splice_read,
 };
 
 const struct inode_operations udf_file_inode_operations = {
index 1e096323bad47f240bdbc30191922d46638a5612..6705d74c6d2d9b836dcdd3d3be1d40b65b3bf8e1 100644 (file)
@@ -60,5 +60,5 @@ const struct file_operations ufs_file_operations = {
        .mmap           = generic_file_mmap,
        .open           = generic_file_open,
        .fsync          = ufs_sync_file,
-       .sendfile       = generic_file_sendfile,
+       .splice_read    = generic_file_splice_read,
 };
index cb51dc9613555b6c8a37160b0d45d727359235bd..8c43cd2e237a5f15b18c743e2c13a10fd8c0f51f 100644 (file)
@@ -123,30 +123,6 @@ xfs_file_aio_write_invis(
        return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
 }
 
-STATIC ssize_t
-xfs_file_sendfile(
-       struct file             *filp,
-       loff_t                  *pos,
-       size_t                  count,
-       read_actor_t            actor,
-       void                    *target)
-{
-       return bhv_vop_sendfile(vn_from_inode(filp->f_path.dentry->d_inode),
-                               filp, pos, 0, count, actor, target, NULL);
-}
-
-STATIC ssize_t
-xfs_file_sendfile_invis(
-       struct file             *filp,
-       loff_t                  *pos,
-       size_t                  count,
-       read_actor_t            actor,
-       void                    *target)
-{
-       return bhv_vop_sendfile(vn_from_inode(filp->f_path.dentry->d_inode),
-                               filp, pos, IO_INVIS, count, actor, target, NULL);
-}
-
 STATIC ssize_t
 xfs_file_splice_read(
        struct file             *infilp,
@@ -452,7 +428,6 @@ const struct file_operations xfs_file_operations = {
        .write          = do_sync_write,
        .aio_read       = xfs_file_aio_read,
        .aio_write      = xfs_file_aio_write,
-       .sendfile       = xfs_file_sendfile,
        .splice_read    = xfs_file_splice_read,
        .splice_write   = xfs_file_splice_write,
        .unlocked_ioctl = xfs_file_ioctl,
@@ -475,7 +450,6 @@ const struct file_operations xfs_invis_file_operations = {
        .write          = do_sync_write,
        .aio_read       = xfs_file_aio_read_invis,
        .aio_write      = xfs_file_aio_write_invis,
-       .sendfile       = xfs_file_sendfile_invis,
        .splice_read    = xfs_file_splice_read_invis,
        .splice_write   = xfs_file_splice_write_invis,
        .unlocked_ioctl = xfs_file_ioctl_invis,
index 715adad7dd4dd07607edda8aae8e30bb31697899..af24a457d3a33efebe55719cb3dd1bc0e755fe5d 100644 (file)
  * Feature macros (disable/enable)
  */
 #undef  HAVE_REFCACHE  /* reference cache not needed for NFS in 2.6 */
-#define HAVE_SENDFILE  /* sendfile(2) exists in 2.6, but not in 2.4 */
 #define HAVE_SPLICE    /* a splice(2) exists in 2.6, but not in 2.4 */
 #ifdef CONFIG_SMP
 #define HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */
index ed90403f0ee71dcfaefc4ae03d84990d59155f3e..765ec16a6e392d3406d1891c6a58bfc456f1d23a 100644 (file)
@@ -286,50 +286,6 @@ xfs_read(
        return ret;
 }
 
-ssize_t
-xfs_sendfile(
-       bhv_desc_t              *bdp,
-       struct file             *filp,
-       loff_t                  *offset,
-       int                     ioflags,
-       size_t                  count,
-       read_actor_t            actor,
-       void                    *target,
-       cred_t                  *credp)
-{
-       xfs_inode_t             *ip = XFS_BHVTOI(bdp);
-       xfs_mount_t             *mp = ip->i_mount;
-       ssize_t                 ret;
-
-       XFS_STATS_INC(xs_read_calls);
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return -EIO;
-
-       xfs_ilock(ip, XFS_IOLOCK_SHARED);
-
-       if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
-           (!(ioflags & IO_INVIS))) {
-               bhv_vrwlock_t locktype = VRWLOCK_READ;
-               int error;
-
-               error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp),
-                                     *offset, count,
-                                     FILP_DELAY_FLAG(filp), &locktype);
-               if (error) {
-                       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-                       return -error;
-               }
-       }
-       xfs_rw_enter_trace(XFS_SENDFILE_ENTER, &ip->i_iocore,
-                  (void *)(unsigned long)target, count, *offset, ioflags);
-       ret = generic_file_sendfile(filp, offset, count, actor, target);
-       if (ret > 0)
-               XFS_STATS_ADD(xs_read_bytes, ret);
-
-       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-       return ret;
-}
-
 ssize_t
 xfs_splice_read(
        bhv_desc_t              *bdp,
index 7ac51b1d2161c6b9d2033dc3d3ea96d3e1ff38d7..7c60a1eed88ba6c347d5ba383147d56e077f459c 100644 (file)
@@ -90,9 +90,6 @@ extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
 extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *,
                                const struct iovec *, unsigned int,
                                loff_t *, int, struct cred *);
-extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *,
-                               loff_t *, int, size_t, read_actor_t,
-                               void *, struct cred *);
 extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, loff_t *,
                                struct pipe_inode_info *, size_t, int, int,
                                struct cred *);
index d1b2d01843d177d2f75b8bed5f0c07d3061ba519..013048a92643d1adb1001b652b07c948add850dc 100644 (file)
@@ -139,9 +139,6 @@ typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *,
 typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *,
                                const struct iovec *, unsigned int,
                                loff_t *, int, struct cred *);
-typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *,
-                               loff_t *, int, size_t, read_actor_t,
-                               void *, struct cred *);
 typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, loff_t *,
                                struct pipe_inode_info *, size_t, int, int,
                                struct cred *);
@@ -206,7 +203,6 @@ typedef struct bhv_vnodeops {
        vop_close_t             vop_close;
        vop_read_t              vop_read;
        vop_write_t             vop_write;
-       vop_sendfile_t          vop_sendfile;
        vop_splice_read_t       vop_splice_read;
        vop_splice_write_t      vop_splice_write;
        vop_ioctl_t             vop_ioctl;
@@ -254,8 +250,6 @@ typedef struct bhv_vnodeops {
                VOP(vop_read, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr)
 #define bhv_vop_write(vp,file,iov,segs,offset,ioflags,cr)              \
                VOP(vop_write, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr)
-#define bhv_vop_sendfile(vp,f,off,ioflags,cnt,act,targ,cr)             \
-               VOP(vop_sendfile, vp)(VNHEAD(vp),f,off,ioflags,cnt,act,targ,cr)
 #define bhv_vop_splice_read(vp,f,o,pipe,cnt,fl,iofl,cr)                        \
                VOP(vop_splice_read, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr)
 #define bhv_vop_splice_write(vp,f,o,pipe,cnt,fl,iofl,cr)               \
index de17aed578f04878d7942cd113103fc19ef5619f..70bc82f65311e3b2a57a7cda2fd292256f8201f6 100644 (file)
@@ -4680,9 +4680,6 @@ bhv_vnodeops_t xfs_vnodeops = {
        .vop_open               = xfs_open,
        .vop_close              = xfs_close,
        .vop_read               = xfs_read,
-#ifdef HAVE_SENDFILE
-       .vop_sendfile           = xfs_sendfile,
-#endif
 #ifdef HAVE_SPLICE
        .vop_splice_read        = xfs_splice_read,
        .vop_splice_write       = xfs_splice_write,
index 815bb01480601f7ca1a96e81113fb030df89062d..604fab7031a62e2a8ae2f0cde8022362fd89c38b 100644 (file)
@@ -6,28 +6,23 @@
 
 /*
  * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
+ * way of searching a 100-bit bitmap.  It's guaranteed that at least
+ * one of the 100 bits is cleared.
  */
 static inline int sched_find_first_bit(const unsigned long *b)
 {
 #if BITS_PER_LONG == 64
-       if (unlikely(b[0]))
+       if (b[0])
                return __ffs(b[0]);
-       if (likely(b[1]))
-               return __ffs(b[1]) + 64;
-       return __ffs(b[2]) + 128;
+       return __ffs(b[1]) + 64;
 #elif BITS_PER_LONG == 32
-       if (unlikely(b[0]))
+       if (b[0])
                return __ffs(b[0]);
-       if (unlikely(b[1]))
+       if (b[1])
                return __ffs(b[1]) + 32;
-       if (unlikely(b[2]))
+       if (b[2])
                return __ffs(b[2]) + 64;
-       if (b[3])
-               return __ffs(b[3]) + 96;
-       return __ffs(b[4]) + 128;
+       return __ffs(b[3]) + 96;
 #else
 #error BITS_PER_LONG not defined
 #endif
index 8fcae21adbd5a0af54f89f6b0e7e7e8fa1cdeb60..4663e8b415c9286b4730f0b3e087f47dd80fb02f 100644 (file)
@@ -88,26 +88,26 @@ static const struct drive_list_entry dma_white_list [] = {
 /*
  * Hitachi
  */
-        { "HITACHI_DK14FA-20"    ,       "ALL"           },
-        { "HTS726060M9AT00"      ,       "ALL"           },
+        { "HITACHI_DK14FA-20"    ,       NULL            },
+        { "HTS726060M9AT00"      ,       NULL            },
 /*
  * Maxtor
  */
-        { "Maxtor 6E040L0"      ,       "ALL"           },
-        { "Maxtor 6Y080P0"      ,       "ALL"           },
-        { "Maxtor 6Y160P0"      ,       "ALL"           },
+        { "Maxtor 6E040L0"      ,       NULL            },
+        { "Maxtor 6Y080P0"      ,       NULL            },
+        { "Maxtor 6Y160P0"      ,       NULL            },
 /*
  * Seagate
  */
-        { "ST3120026A"          ,       "ALL"           },
-        { "ST320014A"           ,       "ALL"           },
-        { "ST94011A"            ,       "ALL"           },
-        { "ST340016A"           ,       "ALL"           },
+        { "ST3120026A"          ,       NULL            },
+        { "ST320014A"           ,       NULL            },
+        { "ST94011A"            ,       NULL            },
+        { "ST340016A"           ,       NULL            },
 /*
  * Western Digital
  */
-        { "WDC WD400UE-00HCT0"  ,       "ALL"           },
-        { "WDC WD400JB-00JJC0"  ,       "ALL"           },
+        { "WDC WD400UE-00HCT0"  ,       NULL            },
+        { "WDC WD400JB-00JJC0"  ,       NULL            },
         { NULL                  ,       NULL            }
 };
 
@@ -116,9 +116,9 @@ static const struct drive_list_entry dma_black_list [] = {
 /*
  * Western Digital
  */
-        { "WDC WD100EB-00CGH0"  ,       "ALL"           },
-        { "WDC WD200BB-00AUA1"  ,       "ALL"           },
-        { "WDC AC24300L"        ,       "ALL"           },
+        { "WDC WD100EB-00CGH0"  ,       NULL            },
+        { "WDC WD200BB-00AUA1"  ,       NULL            },
+        { "WDC AC24300L"        ,       NULL            },
         { NULL                  ,       NULL            }
 };
 #endif
index db5b00a792f519d7d4dde9a2e4824a2c7f948db9..fae138bd2207b78e86645047938bc72df60a85d6 100644 (file)
@@ -868,11 +868,6 @@ void kblockd_flush_work(struct work_struct *work);
  */
 #define buffer_heads_over_limit 0
 
-static inline long blk_congestion_wait(int rw, long timeout)
-{
-       return io_schedule_timeout(timeout);
-}
-
 static inline long nr_blockdev_pages(void)
 {
        return 0;
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
new file mode 100644 (file)
index 0000000..d774b77
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+       Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
+       <http://rt2x00.serialmonkey.com>
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the
+       Free Software Foundation, Inc.,
+       59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+       Module: eeprom_93cx6
+       Abstract: EEPROM reader datastructures for 93cx6 chipsets.
+       Supported chipsets: 93c46 & 93c66.
+ */
+
+/*
+ * EEPROM operation defines.
+ */
+#define PCI_EEPROM_WIDTH_93C46 6
+#define PCI_EEPROM_WIDTH_93C66 8
+#define PCI_EEPROM_WIDTH_OPCODE        3
+#define PCI_EEPROM_WRITE_OPCODE        0x05
+#define PCI_EEPROM_READ_OPCODE 0x06
+#define PCI_EEPROM_EWDS_OPCODE 0x10
+#define PCI_EEPROM_EWEN_OPCODE 0x13
+
+/**
+ * struct eeprom_93cx6 - control structure for setting the commands
+ * for reading the eeprom data.
+ * @data: private pointer for the driver.
+ * @register_read(struct eeprom_93cx6 *eeprom): handler to
+ * read the eeprom register, this function should set all reg_* fields.
+ * @register_write(struct eeprom_93cx6 *eeprom): handler to
+ * write to the eeprom register by using all reg_* fields.
+ * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines
+ * @reg_data_in: register field to indicate data input
+ * @reg_data_out: register field to indicate data output
+ * @reg_data_clock: register field to set the data clock
+ * @reg_chip_select: register field to set the chip select
+ *
+ * This structure is used for the communication between the driver
+ * and the eeprom_93cx6 handlers for reading the eeprom.
+ */
+struct eeprom_93cx6 {
+       void *data;
+
+       void (*register_read)(struct eeprom_93cx6 *eeprom);
+       void (*register_write)(struct eeprom_93cx6 *eeprom);
+
+       int width;
+
+       char reg_data_in;
+       char reg_data_out;
+       char reg_data_clock;
+       char reg_chip_select;
+};
+
+extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom,
+       const u8 word, u16 *data);
+extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
+       const u8 word, __le16 *data, const u16 words);
index efbe1fda1a22f0c769f9e103d39317568d597de2..1a45d6f41b090e25447d8766114ddf68d74bd2f1 100644 (file)
 #define FW_CDEV_EVENT_REQUEST          0x02
 #define FW_CDEV_EVENT_ISO_INTERRUPT    0x03
 
-/* The 'closure' fields are for user space to use.  Data passed in the
- * 'closure' field for a request will be returned in the corresponding
- * event.  It's a 64-bit type so that it's a fixed size type big
- * enough to hold a pointer on all platforms. */
-
+/**
+ * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types
+ * @closure:   For arbitrary use by userspace
+ * @type:      Discriminates the fw_cdev_event_ types
+ *
+ * This struct may be used to access generic members of all fw_cdev_event_
+ * types regardless of the specific type.
+ *
+ * Data passed in the @closure field for a request will be returned in the
+ * corresponding event.  It is big enough to hold a pointer on all platforms.
+ * The ioctl used to set @closure depends on the @type of event.
+ */
 struct fw_cdev_event_common {
        __u64 closure;
        __u32 type;
 };
 
+/**
+ * struct fw_cdev_event_bus_reset - Sent when a bus reset occurred
+ * @closure:   See &fw_cdev_event_common; set by %FW_CDEV_IOC_GET_INFO ioctl
+ * @type:      See &fw_cdev_event_common; always %FW_CDEV_EVENT_BUS_RESET
+ * @node_id:       New node ID of this node
+ * @local_node_id: Node ID of the local node, i.e. of the controller
+ * @bm_node_id:    Node ID of the bus manager
+ * @irm_node_id:   Node ID of the iso resource manager
+ * @root_node_id:  Node ID of the root node
+ * @generation:    New bus generation
+ *
+ * This event is sent when the bus the device belongs to goes through a bus
+ * reset.  It provides information about the new bus configuration, such as
+ * new node ID for this device, new root ID, and others.
+ */
 struct fw_cdev_event_bus_reset {
        __u64 closure;
        __u32 type;
@@ -51,6 +73,20 @@ struct fw_cdev_event_bus_reset {
        __u32 generation;
 };
 
+/**
+ * struct fw_cdev_event_response - Sent when a response packet was received
+ * @closure:   See &fw_cdev_event_common;
+ *             set by %FW_CDEV_IOC_SEND_REQUEST ioctl
+ * @type:      See &fw_cdev_event_common; always %FW_CDEV_EVENT_RESPONSE
+ * @rcode:     Response code returned by the remote node
+ * @length:    Data length, i.e. the response's payload size in bytes
+ * @data:      Payload data, if any
+ *
+ * This event is sent when the stack receives a response to an outgoing request
+ * sent by %FW_CDEV_IOC_SEND_REQUEST ioctl.  The payload data for responses
+ * carrying data (read and lock responses) follows immediately and can be
+ * accessed through the @data field.
+ */
 struct fw_cdev_event_response {
        __u64 closure;
        __u32 type;
@@ -59,6 +95,25 @@ struct fw_cdev_event_response {
        __u32 data[0];
 };
 
+/**
+ * struct fw_cdev_event_request - Sent on incoming request to an address region
+ * @closure:   See &fw_cdev_event_common; set by %FW_CDEV_IOC_ALLOCATE ioctl
+ * @type:      See &fw_cdev_event_common; always %FW_CDEV_EVENT_REQUEST
+ * @tcode:     Transaction code of the incoming request
+ * @offset:    The offset into the 48-bit per-node address space
+ * @handle:    Reference to the kernel-side pending request
+ * @length:    Data length, i.e. the request's payload size in bytes
+ * @data:      Incoming data, if any
+ *
+ * This event is sent when the stack receives an incoming request to an address
+ * region registered using the %FW_CDEV_IOC_ALLOCATE ioctl.  The request is
+ * guaranteed to be completely contained in the specified region.  Userspace is
+ * responsible for sending the response by %FW_CDEV_IOC_SEND_RESPONSE ioctl,
+ * using the same @handle.
+ *
+ * The payload data for requests carrying data (write and lock requests)
+ * follows immediately and can be accessed through the @data field.
+ */
 struct fw_cdev_event_request {
        __u64 closure;
        __u32 type;
@@ -69,14 +124,39 @@ struct fw_cdev_event_request {
        __u32 data[0];
 };
 
+/**
+ * struct fw_cdev_event_iso_interrupt - Sent when an iso packet was completed
+ * @closure:   See &fw_cdev_event_common;
+ *             set by %FW_CDEV_CREATE_ISO_CONTEXT ioctl
+ * @type:      See &fw_cdev_event_common; always %FW_CDEV_EVENT_ISO_INTERRUPT
+ * @cycle:     Cycle counter of the interrupt packet
+ * @header_length: Total length of following headers, in bytes
+ * @header:    Stripped headers, if any
+ *
+ * This event is sent when the controller has completed an &fw_cdev_iso_packet
+ * with the %FW_CDEV_ISO_INTERRUPT bit set.  In the receive case, the headers
+ * stripped of all packets up until and including the interrupt packet are
+ * returned in the @header field.
+ */
 struct fw_cdev_event_iso_interrupt {
        __u64 closure;
        __u32 type;
        __u32 cycle;
-       __u32 header_length;    /* Length in bytes of following headers. */
+       __u32 header_length;
        __u32 header[0];
 };
 
+/**
+ * union fw_cdev_event - Convenience union of fw_cdev_event_ types
+ * @common:        Valid for all types
+ * @bus_reset:     Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET
+ * @response:      Valid if @common.type == %FW_CDEV_EVENT_RESPONSE
+ * @request:       Valid if @common.type == %FW_CDEV_EVENT_REQUEST
+ * @iso_interrupt: Valid if @common.type == %FW_CDEV_EVENT_ISO_INTERRUPT
+ *
+ * Convenience union for userspace use.  Events could be read(2) into a char
+ * buffer and then cast to this union for further processing.
+ */
 union fw_cdev_event {
        struct fw_cdev_event_common common;
        struct fw_cdev_event_bus_reset bus_reset;
@@ -105,35 +185,47 @@ union fw_cdev_event {
  */
 #define FW_CDEV_VERSION                1
 
+/**
+ * struct fw_cdev_get_info - General purpose information ioctl
+ * @version:   The version field is just a running serial number.
+ *             We never break backwards compatibility, but may add more
+ *             structs and ioctls in later revisions.
+ * @rom_length:        If @rom is non-zero, at most rom_length bytes of configuration
+ *             ROM will be copied into that user space address.  In either
+ *             case, @rom_length is updated with the actual length of the
+ *             configuration ROM.
+ * @rom:       If non-zero, address of a buffer to be filled by a copy of the
+ *             local node's configuration ROM
+ * @bus_reset: If non-zero, address of a buffer to be filled by a
+ *             &struct fw_cdev_event_bus_reset with the current state
+ *             of the bus.  This does not cause a bus reset to happen.
+ * @bus_reset_closure: Value of &closure in this and subsequent bus reset events
+ * @card:      The index of the card this device belongs to
+ */
 struct fw_cdev_get_info {
-       /* The version field is just a running serial number.  We
-        * never break backwards compatibility.  Userspace passes in
-        * the version it expects and the kernel passes back the
-        * highest version it can provide.  Even if the structs in
-        * this interface are extended in a later version, the kernel
-        * will not copy back more data than what was present in the
-        * interface version userspace expects. */
        __u32 version;
-
-       /* If non-zero, at most rom_length bytes of config rom will be
-        * copied into that user space address.  In either case,
-        * rom_length is updated with the actual length of the config
-        * rom. */
        __u32 rom_length;
        __u64 rom;
-
-       /* If non-zero, a fw_cdev_event_bus_reset struct will be
-        * copied here with the current state of the bus.  This does
-        * not cause a bus reset to happen.  The value of closure in
-        * this and sub-sequent bus reset events is set to
-        * bus_reset_closure. */
        __u64 bus_reset;
        __u64 bus_reset_closure;
-
-       /* The index of the card this devices belongs to. */
        __u32 card;
 };
 
+/**
+ * struct fw_cdev_send_request - Send an asynchronous request packet
+ * @tcode:     Transaction code of the request
+ * @length:    Length of outgoing payload, in bytes
+ * @offset:    48-bit offset at destination node
+ * @closure:   Passed back to userspace in the response event
+ * @data:      Userspace pointer to payload
+ * @generation:        The bus generation where packet is valid
+ *
+ * Send a request to the device.  This ioctl implements all outgoing requests.
+ * Both quadlet and block request specify the payload as a pointer to the data
+ * in the @data field.  Once the transaction completes, the kernel writes an
+ * &fw_cdev_event_request event back.  The @closure field is passed back to
+ * user space in the response event.
+ */
 struct fw_cdev_send_request {
        __u32 tcode;
        __u32 length;
@@ -143,6 +235,19 @@ struct fw_cdev_send_request {
        __u32 generation;
 };
 
+/**
+ * struct fw_cdev_send_response - Send an asynchronous response packet
+ * @rcode:     Response code as determined by the userspace handler
+ * @length:    Length of outgoing payload, in bytes
+ * @data:      Userspace pointer to payload
+ * @handle:    The handle from the &fw_cdev_event_request
+ *
+ * Send a response to an incoming request.  By setting up an address range using
+ * the %FW_CDEV_IOC_ALLOCATE ioctl, userspace can listen for incoming requests.  An
+ * incoming request will generate an %FW_CDEV_EVENT_REQUEST, and userspace must
+ * send a reply using this ioctl.  The event has a handle to the kernel-side
+ * pending transaction, which should be used with this ioctl.
+ */
 struct fw_cdev_send_response {
        __u32 rcode;
        __u32 length;
@@ -150,6 +255,21 @@ struct fw_cdev_send_response {
        __u32 handle;
 };
 
+/**
+ * struct fw_cdev_allocate - Allocate a CSR address range
+ * @offset:    Start offset of the address range
+ * @closure:   To be passed back to userspace in request events
+ * @length:    Length of the address range, in bytes
+ * @handle:    Handle to the allocation, written by the kernel
+ *
+ * Allocate an address range in the 48-bit address space on the local node
+ * (the controller).  This allows userspace to listen for requests with an
+ * offset within that address range.  When the kernel receives a request
+ * within the range, an &fw_cdev_event_request event will be written back.
+ * The @closure field is passed back to userspace in the response event.
+ * The @handle field is an out parameter, returning a handle to the allocated
+ * range to be used for later deallocation of the range.
+ */
 struct fw_cdev_allocate {
        __u64 offset;
        __u64 closure;
@@ -157,6 +277,11 @@ struct fw_cdev_allocate {
        __u32 handle;
 };
 
+/**
+ * struct fw_cdev_deallocate - Free an address range allocation
+ * @handle:    Handle to the address range, as returned by the kernel when the
+ *             range was allocated
+ */
 struct fw_cdev_deallocate {
        __u32 handle;
 };
@@ -164,10 +289,41 @@ struct fw_cdev_deallocate {
 #define FW_CDEV_LONG_RESET     0
 #define FW_CDEV_SHORT_RESET    1
 
+/**
+ * struct fw_cdev_initiate_bus_reset - Initiate a bus reset
+ * @type:      %FW_CDEV_SHORT_RESET or %FW_CDEV_LONG_RESET
+ *
+ * Initiate a bus reset for the bus this device is on.  The bus reset can be
+ * either the original (long) bus reset or the arbitrated (short) bus reset
+ * introduced in 1394a-2000.
+ */
 struct fw_cdev_initiate_bus_reset {
-       __u32 type;
+       __u32 type;     /* FW_CDEV_SHORT_RESET or FW_CDEV_LONG_RESET */
 };
 
+/**
+ * struct fw_cdev_add_descriptor - Add contents to the local node's config ROM
+ * @immediate: If non-zero, immediate key to insert before pointer
+ * @key:       Upper 8 bits of root directory pointer
+ * @data:      Userspace pointer to contents of descriptor block
+ * @length:    Length of descriptor block data, in bytes
+ * @handle:    Handle to the descriptor, written by the kernel
+ *
+ * Add a descriptor block and optionally a preceding immediate key to the local
+ * node's configuration ROM.
+ *
+ * The @key field specifies the upper 8 bits of the descriptor root directory
+ * pointer and the @data and @length fields specify the contents. The @key
+ * should be of the form 0xXX000000. The offset part of the root directory entry
+ * will be filled in by the kernel.
+ *
+ * If not 0, the @immediate field specifies an immediate key which will be
+ * inserted before the root directory pointer.
+ *
+ * If successful, the kernel adds the descriptor and writes back a handle to the
+ * kernel-side object to be used for later removal of the descriptor block and
+ * immediate key.
+ */
 struct fw_cdev_add_descriptor {
        __u32 immediate;
        __u32 key;
@@ -176,6 +332,14 @@ struct fw_cdev_add_descriptor {
        __u32 handle;
 };
 
+/**
+ * struct fw_cdev_remove_descriptor - Remove contents from the configuration ROM
+ * @handle:    Handle to the descriptor, as returned by the kernel when the
+ *             descriptor was added
+ *
+ * Remove a descriptor block and accompanying immediate key from the local
+ * node's configuration ROM.
+ */
 struct fw_cdev_remove_descriptor {
        __u32 handle;
 };
@@ -183,12 +347,24 @@ struct fw_cdev_remove_descriptor {
 #define FW_CDEV_ISO_CONTEXT_TRANSMIT   0
 #define FW_CDEV_ISO_CONTEXT_RECEIVE    1
 
-#define FW_CDEV_ISO_CONTEXT_MATCH_TAG0          1
-#define FW_CDEV_ISO_CONTEXT_MATCH_TAG1          2
-#define FW_CDEV_ISO_CONTEXT_MATCH_TAG2          4
-#define FW_CDEV_ISO_CONTEXT_MATCH_TAG3          8
-#define FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS     15
-
+/**
+ * struct fw_cdev_create_iso_context - Create a context for isochronous IO
+ * @type:      %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE
+ * @header_size: Header size to strip for receive contexts
+ * @channel:   Channel to bind to
+ * @speed:     Speed to transmit at
+ * @closure:   To be returned in &fw_cdev_event_iso_interrupt
+ * @handle:    Handle to context, written back by kernel
+ *
+ * Prior to sending or receiving isochronous I/O, a context must be created.
+ * The context records information about the transmit or receive configuration
+ * and typically maps to an underlying hardware resource.  A context is set up
+ * for either sending or receiving.  It is bound to a specific isochronous
+ * channel.
+ *
+ * If a context was successfully created, the kernel writes back a handle to the
+ * context, which must be passed in for subsequent operations on that context.
+ */
 struct fw_cdev_create_iso_context {
        __u32 type;
        __u32 header_size;
@@ -201,15 +377,49 @@ struct fw_cdev_create_iso_context {
 #define FW_CDEV_ISO_PAYLOAD_LENGTH(v)  (v)
 #define FW_CDEV_ISO_INTERRUPT          (1 << 16)
 #define FW_CDEV_ISO_SKIP               (1 << 17)
+#define FW_CDEV_ISO_SYNC               (1 << 17)
 #define FW_CDEV_ISO_TAG(v)             ((v) << 18)
 #define FW_CDEV_ISO_SY(v)              ((v) << 20)
 #define FW_CDEV_ISO_HEADER_LENGTH(v)   ((v) << 24)
 
+/**
+ * struct fw_cdev_iso_packet - Isochronous packet
+ * @control:   Contains the header length (8 uppermost bits), the sy field
+ *             (4 bits), the tag field (2 bits), a sync flag (1 bit),
+ *             a skip flag (1 bit), an interrupt flag (1 bit), and the
+ *             payload length (16 lowermost bits)
+ * @header:    Header and payload
+ *
+ * &struct fw_cdev_iso_packet is used to describe isochronous packet queues.
+ *
+ * Use the FW_CDEV_ISO_ macros to fill in @control.  The sy and tag fields are
+ * specified by IEEE 1394a and IEC 61883.
+ *
+ * FIXME - finish this documentation
+ */
 struct fw_cdev_iso_packet {
        __u32 control;
        __u32 header[0];
 };
 
+/**
+ * struct fw_cdev_queue_iso - Queue isochronous packets for I/O
+ * @packets:   Userspace pointer to packet data
+ * @data:      Pointer into mmap()'ed payload buffer
+ * @size:      Size of packet data in bytes
+ * @handle:    Isochronous context handle
+ *
+ * Queue a number of isochronous packets for reception or transmission.
+ * This ioctl takes a pointer to an array of &fw_cdev_iso_packet structs,
+ * which describe how to transmit from or receive into a contiguous region
+ * of a mmap()'ed payload buffer.  As part of the packet descriptors,
+ * a series of headers can be supplied, which will be prepended to the
+ * payload during DMA.
+ *
+ * The kernel may or may not queue all packets, but will write back updated
+ * values of the @packets, @data and @size fields, so the ioctl can be
+ * resubmitted easily.
+ */
 struct fw_cdev_queue_iso {
        __u64 packets;
        __u64 data;
@@ -217,6 +427,23 @@ struct fw_cdev_queue_iso {
        __u32 handle;
 };
 
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG0          1
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG1          2
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG2          4
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG3          8
+#define FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS     15
+
+/**
+ * struct fw_cdev_start_iso - Start an isochronous transmission or reception
+ * @cycle:     Cycle in which to start I/O.  If @cycle is greater than or
+ *             equal to 0, the I/O will start on that cycle.
+ * @sync:      Determines the value to wait for for receive packets that have
+ *             the %FW_CDEV_ISO_SYNC bit set
+ * @tags:      Tag filter bit mask.  Only valid for isochronous reception.
+ *             Determines the tag values for which packets will be accepted.
+ *             Use FW_CDEV_ISO_CONTEXT_MATCH_ macros to set @tags.
+ * @handle:    Isochronous context handle within which to transmit or receive
+ */
 struct fw_cdev_start_iso {
        __s32 cycle;
        __u32 sync;
@@ -224,6 +451,10 @@ struct fw_cdev_start_iso {
        __u32 handle;
 };
 
+/**
+ * struct fw_cdev_stop_iso - Stop an isochronous transmission or reception
+ * @handle:    Handle of isochronous context to stop
+ */
 struct fw_cdev_stop_iso {
        __u32 handle;
 };
index 6a41f4cab14c9a6efa90c824006497a55a230a19..4f0b3bf5983c81fb495794d09b9b5e7c632b17dd 100644 (file)
@@ -1054,7 +1054,7 @@ struct block_device_operations {
 };
 
 /*
- * "descriptor" for what we're up to with a read for sendfile().
+ * "descriptor" for what we're up to with a read.
  * This allows us to use the same read code yet
  * have multiple different users of the data that
  * we read from a file.
@@ -1105,7 +1105,6 @@ struct file_operations {
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
-       ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
@@ -1762,7 +1761,6 @@ extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *,
                unsigned long, loff_t, loff_t *, size_t, ssize_t);
 extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
 extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
-extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
 extern void do_generic_mapping_read(struct address_space *mapping,
                                    struct file_ra_state *, struct file *,
                                    loff_t *, read_descriptor_t *, read_actor_t);
@@ -1792,9 +1790,6 @@ extern int nonseekable_open(struct inode * inode, struct file * filp);
 #ifdef CONFIG_FS_XIP
 extern ssize_t xip_file_read(struct file *filp, char __user *buf, size_t len,
                             loff_t *ppos);
-extern ssize_t xip_file_sendfile(struct file *in_file, loff_t *ppos,
-                                size_t count, read_actor_t actor,
-                                void *target);
 extern int xip_file_mmap(struct file * file, struct vm_area_struct * vma);
 extern ssize_t xip_file_write(struct file *filp, const char __user *buf,
                              size_t len, loff_t *ppos);
diff --git a/include/linux/gpio_mouse.h b/include/linux/gpio_mouse.h
new file mode 100644 (file)
index 0000000..44ed7aa
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Driver for simulating a mouse on GPIO lines.
+ *
+ * Copyright (C) 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 _GPIO_MOUSE_H
+#define _GPIO_MOUSE_H
+
+#define GPIO_MOUSE_POLARITY_ACT_HIGH   0x00
+#define GPIO_MOUSE_POLARITY_ACT_LOW    0x01
+
+#define GPIO_MOUSE_PIN_UP      0
+#define GPIO_MOUSE_PIN_DOWN    1
+#define GPIO_MOUSE_PIN_LEFT    2
+#define GPIO_MOUSE_PIN_RIGHT   3
+#define GPIO_MOUSE_PIN_BLEFT   4
+#define GPIO_MOUSE_PIN_BMIDDLE 5
+#define GPIO_MOUSE_PIN_BRIGHT  6
+#define GPIO_MOUSE_PIN_MAX     7
+
+/**
+ * struct gpio_mouse_platform_data
+ * @scan_ms: integer in ms specifying the scan periode.
+ * @polarity: Pin polarity, active high or low.
+ * @up: GPIO line for up value.
+ * @down: GPIO line for down value.
+ * @left: GPIO line for left value.
+ * @right: GPIO line for right value.
+ * @bleft: GPIO line for left button.
+ * @bmiddle: GPIO line for middle button.
+ * @bright: GPIO line for right button.
+ *
+ * This struct must be added to the platform_device in the board code.
+ * It is used by the gpio_mouse driver to setup GPIO lines and to
+ * calculate mouse movement.
+ */
+struct gpio_mouse_platform_data {
+       int scan_ms;
+       int polarity;
+
+       union {
+               struct {
+                       int up;
+                       int down;
+                       int left;
+                       int right;
+
+                       int bleft;
+                       int bmiddle;
+                       int bright;
+               };
+               int pins[GPIO_MOUSE_PIN_MAX];
+       };
+};
+
+#endif /* _GPIO_MOUSE_H */
index 7803014f3a11bae4f353e7b042c0e1835997c7be..8d302298a161941ce40c6ed47411627d5f0229f8 100644 (file)
 # define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != 0)
 #endif
 
+#ifdef CONFIG_PREEMPT
+# define PREEMPT_CHECK_OFFSET 1
+#else
+# define PREEMPT_CHECK_OFFSET 0
+#endif
+
+/*
+ * Check whether we were atomic before we did preempt_disable():
+ * (used by the scheduler)
+ */
+#define in_atomic_preempt_off() \
+               ((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET)
+
 #ifdef CONFIG_PREEMPT
 # define preemptible() (preempt_count() == 0 && !irqs_disabled())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
index 827ee748fd4c88b76a65a6992c6cd20161b9e9a3..898103b401f1309d68ee5f91b80b3627d8aaa98b 100644 (file)
@@ -263,19 +263,28 @@ struct hid_item {
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x00000100
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x00000200
 #define HID_QUIRK_MIGHTYMOUSE                  0x00000400
-#define HID_QUIRK_CYMOTION                     0x00000800
-#define HID_QUIRK_POWERBOOK_HAS_FN             0x00001000
-#define HID_QUIRK_POWERBOOK_FN_ON              0x00002000
-#define HID_QUIRK_INVERT_HWHEEL                        0x00004000
-#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD        0x00008000
-#define HID_QUIRK_BAD_RELATIVE_KEYS            0x00010000
-#define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00020000
-#define HID_QUIRK_IGNORE_MOUSE                 0x00040000
-#define HID_QUIRK_SONY_PS3_CONTROLLER          0x00080000
-#define HID_QUIRK_LOGITECH_DESCRIPTOR          0x00100000
-#define HID_QUIRK_DUPLICATE_USAGES             0x00200000
-#define HID_QUIRK_RESET_LEDS                   0x00400000
-#define HID_QUIRK_SWAPPED_MIN_MAX              0x00800000
+#define HID_QUIRK_POWERBOOK_HAS_FN             0x00000800
+#define HID_QUIRK_POWERBOOK_FN_ON              0x00001000
+#define HID_QUIRK_INVERT_HWHEEL                        0x00002000
+#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD        0x00004000
+#define HID_QUIRK_BAD_RELATIVE_KEYS            0x00008000
+#define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
+#define HID_QUIRK_IGNORE_MOUSE                 0x00020000
+#define HID_QUIRK_SONY_PS3_CONTROLLER          0x00040000
+#define HID_QUIRK_DUPLICATE_USAGES             0x00080000
+#define HID_QUIRK_RESET_LEDS                   0x00100000
+#define HID_QUIRK_HIDINPUT                     0x00200000
+#define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL        0x00400000
+#define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP     0x00800000
+
+/*
+ * Separate quirks for runtime report descriptor fixup
+ */
+
+#define HID_QUIRK_RDESC_CYMOTION               0x00000001
+#define HID_QUIRK_RDESC_LOGITECH               0x00000002
+#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX                0x00000004
+#define HID_QUIRK_RDESC_PETALYNX               0x00000008
 
 /*
  * This is the global environment of the parser. This information is
@@ -488,6 +497,11 @@ struct hid_descriptor {
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
 
 /* HID core API */
+
+#ifdef CONFIG_HID_DEBUG
+extern int hid_debug;
+#endif
+
 extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
 extern int hidinput_connect(struct hid_device *);
@@ -506,6 +520,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
 int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks);
 int usbhid_quirks_init(char **quirks_param);
 void usbhid_quirks_exit(void);
+void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
 
 #ifdef CONFIG_HID_FF
 int hid_ff_init(struct hid_device *hid);
@@ -523,14 +538,19 @@ static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
 #else
 static inline int hid_ff_init(struct hid_device *hid) { return -1; }
 #endif
-#ifdef DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
-               __FILE__ , ## arg)
+
+#ifdef CONFIG_HID_DEBUG
+#define dbg_hid(format, arg...) if (hid_debug) \
+                               printk(KERN_DEBUG "%s: " format ,\
+                               __FILE__ , ## arg)
+#define dbg_hid_line(format, arg...) if (hid_debug) \
+                               printk(format, ## arg)
 #else
-#define dbg(format, arg...) do {} while (0)
+#define dbg_hid(format, arg...) do {} while (0)
+#define dbg_hid_line dbg_hid
 #endif
 
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
+#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
                __FILE__ , ## arg)
 #endif
 
index 1e365acdd36922dafcfc0a8b287a5368c5b9c9c2..19ab25804056b7b467197d89f1d6b8a02a757912 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/semaphore.h>
+#include <asm/mutex.h>
 
 /******************************************************************************
  * IDE driver configuration options (play with these as desired):
@@ -685,6 +686,8 @@ typedef struct hwif_s {
        u8 mwdma_mask;
        u8 swdma_mask;
 
+       u8 cbl;         /* cable type */
+
        hwif_chipset_t chipset; /* sub-module for tuning.. */
 
        struct pci_dev  *pci_dev;       /* for pci chipsets */
@@ -735,8 +738,8 @@ typedef struct hwif_s {
        void (*ide_dma_clear_irq)(ide_drive_t *drive);
        void (*dma_host_on)(ide_drive_t *drive);
        void (*dma_host_off)(ide_drive_t *drive);
-       int (*ide_dma_lostirq)(ide_drive_t *drive);
-       int (*ide_dma_timeout)(ide_drive_t *drive);
+       void (*dma_lost_irq)(ide_drive_t *drive);
+       void (*dma_timeout)(ide_drive_t *drive);
 
        void (*OUTB)(u8 addr, unsigned long port);
        void (*OUTBSYNC)(ide_drive_t *drive, u8 addr, unsigned long port);
@@ -791,7 +794,6 @@ typedef struct hwif_s {
        unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
        unsigned        reset      : 1; /* reset after probe */
        unsigned        autodma    : 1; /* auto-attempt using DMA at boot */
-       unsigned        udma_four  : 1; /* 1=ATA-66 capable, 0=default */
        unsigned        no_lba48   : 1; /* 1 = cannot do LBA48 */
        unsigned        no_lba48_dma : 1; /* 1 = cannot do LBA48 DMA */
        unsigned        auto_poll  : 1; /* supports nop auto-poll */
@@ -863,7 +865,7 @@ typedef struct hwgroup_s {
 
 typedef struct ide_driver_s ide_driver_t;
 
-extern struct semaphore ide_setting_sem;
+extern struct mutex ide_setting_mtx;
 
 int set_io_32bit(ide_drive_t *, int);
 int set_pio_mode(ide_drive_t *, int);
@@ -1304,8 +1306,8 @@ extern int __ide_dma_check(ide_drive_t *);
 extern int ide_dma_setup(ide_drive_t *);
 extern void ide_dma_start(ide_drive_t *);
 extern int __ide_dma_end(ide_drive_t *);
-extern int __ide_dma_lostirq(ide_drive_t *);
-extern int __ide_dma_timeout(ide_drive_t *);
+extern void ide_dma_lost_irq(ide_drive_t *);
+extern void ide_dma_timeout(ide_drive_t *);
 #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 #else
@@ -1382,11 +1384,11 @@ extern const ide_pio_timings_t ide_pio_timings[6];
 
 
 extern spinlock_t ide_lock;
-extern struct semaphore ide_cfg_sem;
+extern struct mutex ide_cfg_mtx;
 /*
  * Structure locking:
  *
- * ide_cfg_sem and ide_lock together protect changes to
+ * ide_cfg_mtx and ide_lock together protect changes to
  * ide_hwif_t->{next,hwgroup}
  * ide_drive_t->next
  *
index d8521c72f69f9ff4aad1fc97223cd6dbadd5923d..18c98b54303099eec767b2b9b9d7cf4a185f3c76 100644 (file)
@@ -981,15 +981,15 @@ struct input_dev {
        struct mutex mutex;     /* serializes open and close operations */
        unsigned int users;
 
-       struct class_device cdev;
+       struct device dev;
        union {                 /* temporarily so while we switching to struct device */
-               struct device *parent;
-       } dev;
+               struct device *dev;
+       } cdev;
 
        struct list_head        h_list;
        struct list_head        node;
 };
-#define to_input_dev(d) container_of(d, struct input_dev, cdev)
+#define to_input_dev(d) container_of(d, struct input_dev, dev)
 
 /*
  * Verify that we are in sync with input_device_id mod_devicetable.h #defines
@@ -1096,22 +1096,22 @@ struct input_handle {
        struct list_head        h_node;
 };
 
-#define to_dev(n) container_of(n,struct input_dev,node)
-#define to_handler(n) container_of(n,struct input_handler,node)
-#define to_handle(n) container_of(n,struct input_handle,d_node)
-#define to_handle_h(n) container_of(n,struct input_handle,h_node)
+#define to_dev(n) container_of(n, struct input_dev, node)
+#define to_handler(n) container_of(n, struct input_handler, node)
+#define to_handle(n) container_of(n, struct input_handle, d_node)
+#define to_handle_h(n) container_of(n, struct input_handle, h_node)
 
 struct input_dev *input_allocate_device(void);
 void input_free_device(struct input_dev *dev);
 
 static inline struct input_dev *input_get_device(struct input_dev *dev)
 {
-       return to_input_dev(class_device_get(&dev->cdev));
+       return to_input_dev(get_device(&dev->dev));
 }
 
 static inline void input_put_device(struct input_dev *dev)
 {
-       class_device_put(&dev->cdev);
+       put_device(&dev->dev);
 }
 
 static inline void *input_get_drvdata(struct input_dev *dev)
index 8e2042b9d471024635bb412b5ac1a1b0fe075108..2eaa142cd06171bae79f35a7e72442648cb86f46 100644 (file)
@@ -47,8 +47,10 @@ enum {
 #define IOPRIO_NORM    (4)
 static inline int task_ioprio(struct task_struct *task)
 {
-       WARN_ON(!ioprio_valid(task->ioprio));
-       return IOPRIO_PRIO_DATA(task->ioprio);
+       if (ioprio_valid(task->ioprio))
+               return IOPRIO_PRIO_DATA(task->ioprio);
+
+       return IOPRIO_NORM;
 }
 
 static inline int task_nice_ioprio(struct task_struct *task)
index c8884f9712285b25cc88ff7518c2e0b79e0bcb39..8e4120285f72ef3379be0de768880b67453437c9 100644 (file)
@@ -9,13 +9,39 @@
 #define PIPE_BUF_FLAG_ATOMIC   0x02    /* was atomically mapped */
 #define PIPE_BUF_FLAG_GIFT     0x04    /* page is a gift */
 
+/**
+ *     struct pipe_buffer - a linux kernel pipe buffer
+ *     @page: the page containing the data for the pipe buffer
+ *     @offset: offset of data inside the @page
+ *     @len: length of data inside the @page
+ *     @ops: operations associated with this buffer. See @pipe_buf_operations.
+ *     @flags: pipe buffer flags. See above.
+ *     @private: private data owned by the ops.
+ **/
 struct pipe_buffer {
        struct page *page;
        unsigned int offset, len;
        const struct pipe_buf_operations *ops;
        unsigned int flags;
+       unsigned long private;
 };
 
+/**
+ *     struct pipe_inode_info - a linux kernel pipe
+ *     @wait: reader/writer wait point in case of empty/full pipe
+ *     @nrbufs: the number of non-empty pipe buffers in this pipe
+ *     @curbuf: the current pipe buffer entry
+ *     @tmp_page: cached released page
+ *     @readers: number of current readers of this pipe
+ *     @writers: number of current writers of this pipe
+ *     @waiting_writers: number of writers blocked waiting for room
+ *     @r_counter: reader counter
+ *     @w_counter: writer counter
+ *     @fasync_readers: reader side fasync
+ *     @fasync_writers: writer side fasync
+ *     @inode: inode this pipe is attached to
+ *     @bufs: the circular array of pipe buffers
+ **/
 struct pipe_inode_info {
        wait_queue_head_t wait;
        unsigned int nrbufs, curbuf;
@@ -34,22 +60,73 @@ struct pipe_inode_info {
 /*
  * Note on the nesting of these functions:
  *
- * ->pin()
+ * ->confirm()
  *     ->steal()
  *     ...
  *     ->map()
  *     ...
  *     ->unmap()
  *
- * That is, ->map() must be called on a pinned buffer, same goes for ->steal().
+ * That is, ->map() must be called on a confirmed buffer,
+ * same goes for ->steal(). See below for the meaning of each
+ * operation. Also see kerneldoc in fs/pipe.c for the pipe
+ * and generic variants of these hooks.
  */
 struct pipe_buf_operations {
+       /*
+        * This is set to 1, if the generic pipe read/write may coalesce
+        * data into an existing buffer. If this is set to 0, a new pipe
+        * page segment is always used for new data.
+        */
        int can_merge;
+
+       /*
+        * ->map() returns a virtual address mapping of the pipe buffer.
+        * The last integer flag reflects whether this should be an atomic
+        * mapping or not. The atomic map is faster, however you can't take
+        * page faults before calling ->unmap() again. So if you need to eg
+        * access user data through copy_to/from_user(), then you must get
+        * a non-atomic map. ->map() uses the KM_USER0 atomic slot for
+        * atomic maps, so you can't map more than one pipe_buffer at once
+        * and you have to be careful if mapping another page as source
+        * or destination for a copy (IOW, it has to use something else
+        * than KM_USER0).
+        */
        void * (*map)(struct pipe_inode_info *, struct pipe_buffer *, int);
+
+       /*
+        * Undoes ->map(), finishes the virtual mapping of the pipe buffer.
+        */
        void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *, void *);
-       int (*pin)(struct pipe_inode_info *, struct pipe_buffer *);
+
+       /*
+        * ->confirm() verifies that the data in the pipe buffer is there
+        * and that the contents are good. If the pages in the pipe belong
+        * to a file system, we may need to wait for IO completion in this
+        * hook. Returns 0 for good, or a negative error value in case of
+        * error.
+        */
+       int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);
+
+       /*
+        * When the contents of this pipe buffer has been completely
+        * consumed by a reader, ->release() is called.
+        */
        void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
+
+       /*
+        * Attempt to take ownership of the pipe buffer and its contents.
+        * ->steal() returns 0 for success, in which case the contents
+        * of the pipe (the buf->page) is locked and now completely owned
+        * by the caller. The page may then be transferred to a different
+        * mapping, the most often used case is insertion into different
+        * file address space cache.
+        */
        int (*steal)(struct pipe_inode_info *, struct pipe_buffer *);
+
+       /*
+        * Get a reference to the pipe buffer.
+        */
        void (*get)(struct pipe_inode_info *, struct pipe_buffer *);
 };
 
@@ -68,39 +145,7 @@ void __free_pipe_info(struct pipe_inode_info *);
 void *generic_pipe_buf_map(struct pipe_inode_info *, struct pipe_buffer *, int);
 void generic_pipe_buf_unmap(struct pipe_inode_info *, struct pipe_buffer *, void *);
 void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
-int generic_pipe_buf_pin(struct pipe_inode_info *, struct pipe_buffer *);
+int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *);
 int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *);
 
-/*
- * splice is tied to pipes as a transport (at least for now), so we'll just
- * add the splice flags here.
- */
-#define SPLICE_F_MOVE  (0x01)  /* move pages instead of copying */
-#define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */
-                                /* we may still block on the fd we splice */
-                                /* from/to, of course */
-#define SPLICE_F_MORE  (0x04)  /* expect more data */
-#define SPLICE_F_GIFT  (0x08)  /* pages passed in are a gift */
-
-/*
- * Passed to the actors
- */
-struct splice_desc {
-       unsigned int len, total_len;    /* current and remaining length */
-       unsigned int flags;             /* splice flags */
-       struct file *file;              /* file to read/write */
-       loff_t pos;                     /* file position */
-};
-
-typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
-                          struct splice_desc *);
-
-extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *,
-                               loff_t *, size_t, unsigned int,
-                               splice_actor *);
-
-extern ssize_t __splice_from_pipe(struct pipe_inode_info *, struct file *,
-                                 loff_t *, size_t, unsigned int,
-                                 splice_actor *);
-
 #endif
index 693f0e6c54d47595c6f3268d0e20b5de74303d90..cfb680585ab8bd87762fe3e9b2bedfb404882760 100644 (file)
@@ -34,6 +34,8 @@
 #define SCHED_FIFO             1
 #define SCHED_RR               2
 #define SCHED_BATCH            3
+/* SCHED_ISO: reserved but not implemented yet */
+#define SCHED_IDLE             5
 
 #ifdef __KERNEL__
 
@@ -130,6 +132,26 @@ extern unsigned long nr_active(void);
 extern unsigned long nr_iowait(void);
 extern unsigned long weighted_cpuload(const int cpu);
 
+struct seq_file;
+struct cfs_rq;
+#ifdef CONFIG_SCHED_DEBUG
+extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m);
+extern void proc_sched_set_task(struct task_struct *p);
+extern void
+print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now);
+#else
+static inline void
+proc_sched_show_task(struct task_struct *p, struct seq_file *m)
+{
+}
+static inline void proc_sched_set_task(struct task_struct *p)
+{
+}
+static inline void
+print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now)
+{
+}
+#endif
 
 /*
  * Task state bitmask. NOTE! These bits are also
@@ -193,6 +215,7 @@ struct task_struct;
 extern void sched_init(void);
 extern void sched_init_smp(void);
 extern void init_idle(struct task_struct *idle, int cpu);
+extern void init_idle_bootup_task(struct task_struct *idle);
 
 extern cpumask_t nohz_cpu_mask;
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
@@ -479,7 +502,7 @@ struct signal_struct {
         * from jiffies_to_ns(utime + stime) if sched_clock uses something
         * other than jiffies.)
         */
-       unsigned long long sched_time;
+       unsigned long long sum_sched_runtime;
 
        /*
         * We don't bother to synchronize most readers of this at all,
@@ -521,31 +544,6 @@ struct signal_struct {
 #define SIGNAL_STOP_CONTINUED  0x00000004 /* SIGCONT since WCONTINUED reap */
 #define SIGNAL_GROUP_EXIT      0x00000008 /* group exit in progress */
 
-
-/*
- * Priority of a process goes from 0..MAX_PRIO-1, valid RT
- * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
- * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
- * values are inverted: lower p->prio value means higher priority.
- *
- * The MAX_USER_RT_PRIO value allows the actual maximum
- * RT priority to be separate from the value exported to
- * user-space.  This allows kernel threads to set their
- * priority to a value higher than any user task. Note:
- * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
- */
-
-#define MAX_USER_RT_PRIO       100
-#define MAX_RT_PRIO            MAX_USER_RT_PRIO
-
-#define MAX_PRIO               (MAX_RT_PRIO + 40)
-
-#define rt_prio(prio)          unlikely((prio) < MAX_RT_PRIO)
-#define rt_task(p)             rt_prio((p)->prio)
-#define batch_task(p)          (unlikely((p)->policy == SCHED_BATCH))
-#define is_rt_policy(p)                ((p) != SCHED_NORMAL && (p) != SCHED_BATCH)
-#define has_rt_policy(p)       unlikely(is_rt_policy((p)->policy))
-
 /*
  * Some day this will be a full-fledged user tracking system..
  */
@@ -583,13 +581,13 @@ struct reclaim_state;
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
 struct sched_info {
        /* cumulative counters */
-       unsigned long   cpu_time,       /* time spent on the cpu */
-                       run_delay,      /* time spent waiting on a runqueue */
-                       pcnt;           /* # of timeslices run on this cpu */
+       unsigned long pcnt;           /* # of times run on this cpu */
+       unsigned long long cpu_time,  /* time spent on the cpu */
+                          run_delay; /* time spent waiting on a runqueue */
 
        /* timestamps */
-       unsigned long   last_arrival,   /* when we last ran on a cpu */
-                       last_queued;    /* when we were last queued to run */
+       unsigned long long last_arrival,/* when we last ran on a cpu */
+                          last_queued; /* when we were last queued to run */
 };
 #endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */
 
@@ -639,18 +637,24 @@ static inline int sched_info_on(void)
 #endif
 }
 
-enum idle_type
-{
-       SCHED_IDLE,
-       NOT_IDLE,
-       NEWLY_IDLE,
-       MAX_IDLE_TYPES
+enum cpu_idle_type {
+       CPU_IDLE,
+       CPU_NOT_IDLE,
+       CPU_NEWLY_IDLE,
+       CPU_MAX_IDLE_TYPES
 };
 
 /*
  * sched-domains (multiprocessor balancing) declarations:
  */
-#define SCHED_LOAD_SCALE       128UL   /* increase resolution of load */
+
+/*
+ * Increase resolution of nice-level calculations:
+ */
+#define SCHED_LOAD_SHIFT       10
+#define SCHED_LOAD_SCALE       (1L << SCHED_LOAD_SHIFT)
+
+#define SCHED_LOAD_SCALE_FUZZ  (SCHED_LOAD_SCALE >> 5)
 
 #ifdef CONFIG_SMP
 #define SD_LOAD_BALANCE                1       /* Do load balancing on this domain. */
@@ -719,14 +723,14 @@ struct sched_domain {
 
 #ifdef CONFIG_SCHEDSTATS
        /* load_balance() stats */
-       unsigned long lb_cnt[MAX_IDLE_TYPES];
-       unsigned long lb_failed[MAX_IDLE_TYPES];
-       unsigned long lb_balanced[MAX_IDLE_TYPES];
-       unsigned long lb_imbalance[MAX_IDLE_TYPES];
-       unsigned long lb_gained[MAX_IDLE_TYPES];
-       unsigned long lb_hot_gained[MAX_IDLE_TYPES];
-       unsigned long lb_nobusyg[MAX_IDLE_TYPES];
-       unsigned long lb_nobusyq[MAX_IDLE_TYPES];
+       unsigned long lb_cnt[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_failed[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_balanced[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_imbalance[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_gained[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_hot_gained[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_nobusyg[CPU_MAX_IDLE_TYPES];
+       unsigned long lb_nobusyq[CPU_MAX_IDLE_TYPES];
 
        /* Active load balancing */
        unsigned long alb_cnt;
@@ -753,12 +757,6 @@ struct sched_domain {
 extern int partition_sched_domains(cpumask_t *partition1,
                                    cpumask_t *partition2);
 
-/*
- * Maximum cache size the migration-costs auto-tuning code will
- * search from:
- */
-extern unsigned int max_cache_size;
-
 #endif /* CONFIG_SMP */
 
 
@@ -809,14 +807,86 @@ struct mempolicy;
 struct pipe_inode_info;
 struct uts_namespace;
 
-enum sleep_type {
-       SLEEP_NORMAL,
-       SLEEP_NONINTERACTIVE,
-       SLEEP_INTERACTIVE,
-       SLEEP_INTERRUPTED,
+struct rq;
+struct sched_domain;
+
+struct sched_class {
+       struct sched_class *next;
+
+       void (*enqueue_task) (struct rq *rq, struct task_struct *p,
+                             int wakeup, u64 now);
+       void (*dequeue_task) (struct rq *rq, struct task_struct *p,
+                             int sleep, u64 now);
+       void (*yield_task) (struct rq *rq, struct task_struct *p);
+
+       void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
+
+       struct task_struct * (*pick_next_task) (struct rq *rq, u64 now);
+       void (*put_prev_task) (struct rq *rq, struct task_struct *p, u64 now);
+
+       int (*load_balance) (struct rq *this_rq, int this_cpu,
+                       struct rq *busiest,
+                       unsigned long max_nr_move, unsigned long max_load_move,
+                       struct sched_domain *sd, enum cpu_idle_type idle,
+                       int *all_pinned, unsigned long *total_load_moved);
+
+       void (*set_curr_task) (struct rq *rq);
+       void (*task_tick) (struct rq *rq, struct task_struct *p);
+       void (*task_new) (struct rq *rq, struct task_struct *p);
 };
 
-struct prio_array;
+struct load_weight {
+       unsigned long weight, inv_weight;
+};
+
+/*
+ * CFS stats for a schedulable entity (task, task-group etc)
+ *
+ * Current field usage histogram:
+ *
+ *     4 se->block_start
+ *     4 se->run_node
+ *     4 se->sleep_start
+ *     4 se->sleep_start_fair
+ *     6 se->load.weight
+ *     7 se->delta_fair
+ *    15 se->wait_runtime
+ */
+struct sched_entity {
+       long                    wait_runtime;
+       unsigned long           delta_fair_run;
+       unsigned long           delta_fair_sleep;
+       unsigned long           delta_exec;
+       s64                     fair_key;
+       struct load_weight      load;           /* for load-balancing */
+       struct rb_node          run_node;
+       unsigned int            on_rq;
+
+       u64                     wait_start_fair;
+       u64                     wait_start;
+       u64                     exec_start;
+       u64                     sleep_start;
+       u64                     sleep_start_fair;
+       u64                     block_start;
+       u64                     sleep_max;
+       u64                     block_max;
+       u64                     exec_max;
+       u64                     wait_max;
+       u64                     last_ran;
+
+       u64                     sum_exec_runtime;
+       s64                     sum_wait_runtime;
+       s64                     sum_sleep_runtime;
+       unsigned long           wait_runtime_overruns;
+       unsigned long           wait_runtime_underruns;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       struct sched_entity     *parent;
+       /* rq on which this entity is (to be) queued: */
+       struct cfs_rq           *cfs_rq;
+       /* rq "owned" by this entity/group: */
+       struct cfs_rq           *my_q;
+#endif
+};
 
 struct task_struct {
        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
@@ -832,23 +902,20 @@ struct task_struct {
        int oncpu;
 #endif
 #endif
-       int load_weight;        /* for niceness load balancing purposes */
+
        int prio, static_prio, normal_prio;
        struct list_head run_list;
-       struct prio_array *array;
+       struct sched_class *sched_class;
+       struct sched_entity se;
 
        unsigned short ioprio;
 #ifdef CONFIG_BLK_DEV_IO_TRACE
        unsigned int btrace_seq;
 #endif
-       unsigned long sleep_avg;
-       unsigned long long timestamp, last_ran;
-       unsigned long long sched_time; /* sched_clock time spent running */
-       enum sleep_type sleep_type;
 
        unsigned int policy;
        cpumask_t cpus_allowed;
-       unsigned int time_slice, first_time_slice;
+       unsigned int time_slice;
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
        struct sched_info sched_info;
@@ -1078,6 +1145,37 @@ struct task_struct {
 #endif
 };
 
+/*
+ * Priority of a process goes from 0..MAX_PRIO-1, valid RT
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
+ * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
+ * values are inverted: lower p->prio value means higher priority.
+ *
+ * The MAX_USER_RT_PRIO value allows the actual maximum
+ * RT priority to be separate from the value exported to
+ * user-space.  This allows kernel threads to set their
+ * priority to a value higher than any user task. Note:
+ * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
+ */
+
+#define MAX_USER_RT_PRIO       100
+#define MAX_RT_PRIO            MAX_USER_RT_PRIO
+
+#define MAX_PRIO               (MAX_RT_PRIO + 40)
+#define DEFAULT_PRIO           (MAX_RT_PRIO + 20)
+
+static inline int rt_prio(int prio)
+{
+       if (unlikely(prio < MAX_RT_PRIO))
+               return 1;
+       return 0;
+}
+
+static inline int rt_task(struct task_struct *p)
+{
+       return rt_prio(p->prio);
+}
+
 static inline pid_t process_group(struct task_struct *tsk)
 {
        return tsk->signal->pgrp;
@@ -1223,7 +1321,7 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
 
 extern unsigned long long sched_clock(void);
 extern unsigned long long
-current_sched_time(const struct task_struct *current_task);
+task_sched_runtime(struct task_struct *task);
 
 /* sched_exec is called by processes performing an exec */
 #ifdef CONFIG_SMP
@@ -1232,6 +1330,8 @@ extern void sched_exec(void);
 #define sched_exec()   {}
 #endif
 
+extern void sched_clock_unstable_event(void);
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void idle_task_exit(void);
 #else
@@ -1240,6 +1340,14 @@ static inline void idle_task_exit(void) {}
 
 extern void sched_idle_next(void);
 
+extern unsigned int sysctl_sched_granularity;
+extern unsigned int sysctl_sched_wakeup_granularity;
+extern unsigned int sysctl_sched_batch_wakeup_granularity;
+extern unsigned int sysctl_sched_stat_granularity;
+extern unsigned int sysctl_sched_runtime_limit;
+extern unsigned int sysctl_sched_child_runs_first;
+extern unsigned int sysctl_sched_features;
+
 #ifdef CONFIG_RT_MUTEXES
 extern int rt_mutex_getprio(struct task_struct *p);
 extern void rt_mutex_setprio(struct task_struct *p, int prio);
@@ -1317,8 +1425,8 @@ extern void FASTCALL(wake_up_new_task(struct task_struct * tsk,
 #else
  static inline void kick_process(struct task_struct *tsk) { }
 #endif
-extern void FASTCALL(sched_fork(struct task_struct * p, int clone_flags));
-extern void FASTCALL(sched_exit(struct task_struct * p));
+extern void sched_fork(struct task_struct *p, int clone_flags);
+extern void sched_dead(struct task_struct *p);
 
 extern int in_group_p(gid_t);
 extern int in_egroup_p(gid_t);
@@ -1406,7 +1514,7 @@ extern struct mm_struct * mm_alloc(void);
 extern void FASTCALL(__mmdrop(struct mm_struct *));
 static inline void mmdrop(struct mm_struct * mm)
 {
-       if (atomic_dec_and_test(&mm->mm_count))
+       if (unlikely(atomic_dec_and_test(&mm->mm_count)))
                __mmdrop(mm);
 }
 
@@ -1638,10 +1746,7 @@ static inline unsigned int task_cpu(const struct task_struct *p)
        return task_thread_info(p)->cpu;
 }
 
-static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
-{
-       task_thread_info(p)->cpu = cpu;
-}
+extern void set_task_cpu(struct task_struct *p, unsigned int cpu);
 
 #else
 
diff --git a/include/linux/splice.h b/include/linux/splice.h
new file mode 100644 (file)
index 0000000..33e447f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Function declerations and data structures related to the splice
+ * implementation.
+ *
+ * Copyright (C) 2007 Jens Axboe <jens.axboe@oracle.com>
+ *
+ */
+#ifndef SPLICE_H
+#define SPLICE_H
+
+#include <linux/pipe_fs_i.h>
+
+/*
+ * splice is tied to pipes as a transport (at least for now), so we'll just
+ * add the splice flags here.
+ */
+#define SPLICE_F_MOVE  (0x01)  /* move pages instead of copying */
+#define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */
+                                /* we may still block on the fd we splice */
+                                /* from/to, of course */
+#define SPLICE_F_MORE  (0x04)  /* expect more data */
+#define SPLICE_F_GIFT  (0x08)  /* pages passed in are a gift */
+
+/*
+ * Passed to the actors
+ */
+struct splice_desc {
+       unsigned int len, total_len;    /* current and remaining length */
+       unsigned int flags;             /* splice flags */
+       /*
+        * actor() private data
+        */
+       union {
+               void __user *userptr;   /* memory to write to */
+               struct file *file;      /* file to read/write */
+               void *data;             /* cookie */
+       } u;
+       loff_t pos;                     /* file position */
+};
+
+struct partial_page {
+       unsigned int offset;
+       unsigned int len;
+       unsigned long private;
+};
+
+/*
+ * Passed to splice_to_pipe
+ */
+struct splice_pipe_desc {
+       struct page **pages;            /* page map */
+       struct partial_page *partial;   /* pages[] may not be contig */
+       int nr_pages;                   /* number of pages in map */
+       unsigned int flags;             /* splice flags */
+       const struct pipe_buf_operations *ops;/* ops associated with output pipe */
+};
+
+typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
+                          struct splice_desc *);
+typedef int (splice_direct_actor)(struct pipe_inode_info *,
+                                 struct splice_desc *);
+
+extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *,
+                               loff_t *, size_t, unsigned int,
+                               splice_actor *);
+extern ssize_t __splice_from_pipe(struct pipe_inode_info *,
+                                 struct splice_desc *, splice_actor *);
+extern ssize_t splice_to_pipe(struct pipe_inode_info *,
+                             struct splice_pipe_desc *);
+extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
+                                     splice_direct_actor *);
+
+#endif
index 4a7ae8ab6eb873e75aa2f14c59fc40332dd7da48..129d50f2225c02b8bb94505de60dc579b9a87427 100644 (file)
@@ -253,7 +253,7 @@ struct svc_rqst {
                                                 * determine what device number
                                                 * to report (real or virtual)
                                                 */
-       int                     rq_sendfile_ok; /* turned off in gss privacy
+       int                     rq_splice_ok;   /* turned off in gss privacy
                                                 * to prevent encrypting page
                                                 * cache pages */
        wait_queue_head_t       rq_wait;        /* synchronization */
index a9d1f049cc151aa07202ffbc41346dc78a95d4b3..da6c39b2d051c30c7ec14df2b8f3b27115569ddc 100644 (file)
@@ -98,7 +98,7 @@
        .cache_nice_tries       = 0,                    \
        .busy_idx               = 0,                    \
        .idle_idx               = 0,                    \
-       .newidle_idx            = 1,                    \
+       .newidle_idx            = 0,                    \
        .wake_idx               = 0,                    \
        .forkexec_idx           = 0,                    \
        .flags                  = SD_LOAD_BALANCE       \
        .imbalance_pct          = 125,                  \
        .cache_nice_tries       = 1,                    \
        .busy_idx               = 2,                    \
-       .idle_idx               = 1,                    \
-       .newidle_idx            = 2,                    \
+       .idle_idx               = 0,                    \
+       .newidle_idx            = 0,                    \
        .wake_idx               = 1,                    \
        .forkexec_idx           = 1,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
                                | SD_WAKE_AFFINE        \
+                               | SD_WAKE_IDLE          \
                                | SD_SHARE_PKG_RESOURCES\
                                | BALANCE_FOR_MC_POWER, \
        .last_balance           = jiffies,              \
        .imbalance_pct          = 125,                  \
        .cache_nice_tries       = 1,                    \
        .busy_idx               = 2,                    \
-       .idle_idx               = 1,                    \
-       .newidle_idx            = 2,                    \
+       .idle_idx               = 0,                    \
+       .newidle_idx            = 0,                    \
        .wake_idx               = 1,                    \
        .forkexec_idx           = 1,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
                                | SD_WAKE_AFFINE        \
+                               | SD_WAKE_IDLE          \
                                | BALANCE_FOR_PKG_POWER,\
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
index 94bd38a6d947be480281f3a8e4de4edff7f03c84..56aa2ee21f1b284659e6164bcc9f2dea59ada2c1 100644 (file)
@@ -728,6 +728,22 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
        .idVendor = (vend), .idProduct = (prod), \
        .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
 
+/**
+ * USB_DEVICE_INTERFACE_PROTOCOL - macro used to describe a usb
+ *             device with a specific interface protocol
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ * @pr: bInterfaceProtocol value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific interface protocol of devices.
+ */
+#define USB_DEVICE_INTERFACE_PROTOCOL(vend,prod,pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bInterfaceProtocol = (pr)
+
 /**
  * USB_DEVICE_INFO - macro used to describe a class of usb devices
  * @cl: bDeviceClass value
index e820d00e13836af125710e67753ad5fee2b9bc36..0e686280450b3808eb2bbda7124772896b879ac7 100644 (file)
@@ -366,15 +366,15 @@ static inline void remove_wait_queue_locked(wait_queue_head_t *q,
 
 /*
  * These are the old interfaces to sleep waiting for an event.
- * They are racy.  DO NOT use them, use the wait_event* interfaces above.  
- * We plan to remove these interfaces during 2.7.
+ * They are racy.  DO NOT use them, use the wait_event* interfaces above.
+ * We plan to remove these interfaces.
  */
-extern void FASTCALL(sleep_on(wait_queue_head_t *q));
-extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q,
-                                     signed long timeout));
-extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q));
-extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q,
-                                                   signed long timeout));
+extern void sleep_on(wait_queue_head_t *q);
+extern long sleep_on_timeout(wait_queue_head_t *q,
+                                     signed long timeout);
+extern void interruptible_sleep_on(wait_queue_head_t *q);
+extern long interruptible_sleep_on_timeout(wait_queue_head_t *q,
+                                          signed long timeout);
 
 /*
  * Waitqueues which are removed from the waitqueue_head at wakeup time
index eae7e2e844974b903dd3b0094a5ead23da7546ac..ad6e278ba7f2df6e11c347840a8175ea2dc25930 100644 (file)
 #define MANFID_POSSIO                  0x030c
 #define PRODID_POSSIO_GCC              0x0003
 
+#define MANFID_NEC                     0x0010
+
 #endif /* _LINUX_CISCODE_H */
index a9e99f8328ff485386faf668b61ee59c7a1fb085..d9d878a3bb46835e1f2c4301620975e05757ee1d 100644 (file)
@@ -686,6 +686,4 @@ config STOP_MACHINE
          Need stop_machine() primitive.
 endmenu
 
-menu "Block layer"
 source "block/Kconfig"
-endmenu
index eb8bdbae4fc79026f8ee4664f34da66c82076c1e..0eb1c7463fe4d08c3012ee66cb486c72122a26d5 100644 (file)
@@ -436,15 +436,16 @@ static void noinline __init_refok rest_init(void)
 
        /*
         * The boot idle thread must execute schedule()
-        * at least one to get things moving:
+        * at least once to get things moving:
         */
+       init_idle_bootup_task(current);
        preempt_enable_no_resched();
        schedule();
        preempt_disable();
 
        /* Call into cpu_idle with preempt disabled */
        cpu_idle();
-} 
+}
 
 /* Check for early params. */
 static int __init do_early_param(char *param, char *val)
index c0148ae992c4aaee7295c50a6670a1ffc6c13b33..81e697829633cb31725e589e68ab55642b6aa9e1 100644 (file)
@@ -99,9 +99,10 @@ void __delayacct_blkio_end(void)
 int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
 {
        s64 tmp;
-       struct timespec ts;
-       unsigned long t1,t2,t3;
+       unsigned long t1;
+       unsigned long long t2, t3;
        unsigned long flags;
+       struct timespec ts;
 
        /* Though tsk->delays accessed later, early exit avoids
         * unnecessary returning of other data
@@ -124,11 +125,10 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
 
        d->cpu_count += t1;
 
-       jiffies_to_timespec(t2, &ts);
-       tmp = (s64)d->cpu_delay_total + timespec_to_ns(&ts);
+       tmp = (s64)d->cpu_delay_total + t2;
        d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
 
-       tmp = (s64)d->cpu_run_virtual_total + (s64)jiffies_to_usecs(t3) * 1000;
+       tmp = (s64)d->cpu_run_virtual_total + t3;
        d->cpu_run_virtual_total =
                (tmp < (s64)d->cpu_run_virtual_total) ? 0 : tmp;
 
index 5c8ecbaa19a530cc4d417a897457b0d0318bc39b..ca6a11b730231bd0d6d9ece041e1a2f537223582 100644 (file)
@@ -122,9 +122,9 @@ static void __exit_signal(struct task_struct *tsk)
                sig->maj_flt += tsk->maj_flt;
                sig->nvcsw += tsk->nvcsw;
                sig->nivcsw += tsk->nivcsw;
-               sig->sched_time += tsk->sched_time;
                sig->inblock += task_io_get_inblock(tsk);
                sig->oublock += task_io_get_oublock(tsk);
+               sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
                sig = NULL; /* Marker for below. */
        }
 
@@ -182,7 +182,6 @@ repeat:
                zap_leader = (leader->exit_signal == -1);
        }
 
-       sched_exit(p);
        write_unlock_irq(&tasklist_lock);
        proc_flush_task(p);
        release_thread(p);
@@ -291,7 +290,7 @@ static void reparent_to_kthreadd(void)
        /* Set the exit signal to SIGCHLD so we signal init on exit */
        current->exit_signal = SIGCHLD;
 
-       if (!has_rt_policy(current) && (task_nice(current) < 0))
+       if (task_nice(current) < 0)
                set_user_nice(current, 0);
        /* cpus_allowed? */
        /* rt_priority? */
index 73ad5cda1bcd277cf3c86c29bd851df3fc933c73..da3a155bba0ddc5c50a8082833a90be6fe60e8ce 100644 (file)
@@ -877,7 +877,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
        sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
        sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
        sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
-       sig->sched_time = 0;
+       sig->sum_sched_runtime = 0;
        INIT_LIST_HEAD(&sig->cpu_timers[0]);
        INIT_LIST_HEAD(&sig->cpu_timers[1]);
        INIT_LIST_HEAD(&sig->cpu_timers[2]);
@@ -1040,7 +1040,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        p->utime = cputime_zero;
        p->stime = cputime_zero;
-       p->sched_time = 0;
+
 #ifdef CONFIG_TASK_XACCT
        p->rchar = 0;           /* I/O counter: bytes read */
        p->wchar = 0;           /* I/O counter: bytes written */
index 1de710e183734b6e47bd7aa4819bd5b3c54deeb2..b53c8fcd9d82d25044867c9529a17f9b1fdb00f8 100644 (file)
@@ -161,7 +161,7 @@ static inline cputime_t virt_ticks(struct task_struct *p)
 }
 static inline unsigned long long sched_ns(struct task_struct *p)
 {
-       return (p == current) ? current_sched_time(p) : p->sched_time;
+       return task_sched_runtime(p);
 }
 
 int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp)
@@ -246,10 +246,10 @@ static int cpu_clock_sample_group_locked(unsigned int clock_idx,
                } while (t != p);
                break;
        case CPUCLOCK_SCHED:
-               cpu->sched = p->signal->sched_time;
+               cpu->sched = p->signal->sum_sched_runtime;
                /* Add in each other live thread.  */
                while ((t = next_thread(t)) != p) {
-                       cpu->sched += t->sched_time;
+                       cpu->sched += t->se.sum_exec_runtime;
                }
                cpu->sched += sched_ns(p);
                break;
@@ -422,7 +422,7 @@ int posix_cpu_timer_del(struct k_itimer *timer)
  */
 static void cleanup_timers(struct list_head *head,
                           cputime_t utime, cputime_t stime,
-                          unsigned long long sched_time)
+                          unsigned long long sum_exec_runtime)
 {
        struct cpu_timer_list *timer, *next;
        cputime_t ptime = cputime_add(utime, stime);
@@ -451,10 +451,10 @@ static void cleanup_timers(struct list_head *head,
        ++head;
        list_for_each_entry_safe(timer, next, head, entry) {
                list_del_init(&timer->entry);
-               if (timer->expires.sched < sched_time) {
+               if (timer->expires.sched < sum_exec_runtime) {
                        timer->expires.sched = 0;
                } else {
-                       timer->expires.sched -= sched_time;
+                       timer->expires.sched -= sum_exec_runtime;
                }
        }
 }
@@ -467,7 +467,7 @@ static void cleanup_timers(struct list_head *head,
 void posix_cpu_timers_exit(struct task_struct *tsk)
 {
        cleanup_timers(tsk->cpu_timers,
-                      tsk->utime, tsk->stime, tsk->sched_time);
+                      tsk->utime, tsk->stime, tsk->se.sum_exec_runtime);
 
 }
 void posix_cpu_timers_exit_group(struct task_struct *tsk)
@@ -475,7 +475,7 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)
        cleanup_timers(tsk->signal->cpu_timers,
                       cputime_add(tsk->utime, tsk->signal->utime),
                       cputime_add(tsk->stime, tsk->signal->stime),
-                      tsk->sched_time + tsk->signal->sched_time);
+                    tsk->se.sum_exec_runtime + tsk->signal->sum_sched_runtime);
 }
 
 
@@ -536,7 +536,7 @@ static void process_timer_rebalance(struct task_struct *p,
                nsleft = max_t(unsigned long long, nsleft, 1);
                do {
                        if (likely(!(t->flags & PF_EXITING))) {
-                               ns = t->sched_time + nsleft;
+                               ns = t->se.sum_exec_runtime + nsleft;
                                if (t->it_sched_expires == 0 ||
                                    t->it_sched_expires > ns) {
                                        t->it_sched_expires = ns;
@@ -1004,7 +1004,7 @@ static void check_thread_timers(struct task_struct *tsk,
                struct cpu_timer_list *t = list_first_entry(timers,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (!--maxfire || tsk->sched_time < t->expires.sched) {
+               if (!--maxfire || tsk->se.sum_exec_runtime < t->expires.sched) {
                        tsk->it_sched_expires = t->expires.sched;
                        break;
                }
@@ -1024,7 +1024,7 @@ static void check_process_timers(struct task_struct *tsk,
        int maxfire;
        struct signal_struct *const sig = tsk->signal;
        cputime_t utime, stime, ptime, virt_expires, prof_expires;
-       unsigned long long sched_time, sched_expires;
+       unsigned long long sum_sched_runtime, sched_expires;
        struct task_struct *t;
        struct list_head *timers = sig->cpu_timers;
 
@@ -1044,12 +1044,12 @@ static void check_process_timers(struct task_struct *tsk,
         */
        utime = sig->utime;
        stime = sig->stime;
-       sched_time = sig->sched_time;
+       sum_sched_runtime = sig->sum_sched_runtime;
        t = tsk;
        do {
                utime = cputime_add(utime, t->utime);
                stime = cputime_add(stime, t->stime);
-               sched_time += t->sched_time;
+               sum_sched_runtime += t->se.sum_exec_runtime;
                t = next_thread(t);
        } while (t != tsk);
        ptime = cputime_add(utime, stime);
@@ -1090,7 +1090,7 @@ static void check_process_timers(struct task_struct *tsk,
                struct cpu_timer_list *t = list_first_entry(timers,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (!--maxfire || sched_time < t->expires.sched) {
+               if (!--maxfire || sum_sched_runtime < t->expires.sched) {
                        sched_expires = t->expires.sched;
                        break;
                }
@@ -1182,7 +1182,7 @@ static void check_process_timers(struct task_struct *tsk,
                virt_left = cputime_sub(virt_expires, utime);
                virt_left = cputime_div_non_zero(virt_left, nthreads);
                if (sched_expires) {
-                       sched_left = sched_expires - sched_time;
+                       sched_left = sched_expires - sum_sched_runtime;
                        do_div(sched_left, nthreads);
                        sched_left = max_t(unsigned long long, sched_left, 1);
                } else {
@@ -1208,7 +1208,7 @@ static void check_process_timers(struct task_struct *tsk,
                                t->it_virt_expires = ticks;
                        }
 
-                       sched = t->sched_time + sched_left;
+                       sched = t->se.sum_exec_runtime + sched_left;
                        if (sched_expires && (t->it_sched_expires == 0 ||
                                              t->it_sched_expires > sched)) {
                                t->it_sched_expires = sched;
@@ -1300,7 +1300,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
 
        if (UNEXPIRED(prof) && UNEXPIRED(virt) &&
            (tsk->it_sched_expires == 0 ||
-            tsk->sched_time < tsk->it_sched_expires))
+            tsk->se.sum_exec_runtime < tsk->it_sched_expires))
                return;
 
 #undef UNEXPIRED
index 95db8c79fe8f3371249029a19e48e817ffc34d12..3b299fb3855cc5384fb520beb18b6f6a904da511 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/cpu.h>
+#include <linux/splice.h>
 
 /* list of open channels, for cpu hotplug */
 static DEFINE_MUTEX(relay_channels_mutex);
@@ -121,6 +122,7 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
                buf->page_array[i] = alloc_page(GFP_KERNEL);
                if (unlikely(!buf->page_array[i]))
                        goto depopulate;
+               set_page_private(buf->page_array[i], (unsigned long)buf);
        }
        mem = vmap(buf->page_array, n_pages, VM_MAP, PAGE_KERNEL);
        if (!mem)
@@ -970,43 +972,6 @@ static int subbuf_read_actor(size_t read_start,
        return ret;
 }
 
-/*
- *     subbuf_send_actor - send up to one subbuf's worth of data
- */
-static int subbuf_send_actor(size_t read_start,
-                            struct rchan_buf *buf,
-                            size_t avail,
-                            read_descriptor_t *desc,
-                            read_actor_t actor)
-{
-       unsigned long pidx, poff;
-       unsigned int subbuf_pages;
-       int ret = 0;
-
-       subbuf_pages = buf->chan->alloc_size >> PAGE_SHIFT;
-       pidx = (read_start / PAGE_SIZE) % subbuf_pages;
-       poff = read_start & ~PAGE_MASK;
-       while (avail) {
-               struct page *p = buf->page_array[pidx];
-               unsigned int len;
-
-               len = PAGE_SIZE - poff;
-               if (len > avail)
-                       len = avail;
-
-               len = actor(desc, p, poff, len);
-               if (desc->error)
-                       break;
-
-               avail -= len;
-               ret += len;
-               poff = 0;
-               pidx = (pidx + 1) % subbuf_pages;
-       }
-
-       return ret;
-}
-
 typedef int (*subbuf_actor_t) (size_t read_start,
                               struct rchan_buf *buf,
                               size_t avail,
@@ -1067,19 +1032,159 @@ static ssize_t relay_file_read(struct file *filp,
                                       NULL, &desc);
 }
 
-static ssize_t relay_file_sendfile(struct file *filp,
-                                  loff_t *ppos,
-                                  size_t count,
-                                  read_actor_t actor,
-                                  void *target)
+static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)
 {
-       read_descriptor_t desc;
-       desc.written = 0;
-       desc.count = count;
-       desc.arg.data = target;
-       desc.error = 0;
-       return relay_file_read_subbufs(filp, ppos, subbuf_send_actor,
-                                      actor, &desc);
+       rbuf->bytes_consumed += bytes_consumed;
+
+       if (rbuf->bytes_consumed >= rbuf->chan->subbuf_size) {
+               relay_subbufs_consumed(rbuf->chan, rbuf->cpu, 1);
+               rbuf->bytes_consumed %= rbuf->chan->subbuf_size;
+       }
+}
+
+static void relay_pipe_buf_release(struct pipe_inode_info *pipe,
+                                  struct pipe_buffer *buf)
+{
+       struct rchan_buf *rbuf;
+
+       rbuf = (struct rchan_buf *)page_private(buf->page);
+       relay_consume_bytes(rbuf, buf->private);
+}
+
+static struct pipe_buf_operations relay_pipe_buf_ops = {
+       .can_merge = 0,
+       .map = generic_pipe_buf_map,
+       .unmap = generic_pipe_buf_unmap,
+       .confirm = generic_pipe_buf_confirm,
+       .release = relay_pipe_buf_release,
+       .steal = generic_pipe_buf_steal,
+       .get = generic_pipe_buf_get,
+};
+
+/**
+ *     subbuf_splice_actor - splice up to one subbuf's worth of data
+ */
+static int subbuf_splice_actor(struct file *in,
+                              loff_t *ppos,
+                              struct pipe_inode_info *pipe,
+                              size_t len,
+                              unsigned int flags,
+                              int *nonpad_ret)
+{
+       unsigned int pidx, poff, total_len, subbuf_pages, ret;
+       struct rchan_buf *rbuf = in->private_data;
+       unsigned int subbuf_size = rbuf->chan->subbuf_size;
+       size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size;
+       size_t read_subbuf = read_start / subbuf_size;
+       size_t padding = rbuf->padding[read_subbuf];
+       size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding;
+       struct page *pages[PIPE_BUFFERS];
+       struct partial_page partial[PIPE_BUFFERS];
+       struct splice_pipe_desc spd = {
+               .pages = pages,
+               .nr_pages = 0,
+               .partial = partial,
+               .flags = flags,
+               .ops = &relay_pipe_buf_ops,
+       };
+
+       if (rbuf->subbufs_produced == rbuf->subbufs_consumed)
+               return 0;
+
+       /*
+        * Adjust read len, if longer than what is available
+        */
+       if (len > (subbuf_size - read_start % subbuf_size))
+               len = subbuf_size - read_start % subbuf_size;
+
+       subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT;
+       pidx = (read_start / PAGE_SIZE) % subbuf_pages;
+       poff = read_start & ~PAGE_MASK;
+
+       for (total_len = 0; spd.nr_pages < subbuf_pages; spd.nr_pages++) {
+               unsigned int this_len, this_end, private;
+               unsigned int cur_pos = read_start + total_len;
+
+               if (!len)
+                       break;
+
+               this_len = min_t(unsigned long, len, PAGE_SIZE - poff);
+               private = this_len;
+
+               spd.pages[spd.nr_pages] = rbuf->page_array[pidx];
+               spd.partial[spd.nr_pages].offset = poff;
+
+               this_end = cur_pos + this_len;
+               if (this_end >= nonpad_end) {
+                       this_len = nonpad_end - cur_pos;
+                       private = this_len + padding;
+               }
+               spd.partial[spd.nr_pages].len = this_len;
+               spd.partial[spd.nr_pages].private = private;
+
+               len -= this_len;
+               total_len += this_len;
+               poff = 0;
+               pidx = (pidx + 1) % subbuf_pages;
+
+               if (this_end >= nonpad_end) {
+                       spd.nr_pages++;
+                       break;
+               }
+       }
+
+       if (!spd.nr_pages)
+               return 0;
+
+       ret = *nonpad_ret = splice_to_pipe(pipe, &spd);
+       if (ret < 0 || ret < total_len)
+               return ret;
+
+        if (read_start + ret == nonpad_end)
+                ret += padding;
+
+        return ret;
+}
+
+static ssize_t relay_file_splice_read(struct file *in,
+                                     loff_t *ppos,
+                                     struct pipe_inode_info *pipe,
+                                     size_t len,
+                                     unsigned int flags)
+{
+       ssize_t spliced;
+       int ret;
+       int nonpad_ret = 0;
+
+       ret = 0;
+       spliced = 0;
+
+       while (len) {
+               ret = subbuf_splice_actor(in, ppos, pipe, len, flags, &nonpad_ret);
+               if (ret < 0)
+                       break;
+               else if (!ret) {
+                       if (spliced)
+                               break;
+                       if (flags & SPLICE_F_NONBLOCK) {
+                               ret = -EAGAIN;
+                               break;
+                       }
+               }
+
+               *ppos += ret;
+               if (ret > len)
+                       len = 0;
+               else
+                       len -= ret;
+               spliced += nonpad_ret;
+               nonpad_ret = 0;
+       }
+
+       if (spliced)
+               return spliced;
+
+       return ret;
 }
 
 const struct file_operations relay_file_operations = {
@@ -1089,7 +1194,7 @@ const struct file_operations relay_file_operations = {
        .read           = relay_file_read,
        .llseek         = no_llseek,
        .release        = relay_file_release,
-       .sendfile       = relay_file_sendfile,
+       .splice_read    = relay_file_splice_read,
 };
 EXPORT_SYMBOL_GPL(relay_file_operations);
 
index 50e1a312269945284bc0ce769eb9b2acd629b7f2..9fbced64bfee004e1275088bb22eb4ac848e1733 100644 (file)
  *             by Davide Libenzi, preemptible kernel bits by Robert Love.
  *  2003-09-03 Interactivity tuning by Con Kolivas.
  *  2004-04-02 Scheduler domains code by Nick Piggin
+ *  2007-04-15  Work begun on replacing all interactivity tuning with a
+ *              fair scheduling design by Con Kolivas.
+ *  2007-05-05  Load balancing (smp-nice) and other improvements
+ *              by Peter Williams
+ *  2007-05-06  Interactivity improvements to CFS by Mike Galbraith
+ *  2007-07-01  Group scheduling enhancements by Srivatsa Vaddagiri
  */
 
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/nmi.h>
 #include <linux/init.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/highmem.h>
 #include <linux/smp_lock.h>
 #include <asm/mmu_context.h>
@@ -53,9 +59,9 @@
 #include <linux/kprobes.h>
 #include <linux/delayacct.h>
 #include <linux/reciprocal_div.h>
+#include <linux/unistd.h>
 
 #include <asm/tlb.h>
-#include <asm/unistd.h>
 
 /*
  * Scheduler clock - returns current time in nanosec units.
@@ -91,6 +97,9 @@ unsigned long long __attribute__((weak)) sched_clock(void)
 #define NS_TO_JIFFIES(TIME)    ((TIME) / (1000000000 / HZ))
 #define JIFFIES_TO_NS(TIME)    ((TIME) * (1000000000 / HZ))
 
+#define NICE_0_LOAD            SCHED_LOAD_SCALE
+#define NICE_0_SHIFT           SCHED_LOAD_SHIFT
+
 /*
  * These are the 'tuning knobs' of the scheduler:
  *
@@ -100,87 +109,6 @@ unsigned long long __attribute__((weak)) sched_clock(void)
  */
 #define MIN_TIMESLICE          max(5 * HZ / 1000, 1)
 #define DEF_TIMESLICE          (100 * HZ / 1000)
-#define ON_RUNQUEUE_WEIGHT      30
-#define CHILD_PENALTY           95
-#define PARENT_PENALTY         100
-#define EXIT_WEIGHT              3
-#define PRIO_BONUS_RATIO        25
-#define MAX_BONUS              (MAX_USER_PRIO * PRIO_BONUS_RATIO / 100)
-#define INTERACTIVE_DELTA        2
-#define MAX_SLEEP_AVG          (DEF_TIMESLICE * MAX_BONUS)
-#define STARVATION_LIMIT       (MAX_SLEEP_AVG)
-#define NS_MAX_SLEEP_AVG       (JIFFIES_TO_NS(MAX_SLEEP_AVG))
-
-/*
- * If a task is 'interactive' then we reinsert it in the active
- * array after it has expired its current timeslice. (it will not
- * continue to run immediately, it will still roundrobin with
- * other interactive tasks.)
- *
- * This part scales the interactivity limit depending on niceness.
- *
- * We scale it linearly, offset by the INTERACTIVE_DELTA delta.
- * Here are a few examples of different nice levels:
- *
- *  TASK_INTERACTIVE(-20): [1,1,1,1,1,1,1,1,1,0,0]
- *  TASK_INTERACTIVE(-10): [1,1,1,1,1,1,1,0,0,0,0]
- *  TASK_INTERACTIVE(  0): [1,1,1,1,0,0,0,0,0,0,0]
- *  TASK_INTERACTIVE( 10): [1,1,0,0,0,0,0,0,0,0,0]
- *  TASK_INTERACTIVE( 19): [0,0,0,0,0,0,0,0,0,0,0]
- *
- * (the X axis represents the possible -5 ... 0 ... +5 dynamic
- *  priority range a task can explore, a value of '1' means the
- *  task is rated interactive.)
- *
- * Ie. nice +19 tasks can never get 'interactive' enough to be
- * reinserted into the active array. And only heavily CPU-hog nice -20
- * tasks will be expired. Default nice 0 tasks are somewhere between,
- * it takes some effort for them to get interactive, but it's not
- * too hard.
- */
-
-#define CURRENT_BONUS(p) \
-       (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / \
-               MAX_SLEEP_AVG)
-
-#define GRANULARITY    (10 * HZ / 1000 ? : 1)
-
-#ifdef CONFIG_SMP
-#define TIMESLICE_GRANULARITY(p)       (GRANULARITY * \
-               (1 << (((MAX_BONUS - CURRENT_BONUS(p)) ? : 1) - 1)) * \
-                       num_online_cpus())
-#else
-#define TIMESLICE_GRANULARITY(p)       (GRANULARITY * \
-               (1 << (((MAX_BONUS - CURRENT_BONUS(p)) ? : 1) - 1)))
-#endif
-
-#define SCALE(v1,v1_max,v2_max) \
-       (v1) * (v2_max) / (v1_max)
-
-#define DELTA(p) \
-       (SCALE(TASK_NICE(p) + 20, 40, MAX_BONUS) - 20 * MAX_BONUS / 40 + \
-               INTERACTIVE_DELTA)
-
-#define TASK_INTERACTIVE(p) \
-       ((p)->prio <= (p)->static_prio - DELTA(p))
-
-#define INTERACTIVE_SLEEP(p) \
-       (JIFFIES_TO_NS(MAX_SLEEP_AVG * \
-               (MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1))
-
-#define TASK_PREEMPTS_CURR(p, rq) \
-       ((p)->prio < (rq)->curr->prio)
-
-#define SCALE_PRIO(x, prio) \
-       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
-
-static unsigned int static_prio_timeslice(int static_prio)
-{
-       if (static_prio < NICE_TO_PRIO(0))
-               return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio);
-       else
-               return SCALE_PRIO(DEF_TIMESLICE, static_prio);
-}
 
 #ifdef CONFIG_SMP
 /*
@@ -203,28 +131,87 @@ static inline void sg_inc_cpu_power(struct sched_group *sg, u32 val)
 }
 #endif
 
+#define SCALE_PRIO(x, prio) \
+       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
+
 /*
- * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
+ * static_prio_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
  * to time slice values: [800ms ... 100ms ... 5ms]
- *
- * The higher a thread's priority, the bigger timeslices
- * it gets during one round of execution. But even the lowest
- * priority thread gets MIN_TIMESLICE worth of execution time.
  */
+static unsigned int static_prio_timeslice(int static_prio)
+{
+       if (static_prio == NICE_TO_PRIO(19))
+               return 1;
+
+       if (static_prio < NICE_TO_PRIO(0))
+               return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio);
+       else
+               return SCALE_PRIO(DEF_TIMESLICE, static_prio);
+}
+
+static inline int rt_policy(int policy)
+{
+       if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+               return 1;
+       return 0;
+}
 
-static inline unsigned int task_timeslice(struct task_struct *p)
+static inline int task_has_rt_policy(struct task_struct *p)
 {
-       return static_prio_timeslice(p->static_prio);
+       return rt_policy(p->policy);
 }
 
 /*
- * These are the runqueue data structures:
+ * This is the priority-queue data structure of the RT scheduling class:
  */
+struct rt_prio_array {
+       DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */
+       struct list_head queue[MAX_RT_PRIO];
+};
+
+struct load_stat {
+       struct load_weight load;
+       u64 load_update_start, load_update_last;
+       unsigned long delta_fair, delta_exec, delta_stat;
+};
+
+/* CFS-related fields in a runqueue */
+struct cfs_rq {
+       struct load_weight load;
+       unsigned long nr_running;
+
+       s64 fair_clock;
+       u64 exec_clock;
+       s64 wait_runtime;
+       u64 sleeper_bonus;
+       unsigned long wait_runtime_overruns, wait_runtime_underruns;
+
+       struct rb_root tasks_timeline;
+       struct rb_node *rb_leftmost;
+       struct rb_node *rb_load_balance_curr;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       /* 'curr' points to currently running entity on this cfs_rq.
+        * It is set to NULL otherwise (i.e when none are currently running).
+        */
+       struct sched_entity *curr;
+       struct rq *rq;  /* cpu runqueue to which this cfs_rq is attached */
 
-struct prio_array {
-       unsigned int nr_active;
-       DECLARE_BITMAP(bitmap, MAX_PRIO+1); /* include 1 bit for delimiter */
-       struct list_head queue[MAX_PRIO];
+       /* leaf cfs_rqs are those that hold tasks (lowest schedulable entity in
+        * a hierarchy). Non-leaf lrqs hold other higher schedulable entities
+        * (like users, containers etc.)
+        *
+        * leaf_cfs_rq_list ties together list of leaf cfs_rq's in a cpu. This
+        * list is used during load balance.
+        */
+       struct list_head leaf_cfs_rq_list; /* Better name : task_cfs_rq_list? */
+#endif
+};
+
+/* Real-Time classes' related field in a runqueue: */
+struct rt_rq {
+       struct rt_prio_array active;
+       int rt_load_balance_idx;
+       struct list_head *rt_load_balance_head, *rt_load_balance_curr;
 };
 
 /*
@@ -235,22 +222,28 @@ struct prio_array {
  * acquire operations must be ordered by ascending &runqueue.
  */
 struct rq {
-       spinlock_t lock;
+       spinlock_t lock;        /* runqueue lock */
 
        /*
         * nr_running and cpu_load should be in the same cacheline because
         * remote CPUs use both these fields when doing load calculation.
         */
        unsigned long nr_running;
-       unsigned long raw_weighted_load;
-#ifdef CONFIG_SMP
-       unsigned long cpu_load[3];
+       #define CPU_LOAD_IDX_MAX 5
+       unsigned long cpu_load[CPU_LOAD_IDX_MAX];
        unsigned char idle_at_tick;
 #ifdef CONFIG_NO_HZ
        unsigned char in_nohz_recently;
 #endif
+       struct load_stat ls;    /* capture load from *all* tasks on this cpu */
+       unsigned long nr_load_updates;
+       u64 nr_switches;
+
+       struct cfs_rq cfs;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       struct list_head leaf_cfs_rq_list; /* list of leaf cfs_rq on this cpu */
 #endif
-       unsigned long long nr_switches;
+       struct rt_rq  rt;
 
        /*
         * This is part of a global counter where only the total sum
@@ -260,14 +253,18 @@ struct rq {
         */
        unsigned long nr_uninterruptible;
 
-       unsigned long expired_timestamp;
-       /* Cached timestamp set by update_cpu_clock() */
-       unsigned long long most_recent_timestamp;
        struct task_struct *curr, *idle;
        unsigned long next_balance;
        struct mm_struct *prev_mm;
-       struct prio_array *active, *expired, arrays[2];
-       int best_expired_prio;
+
+       u64 clock, prev_clock_raw;
+       s64 clock_max_delta;
+
+       unsigned int clock_warps, clock_overflows;
+       unsigned int clock_unstable_events;
+
+       struct sched_class *load_balance_class;
+
        atomic_t nr_iowait;
 
 #ifdef CONFIG_SMP
@@ -307,6 +304,11 @@ struct rq {
 static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
 static DEFINE_MUTEX(sched_hotcpu_mutex);
 
+static inline void check_preempt_curr(struct rq *rq, struct task_struct *p)
+{
+       rq->curr->sched_class->check_preempt_curr(rq, p);
+}
+
 static inline int cpu_of(struct rq *rq)
 {
 #ifdef CONFIG_SMP
@@ -316,6 +318,52 @@ static inline int cpu_of(struct rq *rq)
 #endif
 }
 
+/*
+ * Per-runqueue clock, as finegrained as the platform can give us:
+ */
+static unsigned long long __rq_clock(struct rq *rq)
+{
+       u64 prev_raw = rq->prev_clock_raw;
+       u64 now = sched_clock();
+       s64 delta = now - prev_raw;
+       u64 clock = rq->clock;
+
+       /*
+        * Protect against sched_clock() occasionally going backwards:
+        */
+       if (unlikely(delta < 0)) {
+               clock++;
+               rq->clock_warps++;
+       } else {
+               /*
+                * Catch too large forward jumps too:
+                */
+               if (unlikely(delta > 2*TICK_NSEC)) {
+                       clock++;
+                       rq->clock_overflows++;
+               } else {
+                       if (unlikely(delta > rq->clock_max_delta))
+                               rq->clock_max_delta = delta;
+                       clock += delta;
+               }
+       }
+
+       rq->prev_clock_raw = now;
+       rq->clock = clock;
+
+       return clock;
+}
+
+static inline unsigned long long rq_clock(struct rq *rq)
+{
+       int this_cpu = smp_processor_id();
+
+       if (this_cpu == cpu_of(rq))
+               return __rq_clock(rq);
+
+       return rq->clock;
+}
+
 /*
  * The domain tree (rq->sd) is protected by RCU's quiescent state transition.
  * See detach_destroy_domains: synchronize_sched for details.
@@ -331,6 +379,18 @@ static inline int cpu_of(struct rq *rq)
 #define task_rq(p)             cpu_rq(task_cpu(p))
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/* Change a task's ->cfs_rq if it moves across CPUs */
+static inline void set_task_cfs_rq(struct task_struct *p)
+{
+       p->se.cfs_rq = &task_rq(p)->cfs;
+}
+#else
+static inline void set_task_cfs_rq(struct task_struct *p)
+{
+}
+#endif
+
 #ifndef prepare_arch_switch
 # define prepare_arch_switch(next)     do { } while (0)
 #endif
@@ -460,134 +520,6 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags)
        spin_unlock_irqrestore(&rq->lock, *flags);
 }
 
-#ifdef CONFIG_SCHEDSTATS
-/*
- * bump this up when changing the output format or the meaning of an existing
- * format, so that tools can adapt (or abort)
- */
-#define SCHEDSTAT_VERSION 14
-
-static int show_schedstat(struct seq_file *seq, void *v)
-{
-       int cpu;
-
-       seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
-       seq_printf(seq, "timestamp %lu\n", jiffies);
-       for_each_online_cpu(cpu) {
-               struct rq *rq = cpu_rq(cpu);
-#ifdef CONFIG_SMP
-               struct sched_domain *sd;
-               int dcnt = 0;
-#endif
-
-               /* runqueue-specific stats */
-               seq_printf(seq,
-                   "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
-                   cpu, rq->yld_both_empty,
-                   rq->yld_act_empty, rq->yld_exp_empty, rq->yld_cnt,
-                   rq->sched_switch, rq->sched_cnt, rq->sched_goidle,
-                   rq->ttwu_cnt, rq->ttwu_local,
-                   rq->rq_sched_info.cpu_time,
-                   rq->rq_sched_info.run_delay, rq->rq_sched_info.pcnt);
-
-               seq_printf(seq, "\n");
-
-#ifdef CONFIG_SMP
-               /* domain-specific stats */
-               preempt_disable();
-               for_each_domain(cpu, sd) {
-                       enum idle_type itype;
-                       char mask_str[NR_CPUS];
-
-                       cpumask_scnprintf(mask_str, NR_CPUS, sd->span);
-                       seq_printf(seq, "domain%d %s", dcnt++, mask_str);
-                       for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES;
-                                       itype++) {
-                               seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu "
-                                               "%lu",
-                                   sd->lb_cnt[itype],
-                                   sd->lb_balanced[itype],
-                                   sd->lb_failed[itype],
-                                   sd->lb_imbalance[itype],
-                                   sd->lb_gained[itype],
-                                   sd->lb_hot_gained[itype],
-                                   sd->lb_nobusyq[itype],
-                                   sd->lb_nobusyg[itype]);
-                       }
-                       seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu"
-                           " %lu %lu %lu\n",
-                           sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
-                           sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
-                           sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
-                           sd->ttwu_wake_remote, sd->ttwu_move_affine,
-                           sd->ttwu_move_balance);
-               }
-               preempt_enable();
-#endif
-       }
-       return 0;
-}
-
-static int schedstat_open(struct inode *inode, struct file *file)
-{
-       unsigned int size = PAGE_SIZE * (1 + num_online_cpus() / 32);
-       char *buf = kmalloc(size, GFP_KERNEL);
-       struct seq_file *m;
-       int res;
-
-       if (!buf)
-               return -ENOMEM;
-       res = single_open(file, show_schedstat, NULL);
-       if (!res) {
-               m = file->private_data;
-               m->buf = buf;
-               m->size = size;
-       } else
-               kfree(buf);
-       return res;
-}
-
-const struct file_operations proc_schedstat_operations = {
-       .open    = schedstat_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
-
-/*
- * Expects runqueue lock to be held for atomicity of update
- */
-static inline void
-rq_sched_info_arrive(struct rq *rq, unsigned long delta_jiffies)
-{
-       if (rq) {
-               rq->rq_sched_info.run_delay += delta_jiffies;
-               rq->rq_sched_info.pcnt++;
-       }
-}
-
-/*
- * Expects runqueue lock to be held for atomicity of update
- */
-static inline void
-rq_sched_info_depart(struct rq *rq, unsigned long delta_jiffies)
-{
-       if (rq)
-               rq->rq_sched_info.cpu_time += delta_jiffies;
-}
-# define schedstat_inc(rq, field)      do { (rq)->field++; } while (0)
-# define schedstat_add(rq, field, amt) do { (rq)->field += (amt); } while (0)
-#else /* !CONFIG_SCHEDSTATS */
-static inline void
-rq_sched_info_arrive(struct rq *rq, unsigned long delta_jiffies)
-{}
-static inline void
-rq_sched_info_depart(struct rq *rq, unsigned long delta_jiffies)
-{}
-# define schedstat_inc(rq, field)      do { } while (0)
-# define schedstat_add(rq, field, amt) do { } while (0)
-#endif
-
 /*
  * this_rq_lock - lock this runqueue and disable interrupts.
  */
@@ -603,177 +535,172 @@ static inline struct rq *this_rq_lock(void)
        return rq;
 }
 
-#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
 /*
- * Called when a process is dequeued from the active array and given
- * the cpu.  We should note that with the exception of interactive
- * tasks, the expired queue will become the active queue after the active
- * queue is empty, without explicitly dequeuing and requeuing tasks in the
- * expired queue.  (Interactive tasks may be requeued directly to the
- * active queue, thus delaying tasks in the expired queue from running;
- * see scheduler_tick()).
- *
- * This function is only called from sched_info_arrive(), rather than
- * dequeue_task(). Even though a task may be queued and dequeued multiple
- * times as it is shuffled about, we're really interested in knowing how
- * long it was from the *first* time it was queued to the time that it
- * finally hit a cpu.
+ * CPU frequency is/was unstable - start new by setting prev_clock_raw:
  */
-static inline void sched_info_dequeued(struct task_struct *t)
+void sched_clock_unstable_event(void)
 {
-       t->sched_info.last_queued = 0;
+       unsigned long flags;
+       struct rq *rq;
+
+       rq = task_rq_lock(current, &flags);
+       rq->prev_clock_raw = sched_clock();
+       rq->clock_unstable_events++;
+       task_rq_unlock(rq, &flags);
 }
 
 /*
- * Called when a task finally hits the cpu.  We can now calculate how
- * long it was waiting to run.  We also note when it began so that we
- * can keep stats on how long its timeslice is.
+ * resched_task - mark a task 'to be rescheduled now'.
+ *
+ * On UP this means the setting of the need_resched flag, on SMP it
+ * might also involve a cross-CPU call to trigger the scheduler on
+ * the target CPU.
  */
-static void sched_info_arrive(struct task_struct *t)
+#ifdef CONFIG_SMP
+
+#ifndef tsk_is_polling
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+#endif
+
+static void resched_task(struct task_struct *p)
 {
-       unsigned long now = jiffies, delta_jiffies = 0;
+       int cpu;
+
+       assert_spin_locked(&task_rq(p)->lock);
+
+       if (unlikely(test_tsk_thread_flag(p, TIF_NEED_RESCHED)))
+               return;
+
+       set_tsk_thread_flag(p, TIF_NEED_RESCHED);
 
-       if (t->sched_info.last_queued)
-               delta_jiffies = now - t->sched_info.last_queued;
-       sched_info_dequeued(t);
-       t->sched_info.run_delay += delta_jiffies;
-       t->sched_info.last_arrival = now;
-       t->sched_info.pcnt++;
+       cpu = task_cpu(p);
+       if (cpu == smp_processor_id())
+               return;
 
-       rq_sched_info_arrive(task_rq(t), delta_jiffies);
+       /* NEED_RESCHED must be visible before we test polling */
+       smp_mb();
+       if (!tsk_is_polling(p))
+               smp_send_reschedule(cpu);
 }
 
-/*
- * Called when a process is queued into either the active or expired
- * array.  The time is noted and later used to determine how long we
- * had to wait for us to reach the cpu.  Since the expired queue will
- * become the active queue after active queue is empty, without dequeuing
- * and requeuing any tasks, we are interested in queuing to either. It
- * is unusual but not impossible for tasks to be dequeued and immediately
- * requeued in the same or another array: this can happen in sched_yield(),
- * set_user_nice(), and even load_balance() as it moves tasks from runqueue
- * to runqueue.
- *
- * This function is only called from enqueue_task(), but also only updates
- * the timestamp if it is already not set.  It's assumed that
- * sched_info_dequeued() will clear that stamp when appropriate.
- */
-static inline void sched_info_queued(struct task_struct *t)
+static void resched_cpu(int cpu)
 {
-       if (unlikely(sched_info_on()))
-               if (!t->sched_info.last_queued)
-                       t->sched_info.last_queued = jiffies;
+       struct rq *rq = cpu_rq(cpu);
+       unsigned long flags;
+
+       if (!spin_trylock_irqsave(&rq->lock, flags))
+               return;
+       resched_task(cpu_curr(cpu));
+       spin_unlock_irqrestore(&rq->lock, flags);
 }
+#else
+static inline void resched_task(struct task_struct *p)
+{
+       assert_spin_locked(&task_rq(p)->lock);
+       set_tsk_need_resched(p);
+}
+#endif
 
-/*
- * Called when a process ceases being the active-running process, either
- * voluntarily or involuntarily.  Now we can calculate how long we ran.
- */
-static inline void sched_info_depart(struct task_struct *t)
+static u64 div64_likely32(u64 divident, unsigned long divisor)
 {
-       unsigned long delta_jiffies = jiffies - t->sched_info.last_arrival;
+#if BITS_PER_LONG == 32
+       if (likely(divident <= 0xffffffffULL))
+               return (u32)divident / divisor;
+       do_div(divident, divisor);
 
-       t->sched_info.cpu_time += delta_jiffies;
-       rq_sched_info_depart(task_rq(t), delta_jiffies);
+       return divident;
+#else
+       return divident / divisor;
+#endif
 }
 
-/*
- * Called when tasks are switched involuntarily due, typically, to expiring
- * their time slice.  (This may also be called when switching to or from
- * the idle task.)  We are only called when prev != next.
- */
-static inline void
-__sched_info_switch(struct task_struct *prev, struct task_struct *next)
+#if BITS_PER_LONG == 32
+# define WMULT_CONST   (~0UL)
+#else
+# define WMULT_CONST   (1UL << 32)
+#endif
+
+#define WMULT_SHIFT    32
+
+static inline unsigned long
+calc_delta_mine(unsigned long delta_exec, unsigned long weight,
+               struct load_weight *lw)
 {
-       struct rq *rq = task_rq(prev);
+       u64 tmp;
+
+       if (unlikely(!lw->inv_weight))
+               lw->inv_weight = WMULT_CONST / lw->weight;
 
+       tmp = (u64)delta_exec * weight;
        /*
-        * prev now departs the cpu.  It's not interesting to record
-        * stats about how efficient we were at scheduling the idle
-        * process, however.
+        * Check whether we'd overflow the 64-bit multiplication:
         */
-       if (prev != rq->idle)
-               sched_info_depart(prev);
+       if (unlikely(tmp > WMULT_CONST)) {
+               tmp = ((tmp >> WMULT_SHIFT/2) * lw->inv_weight)
+                               >> (WMULT_SHIFT/2);
+       } else {
+               tmp = (tmp * lw->inv_weight) >> WMULT_SHIFT;
+       }
 
-       if (next != rq->idle)
-               sched_info_arrive(next);
-}
-static inline void
-sched_info_switch(struct task_struct *prev, struct task_struct *next)
-{
-       if (unlikely(sched_info_on()))
-               __sched_info_switch(prev, next);
+       return (unsigned long)min(tmp, (u64)sysctl_sched_runtime_limit);
 }
-#else
-#define sched_info_queued(t)           do { } while (0)
-#define sched_info_switch(t, next)     do { } while (0)
-#endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */
 
-/*
- * Adding/removing a task to/from a priority array:
- */
-static void dequeue_task(struct task_struct *p, struct prio_array *array)
+static inline unsigned long
+calc_delta_fair(unsigned long delta_exec, struct load_weight *lw)
 {
-       array->nr_active--;
-       list_del(&p->run_list);
-       if (list_empty(array->queue + p->prio))
-               __clear_bit(p->prio, array->bitmap);
+       return calc_delta_mine(delta_exec, NICE_0_LOAD, lw);
 }
 
-static void enqueue_task(struct task_struct *p, struct prio_array *array)
+static void update_load_add(struct load_weight *lw, unsigned long inc)
 {
-       sched_info_queued(p);
-       list_add_tail(&p->run_list, array->queue + p->prio);
-       __set_bit(p->prio, array->bitmap);
-       array->nr_active++;
-       p->array = array;
+       lw->weight += inc;
+       lw->inv_weight = 0;
 }
 
-/*
- * Put task to the end of the run list without the overhead of dequeue
- * followed by enqueue.
- */
-static void requeue_task(struct task_struct *p, struct prio_array *array)
+static void update_load_sub(struct load_weight *lw, unsigned long dec)
 {
-       list_move_tail(&p->run_list, array->queue + p->prio);
+       lw->weight -= dec;
+       lw->inv_weight = 0;
 }
 
-static inline void
-enqueue_task_head(struct task_struct *p, struct prio_array *array)
+static void __update_curr_load(struct rq *rq, struct load_stat *ls)
 {
-       list_add(&p->run_list, array->queue + p->prio);
-       __set_bit(p->prio, array->bitmap);
-       array->nr_active++;
-       p->array = array;
+       if (rq->curr != rq->idle && ls->load.weight) {
+               ls->delta_exec += ls->delta_stat;
+               ls->delta_fair += calc_delta_fair(ls->delta_stat, &ls->load);
+               ls->delta_stat = 0;
+       }
 }
 
 /*
- * __normal_prio - return the priority that is based on the static
- * priority but is modified by bonuses/penalties.
- *
- * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
- * into the -5 ... 0 ... +5 bonus/penalty range.
+ * Update delta_exec, delta_fair fields for rq.
  *
- * We use 25% of the full 0...39 priority range so that:
+ * delta_fair clock advances at a rate inversely proportional to
+ * total load (rq->ls.load.weight) on the runqueue, while
+ * delta_exec advances at the same rate as wall-clock (provided
+ * cpu is not idle).
  *
- * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs.
- * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks.
+ * delta_exec / delta_fair is a measure of the (smoothened) load on this
+ * runqueue over any given interval. This (smoothened) load is used
+ * during load balance.
  *
- * Both properties are important to certain workloads.
+ * This function is called /before/ updating rq->ls.load
+ * and when switching tasks.
  */
-
-static inline int __normal_prio(struct task_struct *p)
+static void update_curr_load(struct rq *rq, u64 now)
 {
-       int bonus, prio;
+       struct load_stat *ls = &rq->ls;
+       u64 start;
 
-       bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;
-
-       prio = p->static_prio - bonus;
-       if (prio < MAX_RT_PRIO)
-               prio = MAX_RT_PRIO;
-       if (prio > MAX_PRIO-1)
-               prio = MAX_PRIO-1;
-       return prio;
+       start = ls->load_update_start;
+       ls->load_update_start = now;
+       ls->delta_stat += now - start;
+       /*
+        * Stagger updates to ls->delta_fair. Very frequent updates
+        * can be expensive.
+        */
+       if (ls->delta_stat >= sysctl_sched_stat_granularity)
+               __update_curr_load(rq, ls);
 }
 
 /*
@@ -791,53 +718,146 @@ static inline int __normal_prio(struct task_struct *p)
  * this code will need modification
  */
 #define TIME_SLICE_NICE_ZERO DEF_TIMESLICE
-#define LOAD_WEIGHT(lp) \
+#define load_weight(lp) \
        (((lp) * SCHED_LOAD_SCALE) / TIME_SLICE_NICE_ZERO)
 #define PRIO_TO_LOAD_WEIGHT(prio) \
-       LOAD_WEIGHT(static_prio_timeslice(prio))
+       load_weight(static_prio_timeslice(prio))
 #define RTPRIO_TO_LOAD_WEIGHT(rp) \
-       (PRIO_TO_LOAD_WEIGHT(MAX_RT_PRIO) + LOAD_WEIGHT(rp))
+       (PRIO_TO_LOAD_WEIGHT(MAX_RT_PRIO) + load_weight(rp))
 
-static void set_load_weight(struct task_struct *p)
-{
-       if (has_rt_policy(p)) {
-#ifdef CONFIG_SMP
-               if (p == task_rq(p)->migration_thread)
-                       /*
-                        * The migration thread does the actual balancing.
-                        * Giving its load any weight will skew balancing
-                        * adversely.
-                        */
-                       p->load_weight = 0;
-               else
-#endif
-                       p->load_weight = RTPRIO_TO_LOAD_WEIGHT(p->rt_priority);
-       } else
-               p->load_weight = PRIO_TO_LOAD_WEIGHT(p->static_prio);
-}
+#define WEIGHT_IDLEPRIO                2
+#define WMULT_IDLEPRIO         (1 << 31)
+
+/*
+ * Nice levels are multiplicative, with a gentle 10% change for every
+ * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
+ * nice 1, it will get ~10% less CPU time than another CPU-bound task
+ * that remained on nice 0.
+ *
+ * The "10% effect" is relative and cumulative: from _any_ nice level,
+ * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
+ * it's +10% CPU usage.
+ */
+static const int prio_to_weight[40] = {
+/* -20 */ 88818, 71054, 56843, 45475, 36380, 29104, 23283, 18626, 14901, 11921,
+/* -10 */  9537,  7629,  6103,  4883,  3906,  3125,  2500,  2000,  1600,  1280,
+/*   0 */  NICE_0_LOAD /* 1024 */,
+/*   1 */          819,   655,   524,   419,   336,   268,   215,   172,   137,
+/*  10 */   110,    87,    70,    56,    45,    36,    29,    23,    18,    15,
+};
+
+static const u32 prio_to_wmult[40] = {
+       48356,   60446,   75558,   94446,  118058,  147573,
+       184467,  230589,  288233,  360285,  450347,
+       562979,  703746,  879575, 1099582, 1374389,
+       717986, 2147483, 2684354, 3355443, 4194304,
+       244160, 6557201, 8196502, 10250518, 12782640,
+       16025997, 19976592, 24970740, 31350126, 39045157,
+       49367440, 61356675, 76695844, 95443717, 119304647,
+       148102320, 186737708, 238609294, 286331153,
+};
 
 static inline void
-inc_raw_weighted_load(struct rq *rq, const struct task_struct *p)
+inc_load(struct rq *rq, const struct task_struct *p, u64 now)
 {
-       rq->raw_weighted_load += p->load_weight;
+       update_curr_load(rq, now);
+       update_load_add(&rq->ls.load, p->se.load.weight);
 }
 
 static inline void
-dec_raw_weighted_load(struct rq *rq, const struct task_struct *p)
+dec_load(struct rq *rq, const struct task_struct *p, u64 now)
 {
-       rq->raw_weighted_load -= p->load_weight;
+       update_curr_load(rq, now);
+       update_load_sub(&rq->ls.load, p->se.load.weight);
 }
 
-static inline void inc_nr_running(struct task_struct *p, struct rq *rq)
+static inline void inc_nr_running(struct task_struct *p, struct rq *rq, u64 now)
 {
        rq->nr_running++;
-       inc_raw_weighted_load(rq, p);
+       inc_load(rq, p, now);
 }
 
-static inline void dec_nr_running(struct task_struct *p, struct rq *rq)
+static inline void dec_nr_running(struct task_struct *p, struct rq *rq, u64 now)
 {
        rq->nr_running--;
-       dec_raw_weighted_load(rq, p);
+       dec_load(rq, p, now);
+}
+
+static void activate_task(struct rq *rq, struct task_struct *p, int wakeup);
+
+/*
+ * runqueue iterator, to support SMP load-balancing between different
+ * scheduling classes, without having to expose their internal data
+ * structures to the load-balancing proper:
+ */
+struct rq_iterator {
+       void *arg;
+       struct task_struct *(*start)(void *);
+       struct task_struct *(*next)(void *);
+};
+
+static int balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
+                     unsigned long max_nr_move, unsigned long max_load_move,
+                     struct sched_domain *sd, enum cpu_idle_type idle,
+                     int *all_pinned, unsigned long *load_moved,
+                     int this_best_prio, int best_prio, int best_prio_seen,
+                     struct rq_iterator *iterator);
+
+#include "sched_stats.h"
+#include "sched_rt.c"
+#include "sched_fair.c"
+#include "sched_idletask.c"
+#ifdef CONFIG_SCHED_DEBUG
+# include "sched_debug.c"
+#endif
+
+#define sched_class_highest (&rt_sched_class)
+
+static void set_load_weight(struct task_struct *p)
+{
+       task_rq(p)->cfs.wait_runtime -= p->se.wait_runtime;
+       p->se.wait_runtime = 0;
+
+       if (task_has_rt_policy(p)) {
+               p->se.load.weight = prio_to_weight[0] * 2;
+               p->se.load.inv_weight = prio_to_wmult[0] >> 1;
+               return;
+       }
+
+       /*
+        * SCHED_IDLE tasks get minimal weight:
+        */
+       if (p->policy == SCHED_IDLE) {
+               p->se.load.weight = WEIGHT_IDLEPRIO;
+               p->se.load.inv_weight = WMULT_IDLEPRIO;
+               return;
+       }
+
+       p->se.load.weight = prio_to_weight[p->static_prio - MAX_RT_PRIO];
+       p->se.load.inv_weight = prio_to_wmult[p->static_prio - MAX_RT_PRIO];
+}
+
+static void
+enqueue_task(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
+{
+       sched_info_queued(p);
+       p->sched_class->enqueue_task(rq, p, wakeup, now);
+       p->se.on_rq = 1;
+}
+
+static void
+dequeue_task(struct rq *rq, struct task_struct *p, int sleep, u64 now)
+{
+       p->sched_class->dequeue_task(rq, p, sleep, now);
+       p->se.on_rq = 0;
+}
+
+/*
+ * __normal_prio - return the priority that is based on the static prio
+ */
+static inline int __normal_prio(struct task_struct *p)
+{
+       return p->static_prio;
 }
 
 /*
@@ -851,7 +871,7 @@ static inline int normal_prio(struct task_struct *p)
 {
        int prio;
 
-       if (has_rt_policy(p))
+       if (task_has_rt_policy(p))
                prio = MAX_RT_PRIO-1 - p->rt_priority;
        else
                prio = __normal_prio(p);
@@ -879,222 +899,47 @@ static int effective_prio(struct task_struct *p)
 }
 
 /*
- * __activate_task - move a task to the runqueue.
- */
-static void __activate_task(struct task_struct *p, struct rq *rq)
-{
-       struct prio_array *target = rq->active;
-
-       if (batch_task(p))
-               target = rq->expired;
-       enqueue_task(p, target);
-       inc_nr_running(p, rq);
-}
-
-/*
- * __activate_idle_task - move idle task to the _front_ of runqueue.
- */
-static inline void __activate_idle_task(struct task_struct *p, struct rq *rq)
-{
-       enqueue_task_head(p, rq->active);
-       inc_nr_running(p, rq);
-}
-
-/*
- * Recalculate p->normal_prio and p->prio after having slept,
- * updating the sleep-average too:
+ * activate_task - move a task to the runqueue.
  */
-static int recalc_task_prio(struct task_struct *p, unsigned long long now)
+static void activate_task(struct rq *rq, struct task_struct *p, int wakeup)
 {
-       /* Caller must always ensure 'now >= p->timestamp' */
-       unsigned long sleep_time = now - p->timestamp;
-
-       if (batch_task(p))
-               sleep_time = 0;
-
-       if (likely(sleep_time > 0)) {
-               /*
-                * This ceiling is set to the lowest priority that would allow
-                * a task to be reinserted into the active array on timeslice
-                * completion.
-                */
-               unsigned long ceiling = INTERACTIVE_SLEEP(p);
-
-               if (p->mm && sleep_time > ceiling && p->sleep_avg < ceiling) {
-                       /*
-                        * Prevents user tasks from achieving best priority
-                        * with one single large enough sleep.
-                        */
-                       p->sleep_avg = ceiling;
-                       /*
-                        * Using INTERACTIVE_SLEEP() as a ceiling places a
-                        * nice(0) task 1ms sleep away from promotion, and
-                        * gives it 700ms to round-robin with no chance of
-                        * being demoted.  This is more than generous, so
-                        * mark this sleep as non-interactive to prevent the
-                        * on-runqueue bonus logic from intervening should
-                        * this task not receive cpu immediately.
-                        */
-                       p->sleep_type = SLEEP_NONINTERACTIVE;
-               } else {
-                       /*
-                        * Tasks waking from uninterruptible sleep are
-                        * limited in their sleep_avg rise as they
-                        * are likely to be waiting on I/O
-                        */
-                       if (p->sleep_type == SLEEP_NONINTERACTIVE && p->mm) {
-                               if (p->sleep_avg >= ceiling)
-                                       sleep_time = 0;
-                               else if (p->sleep_avg + sleep_time >=
-                                        ceiling) {
-                                               p->sleep_avg = ceiling;
-                                               sleep_time = 0;
-                               }
-                       }
-
-                       /*
-                        * This code gives a bonus to interactive tasks.
-                        *
-                        * The boost works by updating the 'average sleep time'
-                        * value here, based on ->timestamp. The more time a
-                        * task spends sleeping, the higher the average gets -
-                        * and the higher the priority boost gets as well.
-                        */
-                       p->sleep_avg += sleep_time;
+       u64 now = rq_clock(rq);
 
-               }
-               if (p->sleep_avg > NS_MAX_SLEEP_AVG)
-                       p->sleep_avg = NS_MAX_SLEEP_AVG;
-       }
+       if (p->state == TASK_UNINTERRUPTIBLE)
+               rq->nr_uninterruptible--;
 
-       return effective_prio(p);
+       enqueue_task(rq, p, wakeup, now);
+       inc_nr_running(p, rq, now);
 }
 
 /*
- * activate_task - move a task to the runqueue and do priority recalculation
- *
- * Update all the scheduling statistics stuff. (sleep average
- * calculation, priority modifiers, etc.)
+ * activate_idle_task - move idle task to the _front_ of runqueue.
  */
-static void activate_task(struct task_struct *p, struct rq *rq, int local)
+static inline void activate_idle_task(struct task_struct *p, struct rq *rq)
 {
-       unsigned long long now;
-
-       if (rt_task(p))
-               goto out;
-
-       now = sched_clock();
-#ifdef CONFIG_SMP
-       if (!local) {
-               /* Compensate for drifting sched_clock */
-               struct rq *this_rq = this_rq();
-               now = (now - this_rq->most_recent_timestamp)
-                       + rq->most_recent_timestamp;
-       }
-#endif
+       u64 now = rq_clock(rq);
 
-       /*
-        * Sleep time is in units of nanosecs, so shift by 20 to get a
-        * milliseconds-range estimation of the amount of time that the task
-        * spent sleeping:
-        */
-       if (unlikely(prof_on == SLEEP_PROFILING)) {
-               if (p->state == TASK_UNINTERRUPTIBLE)
-                       profile_hits(SLEEP_PROFILING, (void *)get_wchan(p),
-                                    (now - p->timestamp) >> 20);
-       }
-
-       p->prio = recalc_task_prio(p, now);
+       if (p->state == TASK_UNINTERRUPTIBLE)
+               rq->nr_uninterruptible--;
 
-       /*
-        * This checks to make sure it's not an uninterruptible task
-        * that is now waking up.
-        */
-       if (p->sleep_type == SLEEP_NORMAL) {
-               /*
-                * Tasks which were woken up by interrupts (ie. hw events)
-                * are most likely of interactive nature. So we give them
-                * the credit of extending their sleep time to the period
-                * of time they spend on the runqueue, waiting for execution
-                * on a CPU, first time around:
-                */
-               if (in_interrupt())
-                       p->sleep_type = SLEEP_INTERRUPTED;
-               else {
-                       /*
-                        * Normal first-time wakeups get a credit too for
-                        * on-runqueue time, but it will be weighted down:
-                        */
-                       p->sleep_type = SLEEP_INTERACTIVE;
-               }
-       }
-       p->timestamp = now;
-out:
-       __activate_task(p, rq);
+       enqueue_task(rq, p, 0, now);
+       inc_nr_running(p, rq, now);
 }
 
 /*
  * deactivate_task - remove a task from the runqueue.
  */
-static void deactivate_task(struct task_struct *p, struct rq *rq)
-{
-       dec_nr_running(p, rq);
-       dequeue_task(p, p->array);
-       p->array = NULL;
-}
-
-/*
- * resched_task - mark a task 'to be rescheduled now'.
- *
- * On UP this means the setting of the need_resched flag, on SMP it
- * might also involve a cross-CPU call to trigger the scheduler on
- * the target CPU.
- */
-#ifdef CONFIG_SMP
-
-#ifndef tsk_is_polling
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-#endif
-
-static void resched_task(struct task_struct *p)
+static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep)
 {
-       int cpu;
+       u64 now = rq_clock(rq);
 
-       assert_spin_locked(&task_rq(p)->lock);
+       if (p->state == TASK_UNINTERRUPTIBLE)
+               rq->nr_uninterruptible++;
 
-       if (unlikely(test_tsk_thread_flag(p, TIF_NEED_RESCHED)))
-               return;
-
-       set_tsk_thread_flag(p, TIF_NEED_RESCHED);
-
-       cpu = task_cpu(p);
-       if (cpu == smp_processor_id())
-               return;
-
-       /* NEED_RESCHED must be visible before we test polling */
-       smp_mb();
-       if (!tsk_is_polling(p))
-               smp_send_reschedule(cpu);
+       dequeue_task(rq, p, sleep, now);
+       dec_nr_running(p, rq, now);
 }
 
-static void resched_cpu(int cpu)
-{
-       struct rq *rq = cpu_rq(cpu);
-       unsigned long flags;
-
-       if (!spin_trylock_irqsave(&rq->lock, flags))
-               return;
-       resched_task(cpu_curr(cpu));
-       spin_unlock_irqrestore(&rq->lock, flags);
-}
-#else
-static inline void resched_task(struct task_struct *p)
-{
-       assert_spin_locked(&task_rq(p)->lock);
-       set_tsk_need_resched(p);
-}
-#endif
-
 /**
  * task_curr - is this task currently executing on a CPU?
  * @p: the task in question.
@@ -1107,10 +952,42 @@ inline int task_curr(const struct task_struct *p)
 /* Used instead of source_load when we know the type == 0 */
 unsigned long weighted_cpuload(const int cpu)
 {
-       return cpu_rq(cpu)->raw_weighted_load;
+       return cpu_rq(cpu)->ls.load.weight;
+}
+
+static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
+{
+#ifdef CONFIG_SMP
+       task_thread_info(p)->cpu = cpu;
+       set_task_cfs_rq(p);
+#endif
 }
 
 #ifdef CONFIG_SMP
+
+void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
+{
+       int old_cpu = task_cpu(p);
+       struct rq *old_rq = cpu_rq(old_cpu), *new_rq = cpu_rq(new_cpu);
+       u64 clock_offset, fair_clock_offset;
+
+       clock_offset = old_rq->clock - new_rq->clock;
+       fair_clock_offset = old_rq->cfs.fair_clock -
+                                                new_rq->cfs.fair_clock;
+       if (p->se.wait_start)
+               p->se.wait_start -= clock_offset;
+       if (p->se.wait_start_fair)
+               p->se.wait_start_fair -= fair_clock_offset;
+       if (p->se.sleep_start)
+               p->se.sleep_start -= clock_offset;
+       if (p->se.block_start)
+               p->se.block_start -= clock_offset;
+       if (p->se.sleep_start_fair)
+               p->se.sleep_start_fair -= fair_clock_offset;
+
+       __set_task_cpu(p, new_cpu);
+}
+
 struct migration_req {
        struct list_head list;
 
@@ -1133,7 +1010,7 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req)
         * If the task is not on a runqueue (and not running), then
         * it is sufficient to simply update the task's cpu field.
         */
-       if (!p->array && !task_running(rq, p)) {
+       if (!p->se.on_rq && !task_running(rq, p)) {
                set_task_cpu(p, dest_cpu);
                return 0;
        }
@@ -1158,9 +1035,8 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req)
 void wait_task_inactive(struct task_struct *p)
 {
        unsigned long flags;
+       int running, on_rq;
        struct rq *rq;
-       struct prio_array *array;
-       int running;
 
 repeat:
        /*
@@ -1192,7 +1068,7 @@ repeat:
         */
        rq = task_rq_lock(p, &flags);
        running = task_running(rq, p);
-       array = p->array;
+       on_rq = p->se.on_rq;
        task_rq_unlock(rq, &flags);
 
        /*
@@ -1215,7 +1091,7 @@ repeat:
         * running right now), it's preempted, and we should
         * yield - it could be a while.
         */
-       if (unlikely(array)) {
+       if (unlikely(on_rq)) {
                yield();
                goto repeat;
        }
@@ -1261,11 +1137,12 @@ void kick_process(struct task_struct *p)
 static inline unsigned long source_load(int cpu, int type)
 {
        struct rq *rq = cpu_rq(cpu);
+       unsigned long total = weighted_cpuload(cpu);
 
        if (type == 0)
-               return rq->raw_weighted_load;
+               return total;
 
-       return min(rq->cpu_load[type-1], rq->raw_weighted_load);
+       return min(rq->cpu_load[type-1], total);
 }
 
 /*
@@ -1275,11 +1152,12 @@ static inline unsigned long source_load(int cpu, int type)
 static inline unsigned long target_load(int cpu, int type)
 {
        struct rq *rq = cpu_rq(cpu);
+       unsigned long total = weighted_cpuload(cpu);
 
        if (type == 0)
-               return rq->raw_weighted_load;
+               return total;
 
-       return max(rq->cpu_load[type-1], rq->raw_weighted_load);
+       return max(rq->cpu_load[type-1], total);
 }
 
 /*
@@ -1288,9 +1166,10 @@ static inline unsigned long target_load(int cpu, int type)
 static inline unsigned long cpu_avg_load_per_task(int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
+       unsigned long total = weighted_cpuload(cpu);
        unsigned long n = rq->nr_running;
 
-       return n ? rq->raw_weighted_load / n : SCHED_LOAD_SCALE;
+       return n ? total / n : SCHED_LOAD_SCALE;
 }
 
 /*
@@ -1392,9 +1271,9 @@ static int sched_balance_self(int cpu, int flag)
        struct sched_domain *tmp, *sd = NULL;
 
        for_each_domain(cpu, tmp) {
-               /*
-                * If power savings logic is enabled for a domain, stop there.
-                */
+               /*
+                * If power savings logic is enabled for a domain, stop there.
+                */
                if (tmp->flags & SD_POWERSAVINGS_BALANCE)
                        break;
                if (tmp->flags & flag)
@@ -1477,9 +1356,9 @@ static int wake_idle(int cpu, struct task_struct *p)
                                if (idle_cpu(i))
                                        return i;
                        }
-               }
-               else
+               } else {
                        break;
+               }
        }
        return cpu;
 }
@@ -1521,7 +1400,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
        if (!(old_state & state))
                goto out;
 
-       if (p->array)
+       if (p->se.on_rq)
                goto out_running;
 
        cpu = task_cpu(p);
@@ -1576,11 +1455,11 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
                         * of the current CPU:
                         */
                        if (sync)
-                               tl -= current->load_weight;
+                               tl -= current->se.load.weight;
 
                        if ((tl <= load &&
                                tl + target_load(cpu, idx) <= tl_per_task) ||
-                               100*(tl + p->load_weight) <= imbalance*load) {
+                              100*(tl + p->se.load.weight) <= imbalance*load) {
                                /*
                                 * This domain has SD_WAKE_AFFINE and
                                 * p is cache cold in this domain, and
@@ -1614,7 +1493,7 @@ out_set_cpu:
                old_state = p->state;
                if (!(old_state & state))
                        goto out;
-               if (p->array)
+               if (p->se.on_rq)
                        goto out_running;
 
                this_cpu = smp_processor_id();
@@ -1623,25 +1502,7 @@ out_set_cpu:
 
 out_activate:
 #endif /* CONFIG_SMP */
-       if (old_state == TASK_UNINTERRUPTIBLE) {
-               rq->nr_uninterruptible--;
-               /*
-                * Tasks on involuntary sleep don't earn
-                * sleep_avg beyond just interactive state.
-                */
-               p->sleep_type = SLEEP_NONINTERACTIVE;
-       } else
-
-       /*
-        * Tasks that have marked their sleep as noninteractive get
-        * woken up with their sleep average not weighted in an
-        * interactive way.
-        */
-               if (old_state & TASK_NONINTERACTIVE)
-                       p->sleep_type = SLEEP_NONINTERACTIVE;
-
-
-       activate_task(p, rq, cpu == this_cpu);
+       activate_task(rq, p, 1);
        /*
         * Sync wakeups (i.e. those types of wakeups where the waker
         * has indicated that it will leave the CPU in short order)
@@ -1650,10 +1511,8 @@ out_activate:
         * the waker guarantees that the freshly woken up task is going
         * to be considered on this CPU.)
         */
-       if (!sync || cpu != this_cpu) {
-               if (TASK_PREEMPTS_CURR(p, rq))
-                       resched_task(rq->curr);
-       }
+       if (!sync || cpu != this_cpu)
+               check_preempt_curr(rq, p);
        success = 1;
 
 out_running:
@@ -1676,19 +1535,36 @@ int fastcall wake_up_state(struct task_struct *p, unsigned int state)
        return try_to_wake_up(p, state, 0);
 }
 
-static void task_running_tick(struct rq *rq, struct task_struct *p);
 /*
  * Perform scheduler related setup for a newly forked process p.
  * p is forked by current.
- */
-void fastcall sched_fork(struct task_struct *p, int clone_flags)
-{
-       int cpu = get_cpu();
+ *
+ * __sched_fork() is basic setup used by init_idle() too:
+ */
+static void __sched_fork(struct task_struct *p)
+{
+       p->se.wait_start_fair           = 0;
+       p->se.wait_start                = 0;
+       p->se.exec_start                = 0;
+       p->se.sum_exec_runtime          = 0;
+       p->se.delta_exec                = 0;
+       p->se.delta_fair_run            = 0;
+       p->se.delta_fair_sleep          = 0;
+       p->se.wait_runtime              = 0;
+       p->se.sum_wait_runtime          = 0;
+       p->se.sum_sleep_runtime         = 0;
+       p->se.sleep_start               = 0;
+       p->se.sleep_start_fair          = 0;
+       p->se.block_start               = 0;
+       p->se.sleep_max                 = 0;
+       p->se.block_max                 = 0;
+       p->se.exec_max                  = 0;
+       p->se.wait_max                  = 0;
+       p->se.wait_runtime_overruns     = 0;
+       p->se.wait_runtime_underruns    = 0;
 
-#ifdef CONFIG_SMP
-       cpu = sched_balance_self(cpu, SD_BALANCE_FORK);
-#endif
-       set_task_cpu(p, cpu);
+       INIT_LIST_HEAD(&p->run_list);
+       p->se.on_rq = 0;
 
        /*
         * We mark the process as running here, but have not actually
@@ -1697,16 +1573,29 @@ void fastcall sched_fork(struct task_struct *p, int clone_flags)
         * event cannot wake it up and insert it on the runqueue either.
         */
        p->state = TASK_RUNNING;
+}
+
+/*
+ * fork()/clone()-time setup:
+ */
+void sched_fork(struct task_struct *p, int clone_flags)
+{
+       int cpu = get_cpu();
+
+       __sched_fork(p);
+
+#ifdef CONFIG_SMP
+       cpu = sched_balance_self(cpu, SD_BALANCE_FORK);
+#endif
+       __set_task_cpu(p, cpu);
 
        /*
         * Make sure we do not leak PI boosting priority to the child:
         */
        p->prio = current->normal_prio;
 
-       INIT_LIST_HEAD(&p->run_list);
-       p->array = NULL;
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
-       if (unlikely(sched_info_on()))
+       if (likely(sched_info_on()))
                memset(&p->sched_info, 0, sizeof(p->sched_info));
 #endif
 #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
@@ -1716,33 +1605,15 @@ void fastcall sched_fork(struct task_struct *p, int clone_flags)
        /* Want to start with kernel preemption disabled. */
        task_thread_info(p)->preempt_count = 1;
 #endif
-       /*
-        * Share the timeslice between parent and child, thus the
-        * total amount of pending timeslices in the system doesn't change,
-        * resulting in more scheduling fairness.
-        */
-       local_irq_disable();
-       p->time_slice = (current->time_slice + 1) >> 1;
-       /*
-        * The remainder of the first timeslice might be recovered by
-        * the parent if the child exits early enough.
-        */
-       p->first_time_slice = 1;
-       current->time_slice >>= 1;
-       p->timestamp = sched_clock();
-       if (unlikely(!current->time_slice)) {
-               /*
-                * This case is rare, it happens when the parent has only
-                * a single jiffy left from its timeslice. Taking the
-                * runqueue lock is not a problem.
-                */
-               current->time_slice = 1;
-               task_running_tick(cpu_rq(cpu), current);
-       }
-       local_irq_enable();
        put_cpu();
 }
 
+/*
+ * After fork, child runs first. (default) If set to 0 then
+ * parent will (try to) run first.
+ */
+unsigned int __read_mostly sysctl_sched_child_runs_first = 1;
+
 /*
  * wake_up_new_task - wake up a newly created task for the first time.
  *
@@ -1752,107 +1623,27 @@ void fastcall sched_fork(struct task_struct *p, int clone_flags)
  */
 void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
 {
-       struct rq *rq, *this_rq;
        unsigned long flags;
-       int this_cpu, cpu;
+       struct rq *rq;
+       int this_cpu;
 
        rq = task_rq_lock(p, &flags);
        BUG_ON(p->state != TASK_RUNNING);
-       this_cpu = smp_processor_id();
-       cpu = task_cpu(p);
-
-       /*
-        * We decrease the sleep average of forking parents
-        * and children as well, to keep max-interactive tasks
-        * from forking tasks that are max-interactive. The parent
-        * (current) is done further down, under its lock.
-        */
-       p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) *
-               CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
+       this_cpu = smp_processor_id(); /* parent's CPU */
 
        p->prio = effective_prio(p);
 
-       if (likely(cpu == this_cpu)) {
-               if (!(clone_flags & CLONE_VM)) {
-                       /*
-                        * The VM isn't cloned, so we're in a good position to
-                        * do child-runs-first in anticipation of an exec. This
-                        * usually avoids a lot of COW overhead.
-                        */
-                       if (unlikely(!current->array))
-                               __activate_task(p, rq);
-                       else {
-                               p->prio = current->prio;
-                               p->normal_prio = current->normal_prio;
-                               list_add_tail(&p->run_list, &current->run_list);
-                               p->array = current->array;
-                               p->array->nr_active++;
-                               inc_nr_running(p, rq);
-                       }
-                       set_need_resched();
-               } else
-                       /* Run child last */
-                       __activate_task(p, rq);
-               /*
-                * We skip the following code due to cpu == this_cpu
-                *
-                *   task_rq_unlock(rq, &flags);
-                *   this_rq = task_rq_lock(current, &flags);
-                */
-               this_rq = rq;
+       if (!sysctl_sched_child_runs_first || (clone_flags & CLONE_VM) ||
+                       task_cpu(p) != this_cpu || !current->se.on_rq) {
+               activate_task(rq, p, 0);
        } else {
-               this_rq = cpu_rq(this_cpu);
-
-               /*
-                * Not the local CPU - must adjust timestamp. This should
-                * get optimised away in the !CONFIG_SMP case.
-                */
-               p->timestamp = (p->timestamp - this_rq->most_recent_timestamp)
-                                       + rq->most_recent_timestamp;
-               __activate_task(p, rq);
-               if (TASK_PREEMPTS_CURR(p, rq))
-                       resched_task(rq->curr);
-
                /*
-                * Parent and child are on different CPUs, now get the
-                * parent runqueue to update the parent's ->sleep_avg:
+                * Let the scheduling class do new task startup
+                * management (if any):
                 */
-               task_rq_unlock(rq, &flags);
-               this_rq = task_rq_lock(current, &flags);
-       }
-       current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
-               PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
-       task_rq_unlock(this_rq, &flags);
-}
-
-/*
- * Potentially available exiting-child timeslices are
- * retrieved here - this way the parent does not get
- * penalized for creating too many threads.
- *
- * (this cannot be used to 'generate' timeslices
- * artificially, because any timeslice recovered here
- * was given away by the parent in the first place.)
- */
-void fastcall sched_exit(struct task_struct *p)
-{
-       unsigned long flags;
-       struct rq *rq;
-
-       /*
-        * If the child was a (relative-) CPU hog then decrease
-        * the sleep_avg of the parent as well.
-        */
-       rq = task_rq_lock(p->parent, &flags);
-       if (p->first_time_slice && task_cpu(p) == task_cpu(p->parent)) {
-               p->parent->time_slice += p->time_slice;
-               if (unlikely(p->parent->time_slice > task_timeslice(p)))
-                       p->parent->time_slice = task_timeslice(p);
+               p->sched_class->task_new(rq, p);
        }
-       if (p->sleep_avg < p->parent->sleep_avg)
-               p->parent->sleep_avg = p->parent->sleep_avg /
-               (EXIT_WEIGHT + 1) * EXIT_WEIGHT + p->sleep_avg /
-               (EXIT_WEIGHT + 1);
+       check_preempt_curr(rq, p);
        task_rq_unlock(rq, &flags);
 }
 
@@ -1917,7 +1708,7 @@ static inline void finish_task_switch(struct rq *rq, struct task_struct *prev)
                /*
                 * Remove function-return probe instances associated with this
                 * task and put them back on the free list.
-                */
+                */
                kprobe_flush_task(prev);
                put_task_struct(prev);
        }
@@ -1945,13 +1736,15 @@ asmlinkage void schedule_tail(struct task_struct *prev)
  * context_switch - switch to the new MM and the new
  * thread's register state.
  */
-static inline struct task_struct *
+static inline void
 context_switch(struct rq *rq, struct task_struct *prev,
               struct task_struct *next)
 {
-       struct mm_struct *mm = next->mm;
-       struct mm_struct *oldmm = prev->active_mm;
+       struct mm_struct *mm, *oldmm;
 
+       prepare_task_switch(rq, next);
+       mm = next->mm;
+       oldmm = prev->active_mm;
        /*
         * For paravirt, this is coupled with an exit in switch_to to
         * combine the page table reload and the switch backend into
@@ -1959,16 +1752,15 @@ context_switch(struct rq *rq, struct task_struct *prev,
         */
        arch_enter_lazy_cpu_mode();
 
-       if (!mm) {
+       if (unlikely(!mm)) {
                next->active_mm = oldmm;
                atomic_inc(&oldmm->mm_count);
                enter_lazy_tlb(oldmm, next);
        } else
                switch_mm(oldmm, mm, next);
 
-       if (!prev->mm) {
+       if (unlikely(!prev->mm)) {
                prev->active_mm = NULL;
-               WARN_ON(rq->prev_mm);
                rq->prev_mm = oldmm;
        }
        /*
@@ -1984,7 +1776,13 @@ context_switch(struct rq *rq, struct task_struct *prev,
        /* Here we just switch the register state and the stack. */
        switch_to(prev, next, prev);
 
-       return prev;
+       barrier();
+       /*
+        * this_rq must be evaluated again because prev may have moved
+        * CPUs since it called schedule(), thus the 'rq' on its stack
+        * frame will be invalid.
+        */
+       finish_task_switch(this_rq(), prev);
 }
 
 /*
@@ -2057,17 +1855,65 @@ unsigned long nr_active(void)
        return running + uninterruptible;
 }
 
-#ifdef CONFIG_SMP
-
 /*
- * Is this task likely cache-hot:
+ * Update rq->cpu_load[] statistics. This function is usually called every
+ * scheduler tick (TICK_NSEC).
  */
-static inline int
-task_hot(struct task_struct *p, unsigned long long now, struct sched_domain *sd)
+static void update_cpu_load(struct rq *this_rq)
 {
-       return (long long)(now - p->last_ran) < (long long)sd->cache_hot_time;
+       u64 fair_delta64, exec_delta64, idle_delta64, sample_interval64, tmp64;
+       unsigned long total_load = this_rq->ls.load.weight;
+       unsigned long this_load =  total_load;
+       struct load_stat *ls = &this_rq->ls;
+       u64 now = __rq_clock(this_rq);
+       int i, scale;
+
+       this_rq->nr_load_updates++;
+       if (unlikely(!(sysctl_sched_features & SCHED_FEAT_PRECISE_CPU_LOAD)))
+               goto do_avg;
+
+       /* Update delta_fair/delta_exec fields first */
+       update_curr_load(this_rq, now);
+
+       fair_delta64 = ls->delta_fair + 1;
+       ls->delta_fair = 0;
+
+       exec_delta64 = ls->delta_exec + 1;
+       ls->delta_exec = 0;
+
+       sample_interval64 = now - ls->load_update_last;
+       ls->load_update_last = now;
+
+       if ((s64)sample_interval64 < (s64)TICK_NSEC)
+               sample_interval64 = TICK_NSEC;
+
+       if (exec_delta64 > sample_interval64)
+               exec_delta64 = sample_interval64;
+
+       idle_delta64 = sample_interval64 - exec_delta64;
+
+       tmp64 = div64_64(SCHED_LOAD_SCALE * exec_delta64, fair_delta64);
+       tmp64 = div64_64(tmp64 * exec_delta64, sample_interval64);
+
+       this_load = (unsigned long)tmp64;
+
+do_avg:
+
+       /* Update our load: */
+       for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
+               unsigned long old_load, new_load;
+
+               /* scale is effectively 1 << i now, and >> i divides by scale */
+
+               old_load = this_rq->cpu_load[i];
+               new_load = this_load;
+
+               this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
+       }
 }
 
+#ifdef CONFIG_SMP
+
 /*
  * double_rq_lock - safely lock two runqueues
  *
@@ -2184,23 +2030,17 @@ void sched_exec(void)
  * pull_task - move a task from a remote runqueue to the local runqueue.
  * Both runqueues must be locked.
  */
-static void pull_task(struct rq *src_rq, struct prio_array *src_array,
-                     struct task_struct *p, struct rq *this_rq,
-                     struct prio_array *this_array, int this_cpu)
+static void pull_task(struct rq *src_rq, struct task_struct *p,
+                     struct rq *this_rq, int this_cpu)
 {
-       dequeue_task(p, src_array);
-       dec_nr_running(p, src_rq);
+       deactivate_task(src_rq, p, 0);
        set_task_cpu(p, this_cpu);
-       inc_nr_running(p, this_rq);
-       enqueue_task(p, this_array);
-       p->timestamp = (p->timestamp - src_rq->most_recent_timestamp)
-                               + this_rq->most_recent_timestamp;
+       activate_task(this_rq, p, 0);
        /*
         * Note that idle threads have a prio of MAX_PRIO, for this test
         * to be always true for them.
         */
-       if (TASK_PREEMPTS_CURR(p, this_rq))
-               resched_task(this_rq->curr);
+       check_preempt_curr(this_rq, p);
 }
 
 /*
@@ -2208,7 +2048,7 @@ static void pull_task(struct rq *src_rq, struct prio_array *src_array,
  */
 static
 int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
-                    struct sched_domain *sd, enum idle_type idle,
+                    struct sched_domain *sd, enum cpu_idle_type idle,
                     int *all_pinned)
 {
        /*
@@ -2225,132 +2065,67 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
                return 0;
 
        /*
-        * Aggressive migration if:
-        * 1) task is cache cold, or
-        * 2) too many balance attempts have failed.
+        * Aggressive migration if too many balance attempts have failed:
         */
-
-       if (sd->nr_balance_failed > sd->cache_nice_tries) {
-#ifdef CONFIG_SCHEDSTATS
-               if (task_hot(p, rq->most_recent_timestamp, sd))
-                       schedstat_inc(sd, lb_hot_gained[idle]);
-#endif
+       if (sd->nr_balance_failed > sd->cache_nice_tries)
                return 1;
-       }
 
-       if (task_hot(p, rq->most_recent_timestamp, sd))
-               return 0;
        return 1;
 }
 
-#define rq_best_prio(rq) min((rq)->curr->prio, (rq)->best_expired_prio)
-
-/*
- * move_tasks tries to move up to max_nr_move tasks and max_load_move weighted
- * load from busiest to this_rq, as part of a balancing operation within
- * "domain". Returns the number of tasks moved.
- *
- * Called with both runqueues locked.
- */
-static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
+static int balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
                      unsigned long max_nr_move, unsigned long max_load_move,
-                     struct sched_domain *sd, enum idle_type idle,
-                     int *all_pinned)
+                     struct sched_domain *sd, enum cpu_idle_type idle,
+                     int *all_pinned, unsigned long *load_moved,
+                     int this_best_prio, int best_prio, int best_prio_seen,
+                     struct rq_iterator *iterator)
 {
-       int idx, pulled = 0, pinned = 0, this_best_prio, best_prio,
-           best_prio_seen, skip_for_load;
-       struct prio_array *array, *dst_array;
-       struct list_head *head, *curr;
-       struct task_struct *tmp;
-       long rem_load_move;
+       int pulled = 0, pinned = 0, skip_for_load;
+       struct task_struct *p;
+       long rem_load_move = max_load_move;
 
        if (max_nr_move == 0 || max_load_move == 0)
                goto out;
 
-       rem_load_move = max_load_move;
        pinned = 1;
-       this_best_prio = rq_best_prio(this_rq);
-       best_prio = rq_best_prio(busiest);
-       /*
-        * Enable handling of the case where there is more than one task
-        * with the best priority.   If the current running task is one
-        * of those with prio==best_prio we know it won't be moved
-        * and therefore it's safe to override the skip (based on load) of
-        * any task we find with that prio.
-        */
-       best_prio_seen = best_prio == busiest->curr->prio;
 
        /*
-        * We first consider expired tasks. Those will likely not be
-        * executed in the near future, and they are most likely to
-        * be cache-cold, thus switching CPUs has the least effect
-        * on them.
+        * Start the load-balancing iterator:
         */
-       if (busiest->expired->nr_active) {
-               array = busiest->expired;
-               dst_array = this_rq->expired;
-       } else {
-               array = busiest->active;
-               dst_array = this_rq->active;
-       }
-
-new_array:
-       /* Start searching at priority 0: */
-       idx = 0;
-skip_bitmap:
-       if (!idx)
-               idx = sched_find_first_bit(array->bitmap);
-       else
-               idx = find_next_bit(array->bitmap, MAX_PRIO, idx);
-       if (idx >= MAX_PRIO) {
-               if (array == busiest->expired && busiest->active->nr_active) {
-                       array = busiest->active;
-                       dst_array = this_rq->active;
-                       goto new_array;
-               }
+       p = iterator->start(iterator->arg);
+next:
+       if (!p)
                goto out;
-       }
-
-       head = array->queue + idx;
-       curr = head->prev;
-skip_queue:
-       tmp = list_entry(curr, struct task_struct, run_list);
-
-       curr = curr->prev;
-
        /*
         * To help distribute high priority tasks accross CPUs we don't
         * skip a task if it will be the highest priority task (i.e. smallest
         * prio value) on its new queue regardless of its load weight
         */
-       skip_for_load = tmp->load_weight > rem_load_move;
-       if (skip_for_load && idx < this_best_prio)
-               skip_for_load = !best_prio_seen && idx == best_prio;
+       skip_for_load = (p->se.load.weight >> 1) > rem_load_move +
+                                                        SCHED_LOAD_SCALE_FUZZ;
+       if (skip_for_load && p->prio < this_best_prio)
+               skip_for_load = !best_prio_seen && p->prio == best_prio;
        if (skip_for_load ||
-           !can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
+           !can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) {
 
-               best_prio_seen |= idx == best_prio;
-               if (curr != head)
-                       goto skip_queue;
-               idx++;
-               goto skip_bitmap;
+               best_prio_seen |= p->prio == best_prio;
+               p = iterator->next(iterator->arg);
+               goto next;
        }
 
-       pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
+       pull_task(busiest, p, this_rq, this_cpu);
        pulled++;
-       rem_load_move -= tmp->load_weight;
+       rem_load_move -= p->se.load.weight;
 
        /*
         * We only want to steal up to the prescribed number of tasks
         * and the prescribed amount of weighted load.
         */
        if (pulled < max_nr_move && rem_load_move > 0) {
-               if (idx < this_best_prio)
-                       this_best_prio = idx;
-               if (curr != head)
-                       goto skip_queue;
-               idx++;
-               goto skip_bitmap;
+               if (p->prio < this_best_prio)
+                       this_best_prio = p->prio;
+               p = iterator->next(iterator->arg);
+               goto next;
        }
 out:
        /*
@@ -2362,9 +2137,39 @@ out:
 
        if (all_pinned)
                *all_pinned = pinned;
+       *load_moved = max_load_move - rem_load_move;
        return pulled;
 }
 
+/*
+ * move_tasks tries to move up to max_nr_move tasks and max_load_move weighted
+ * load from busiest to this_rq, as part of a balancing operation within
+ * "domain". Returns the number of tasks moved.
+ *
+ * Called with both runqueues locked.
+ */
+static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
+                     unsigned long max_nr_move, unsigned long max_load_move,
+                     struct sched_domain *sd, enum cpu_idle_type idle,
+                     int *all_pinned)
+{
+       struct sched_class *class = sched_class_highest;
+       unsigned long load_moved, total_nr_moved = 0, nr_moved;
+       long rem_load_move = max_load_move;
+
+       do {
+               nr_moved = class->load_balance(this_rq, this_cpu, busiest,
+                               max_nr_move, (unsigned long)rem_load_move,
+                               sd, idle, all_pinned, &load_moved);
+               total_nr_moved += nr_moved;
+               max_nr_move -= nr_moved;
+               rem_load_move -= load_moved;
+               class = class->next;
+       } while (class && max_nr_move && rem_load_move > 0);
+
+       return total_nr_moved;
+}
+
 /*
  * find_busiest_group finds and returns the busiest CPU group within the
  * domain. It calculates and returns the amount of weighted load which
@@ -2372,8 +2177,8 @@ out:
  */
 static struct sched_group *
 find_busiest_group(struct sched_domain *sd, int this_cpu,
-                  unsigned long *imbalance, enum idle_type idle, int *sd_idle,
-                  cpumask_t *cpus, int *balance)
+                  unsigned long *imbalance, enum cpu_idle_type idle,
+                  int *sd_idle, cpumask_t *cpus, int *balance)
 {
        struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
        unsigned long max_load, avg_load, total_load, this_load, total_pwr;
@@ -2391,9 +2196,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        max_load = this_load = total_load = total_pwr = 0;
        busiest_load_per_task = busiest_nr_running = 0;
        this_load_per_task = this_nr_running = 0;
-       if (idle == NOT_IDLE)
+       if (idle == CPU_NOT_IDLE)
                load_idx = sd->busy_idx;
-       else if (idle == NEWLY_IDLE)
+       else if (idle == CPU_NEWLY_IDLE)
                load_idx = sd->newidle_idx;
        else
                load_idx = sd->idle_idx;
@@ -2437,7 +2242,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
 
                        avg_load += load;
                        sum_nr_running += rq->nr_running;
-                       sum_weighted_load += rq->raw_weighted_load;
+                       sum_weighted_load += weighted_cpuload(i);
                }
 
                /*
@@ -2477,8 +2282,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                 * Busy processors will not participate in power savings
                 * balance.
                 */
-               if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
-                       goto group_next;
+               if (idle == CPU_NOT_IDLE ||
+                               !(sd->flags & SD_POWERSAVINGS_BALANCE))
+                       goto group_next;
 
                /*
                 * If the local group is idle or completely loaded
@@ -2488,42 +2294,42 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                                    !this_nr_running))
                        power_savings_balance = 0;
 
-               /*
+               /*
                 * If a group is already running at full capacity or idle,
                 * don't include that group in power savings calculations
-                */
-               if (!power_savings_balance || sum_nr_running >= group_capacity
+                */
+               if (!power_savings_balance || sum_nr_running >= group_capacity
                    || !sum_nr_running)
-                       goto group_next;
+                       goto group_next;
 
-               /*
+               /*
                 * Calculate the group which has the least non-idle load.
-                * This is the group from where we need to pick up the load
-                * for saving power
-                */
-               if ((sum_nr_running < min_nr_running) ||
-                   (sum_nr_running == min_nr_running &&
+                * This is the group from where we need to pick up the load
+                * for saving power
+                */
+               if ((sum_nr_running < min_nr_running) ||
+                   (sum_nr_running == min_nr_running &&
                     first_cpu(group->cpumask) <
                     first_cpu(group_min->cpumask))) {
-                       group_min = group;
-                       min_nr_running = sum_nr_running;
+                       group_min = group;
+                       min_nr_running = sum_nr_running;
                        min_load_per_task = sum_weighted_load /
                                                sum_nr_running;
-               }
+               }
 
-               /*
+               /*
                 * Calculate the group which is almost near its
-                * capacity but still has some space to pick up some load
-                * from other group and save more power
-                */
-               if (sum_nr_running <= group_capacity - 1) {
-                       if (sum_nr_running > leader_nr_running ||
-                           (sum_nr_running == leader_nr_running &&
-                            first_cpu(group->cpumask) >
-                             first_cpu(group_leader->cpumask))) {
-                               group_leader = group;
-                               leader_nr_running = sum_nr_running;
-                       }
+                * capacity but still has some space to pick up some load
+                * from other group and save more power
+                */
+               if (sum_nr_running <= group_capacity - 1) {
+                       if (sum_nr_running > leader_nr_running ||
+                           (sum_nr_running == leader_nr_running &&
+                            first_cpu(group->cpumask) >
+                             first_cpu(group_leader->cpumask))) {
+                               group_leader = group;
+                               leader_nr_running = sum_nr_running;
+                       }
                }
 group_next:
 #endif
@@ -2578,7 +2384,7 @@ group_next:
         * a think about bumping its value to force at least one task to be
         * moved
         */
-       if (*imbalance < busiest_load_per_task) {
+       if (*imbalance + SCHED_LOAD_SCALE_FUZZ < busiest_load_per_task/2) {
                unsigned long tmp, pwr_now, pwr_move;
                unsigned int imbn;
 
@@ -2592,7 +2398,8 @@ small_imbalance:
                } else
                        this_load_per_task = SCHED_LOAD_SCALE;
 
-               if (max_load - this_load >= busiest_load_per_task * imbn) {
+               if (max_load - this_load + SCHED_LOAD_SCALE_FUZZ >=
+                                       busiest_load_per_task * imbn) {
                        *imbalance = busiest_load_per_task;
                        return busiest;
                }
@@ -2639,7 +2446,7 @@ small_imbalance:
 
 out_balanced:
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-       if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
+       if (idle == CPU_NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
                goto ret;
 
        if (this == group_leader && group_leader != group_min) {
@@ -2656,7 +2463,7 @@ ret:
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
 static struct rq *
-find_busiest_queue(struct sched_group *group, enum idle_type idle,
+find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle,
                   unsigned long imbalance, cpumask_t *cpus)
 {
        struct rq *busiest = NULL, *rq;
@@ -2664,17 +2471,19 @@ find_busiest_queue(struct sched_group *group, enum idle_type idle,
        int i;
 
        for_each_cpu_mask(i, group->cpumask) {
+               unsigned long wl;
 
                if (!cpu_isset(i, *cpus))
                        continue;
 
                rq = cpu_rq(i);
+               wl = weighted_cpuload(i);
 
-               if (rq->nr_running == 1 && rq->raw_weighted_load > imbalance)
+               if (rq->nr_running == 1 && wl > imbalance)
                        continue;
 
-               if (rq->raw_weighted_load > max_load) {
-                       max_load = rq->raw_weighted_load;
+               if (wl > max_load) {
+                       max_load = wl;
                        busiest = rq;
                }
        }
@@ -2698,7 +2507,7 @@ static inline unsigned long minus_1_or_zero(unsigned long n)
  * tasks if there is an imbalance.
  */
 static int load_balance(int this_cpu, struct rq *this_rq,
-                       struct sched_domain *sd, enum idle_type idle,
+                       struct sched_domain *sd, enum cpu_idle_type idle,
                        int *balance)
 {
        int nr_moved, all_pinned = 0, active_balance = 0, sd_idle = 0;
@@ -2711,10 +2520,10 @@ static int load_balance(int this_cpu, struct rq *this_rq,
        /*
         * When power savings policy is enabled for the parent domain, idle
         * sibling can pick up load irrespective of busy siblings. In this case,
-        * let the state of idle sibling percolate up as IDLE, instead of
-        * portraying it as NOT_IDLE.
+        * let the state of idle sibling percolate up as CPU_IDLE, instead of
+        * portraying it as CPU_NOT_IDLE.
         */
-       if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
+       if (idle != CPU_NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
            !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
                sd_idle = 1;
 
@@ -2848,7 +2657,7 @@ out_one_pinned:
  * Check this_cpu to ensure it is balanced within domain. Attempt to move
  * tasks if there is an imbalance.
  *
- * Called from schedule when this_rq is about to become idle (NEWLY_IDLE).
+ * Called from schedule when this_rq is about to become idle (CPU_NEWLY_IDLE).
  * this_rq is locked.
  */
 static int
@@ -2865,31 +2674,31 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
         * When power savings policy is enabled for the parent domain, idle
         * sibling can pick up load irrespective of busy siblings. In this case,
         * let the state of idle sibling percolate up as IDLE, instead of
-        * portraying it as NOT_IDLE.
+        * portraying it as CPU_NOT_IDLE.
         */
        if (sd->flags & SD_SHARE_CPUPOWER &&
            !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
                sd_idle = 1;
 
-       schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
+       schedstat_inc(sd, lb_cnt[CPU_NEWLY_IDLE]);
 redo:
-       group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE,
+       group = find_busiest_group(sd, this_cpu, &imbalance, CPU_NEWLY_IDLE,
                                   &sd_idle, &cpus, NULL);
        if (!group) {
-               schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
+               schedstat_inc(sd, lb_nobusyg[CPU_NEWLY_IDLE]);
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group, NEWLY_IDLE, imbalance,
+       busiest = find_busiest_queue(group, CPU_NEWLY_IDLE, imbalance,
                                &cpus);
        if (!busiest) {
-               schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
+               schedstat_inc(sd, lb_nobusyq[CPU_NEWLY_IDLE]);
                goto out_balanced;
        }
 
        BUG_ON(busiest == this_rq);
 
-       schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance);
+       schedstat_add(sd, lb_imbalance[CPU_NEWLY_IDLE], imbalance);
 
        nr_moved = 0;
        if (busiest->nr_running > 1) {
@@ -2897,7 +2706,7 @@ redo:
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
                                        minus_1_or_zero(busiest->nr_running),
-                                       imbalance, sd, NEWLY_IDLE, NULL);
+                                       imbalance, sd, CPU_NEWLY_IDLE, NULL);
                spin_unlock(&busiest->lock);
 
                if (!nr_moved) {
@@ -2908,7 +2717,7 @@ redo:
        }
 
        if (!nr_moved) {
-               schedstat_inc(sd, lb_failed[NEWLY_IDLE]);
+               schedstat_inc(sd, lb_failed[CPU_NEWLY_IDLE]);
                if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
                    !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
                        return -1;
@@ -2918,7 +2727,7 @@ redo:
        return nr_moved;
 
 out_balanced:
-       schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
+       schedstat_inc(sd, lb_balanced[CPU_NEWLY_IDLE]);
        if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
            !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
                return -1;
@@ -2934,8 +2743,8 @@ out_balanced:
 static void idle_balance(int this_cpu, struct rq *this_rq)
 {
        struct sched_domain *sd;
-       int pulled_task = 0;
-       unsigned long next_balance = jiffies + 60 *  HZ;
+       int pulled_task = -1;
+       unsigned long next_balance = jiffies + HZ;
 
        for_each_domain(this_cpu, sd) {
                unsigned long interval;
@@ -2954,12 +2763,13 @@ static void idle_balance(int this_cpu, struct rq *this_rq)
                if (pulled_task)
                        break;
        }
-       if (!pulled_task)
+       if (pulled_task || time_after(jiffies, this_rq->next_balance)) {
                /*
                 * We are going idle. next_balance may be set based on
                 * a busy processor. So reset next_balance.
                 */
                this_rq->next_balance = next_balance;
+       }
 }
 
 /*
@@ -3003,7 +2813,7 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
                schedstat_inc(sd, alb_cnt);
 
                if (move_tasks(target_rq, target_cpu, busiest_rq, 1,
-                              RTPRIO_TO_LOAD_WEIGHT(100), sd, SCHED_IDLE,
+                              RTPRIO_TO_LOAD_WEIGHT(100), sd, CPU_IDLE,
                               NULL))
                        schedstat_inc(sd, alb_pushed);
                else
@@ -3012,32 +2822,6 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
        spin_unlock(&target_rq->lock);
 }
 
-static void update_load(struct rq *this_rq)
-{
-       unsigned long this_load;
-       unsigned int i, scale;
-
-       this_load = this_rq->raw_weighted_load;
-
-       /* Update our load: */
-       for (i = 0, scale = 1; i < 3; i++, scale += scale) {
-               unsigned long old_load, new_load;
-
-               /* scale is effectively 1 << i now, and >> i divides by scale */
-
-               old_load = this_rq->cpu_load[i];
-               new_load = this_load;
-               /*
-                * Round up the averaging division if load is increasing. This
-                * prevents us from getting stuck on 9 if the load is 10, for
-                * example.
-                */
-               if (new_load > old_load)
-                       new_load += scale-1;
-               this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
-       }
-}
-
 #ifdef CONFIG_NO_HZ
 static struct {
        atomic_t load_balancer;
@@ -3120,7 +2904,7 @@ static DEFINE_SPINLOCK(balancing);
  *
  * Balancing parameters are set up in arch_init_sched_domains.
  */
-static inline void rebalance_domains(int cpu, enum idle_type idle)
+static inline void rebalance_domains(int cpu, enum cpu_idle_type idle)
 {
        int balance = 1;
        struct rq *rq = cpu_rq(cpu);
@@ -3134,13 +2918,16 @@ static inline void rebalance_domains(int cpu, enum idle_type idle)
                        continue;
 
                interval = sd->balance_interval;
-               if (idle != SCHED_IDLE)
+               if (idle != CPU_IDLE)
                        interval *= sd->busy_factor;
 
                /* scale ms to jiffies */
                interval = msecs_to_jiffies(interval);
                if (unlikely(!interval))
                        interval = 1;
+               if (interval > HZ*NR_CPUS/10)
+                       interval = HZ*NR_CPUS/10;
+
 
                if (sd->flags & SD_SERIALIZE) {
                        if (!spin_trylock(&balancing))
@@ -3154,7 +2941,7 @@ static inline void rebalance_domains(int cpu, enum idle_type idle)
                                 * longer idle, or one of our SMT siblings is
                                 * not idle.
                                 */
-                               idle = NOT_IDLE;
+                               idle = CPU_NOT_IDLE;
                        }
                        sd->last_balance = jiffies;
                }
@@ -3182,11 +2969,12 @@ out:
  */
 static void run_rebalance_domains(struct softirq_action *h)
 {
-       int local_cpu = smp_processor_id();
-       struct rq *local_rq = cpu_rq(local_cpu);
-       enum idle_type idle = local_rq->idle_at_tick ? SCHED_IDLE : NOT_IDLE;
+       int this_cpu = smp_processor_id();
+       struct rq *this_rq = cpu_rq(this_cpu);
+       enum cpu_idle_type idle = this_rq->idle_at_tick ?
+                                               CPU_IDLE : CPU_NOT_IDLE;
 
-       rebalance_domains(local_cpu, idle);
+       rebalance_domains(this_cpu, idle);
 
 #ifdef CONFIG_NO_HZ
        /*
@@ -3194,13 +2982,13 @@ static void run_rebalance_domains(struct softirq_action *h)
         * balancing on behalf of the other idle cpus whose ticks are
         * stopped.
         */
-       if (local_rq->idle_at_tick &&
-           atomic_read(&nohz.load_balancer) == local_cpu) {
+       if (this_rq->idle_at_tick &&
+           atomic_read(&nohz.load_balancer) == this_cpu) {
                cpumask_t cpus = nohz.cpu_mask;
                struct rq *rq;
                int balance_cpu;
 
-               cpu_clear(local_cpu, cpus);
+               cpu_clear(this_cpu, cpus);
                for_each_cpu_mask(balance_cpu, cpus) {
                        /*
                         * If this cpu gets work to do, stop the load balancing
@@ -3213,8 +3001,8 @@ static void run_rebalance_domains(struct softirq_action *h)
                        rebalance_domains(balance_cpu, SCHED_IDLE);
 
                        rq = cpu_rq(balance_cpu);
-                       if (time_after(local_rq->next_balance, rq->next_balance))
-                               local_rq->next_balance = rq->next_balance;
+                       if (time_after(this_rq->next_balance, rq->next_balance))
+                               this_rq->next_balance = rq->next_balance;
                }
        }
 #endif
@@ -3227,9 +3015,8 @@ static void run_rebalance_domains(struct softirq_action *h)
  * idle load balancing owner or decide to stop the periodic load balancing,
  * if the whole system is idle.
  */
-static inline void trigger_load_balance(int cpu)
+static inline void trigger_load_balance(struct rq *rq, int cpu)
 {
-       struct rq *rq = cpu_rq(cpu);
 #ifdef CONFIG_NO_HZ
        /*
         * If we were in the nohz mode recently and busy at the current
@@ -3281,13 +3068,29 @@ static inline void trigger_load_balance(int cpu)
        if (time_after_eq(jiffies, rq->next_balance))
                raise_softirq(SCHED_SOFTIRQ);
 }
-#else
+
+#else  /* CONFIG_SMP */
+
 /*
  * on UP we do not need to balance between CPUs:
  */
 static inline void idle_balance(int cpu, struct rq *rq)
 {
 }
+
+/* Avoid "used but not defined" warning on UP */
+static int balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
+                     unsigned long max_nr_move, unsigned long max_load_move,
+                     struct sched_domain *sd, enum cpu_idle_type idle,
+                     int *all_pinned, unsigned long *load_moved,
+                     int this_best_prio, int best_prio, int best_prio_seen,
+                     struct rq_iterator *iterator)
+{
+       *load_moved = 0;
+
+       return 0;
+}
+
 #endif
 
 DEFINE_PER_CPU(struct kernel_stat, kstat);
@@ -3295,53 +3098,27 @@ DEFINE_PER_CPU(struct kernel_stat, kstat);
 EXPORT_PER_CPU_SYMBOL(kstat);
 
 /*
- * This is called on clock ticks and on context switches.
- * Bank in p->sched_time the ns elapsed since the last tick or switch.
- */
-static inline void
-update_cpu_clock(struct task_struct *p, struct rq *rq, unsigned long long now)
-{
-       p->sched_time += now - p->last_ran;
-       p->last_ran = rq->most_recent_timestamp = now;
-}
-
-/*
- * Return current->sched_time plus any more ns on the sched_clock
- * that have not yet been banked.
+ * Return p->sum_exec_runtime plus any more ns on the sched_clock
+ * that have not yet been banked in case the task is currently running.
  */
-unsigned long long current_sched_time(const struct task_struct *p)
+unsigned long long task_sched_runtime(struct task_struct *p)
 {
-       unsigned long long ns;
        unsigned long flags;
+       u64 ns, delta_exec;
+       struct rq *rq;
 
-       local_irq_save(flags);
-       ns = p->sched_time + sched_clock() - p->last_ran;
-       local_irq_restore(flags);
+       rq = task_rq_lock(p, &flags);
+       ns = p->se.sum_exec_runtime;
+       if (rq->curr == p) {
+               delta_exec = rq_clock(rq) - p->se.exec_start;
+               if ((s64)delta_exec > 0)
+                       ns += delta_exec;
+       }
+       task_rq_unlock(rq, &flags);
 
        return ns;
 }
 
-/*
- * We place interactive tasks back into the active array, if possible.
- *
- * To guarantee that this does not starve expired tasks we ignore the
- * interactivity of a task if the first expired task had to wait more
- * than a 'reasonable' amount of time. This deadline timeout is
- * load-dependent, as the frequency of array switched decreases with
- * increasing number of running tasks. We also ignore the interactivity
- * if a better static_prio task has expired:
- */
-static inline int expired_starving(struct rq *rq)
-{
-       if (rq->curr->static_prio > rq->best_expired_prio)
-               return 1;
-       if (!STARVATION_LIMIT || !rq->expired_timestamp)
-               return 0;
-       if (jiffies - rq->expired_timestamp > STARVATION_LIMIT * rq->nr_running)
-               return 1;
-       return 0;
-}
-
 /*
  * Account user cpu time to a process.
  * @p: the process that the cpu time gets accounted to
@@ -3415,81 +3192,6 @@ void account_steal_time(struct task_struct *p, cputime_t steal)
                cpustat->steal = cputime64_add(cpustat->steal, tmp);
 }
 
-static void task_running_tick(struct rq *rq, struct task_struct *p)
-{
-       if (p->array != rq->active) {
-               /* Task has expired but was not scheduled yet */
-               set_tsk_need_resched(p);
-               return;
-       }
-       spin_lock(&rq->lock);
-       /*
-        * The task was running during this tick - update the
-        * time slice counter. Note: we do not update a thread's
-        * priority until it either goes to sleep or uses up its
-        * timeslice. This makes it possible for interactive tasks
-        * to use up their timeslices at their highest priority levels.
-        */
-       if (rt_task(p)) {
-               /*
-                * RR tasks need a special form of timeslice management.
-                * FIFO tasks have no timeslices.
-                */
-               if ((p->policy == SCHED_RR) && !--p->time_slice) {
-                       p->time_slice = task_timeslice(p);
-                       p->first_time_slice = 0;
-                       set_tsk_need_resched(p);
-
-                       /* put it at the end of the queue: */
-                       requeue_task(p, rq->active);
-               }
-               goto out_unlock;
-       }
-       if (!--p->time_slice) {
-               dequeue_task(p, rq->active);
-               set_tsk_need_resched(p);
-               p->prio = effective_prio(p);
-               p->time_slice = task_timeslice(p);
-               p->first_time_slice = 0;
-
-               if (!rq->expired_timestamp)
-                       rq->expired_timestamp = jiffies;
-               if (!TASK_INTERACTIVE(p) || expired_starving(rq)) {
-                       enqueue_task(p, rq->expired);
-                       if (p->static_prio < rq->best_expired_prio)
-                               rq->best_expired_prio = p->static_prio;
-               } else
-                       enqueue_task(p, rq->active);
-       } else {
-               /*
-                * Prevent a too long timeslice allowing a task to monopolize
-                * the CPU. We do this by splitting up the timeslice into
-                * smaller pieces.
-                *
-                * Note: this does not mean the task's timeslices expire or
-                * get lost in any way, they just might be preempted by
-                * another task of equal priority. (one with higher
-                * priority would have preempted this task already.) We
-                * requeue this task to the end of the list on this priority
-                * level, which is in essence a round-robin of tasks with
-                * equal priority.
-                *
-                * This only applies to tasks in the interactive
-                * delta range with at least TIMESLICE_GRANULARITY to requeue.
-                */
-               if (TASK_INTERACTIVE(p) && !((task_timeslice(p) -
-                       p->time_slice) % TIMESLICE_GRANULARITY(p)) &&
-                       (p->time_slice >= TIMESLICE_GRANULARITY(p)) &&
-                       (p->array == rq->active)) {
-
-                       requeue_task(p, rq->active);
-                       set_tsk_need_resched(p);
-               }
-       }
-out_unlock:
-       spin_unlock(&rq->lock);
-}
-
 /*
  * This function gets called by the timer code, with HZ frequency.
  * We call it with interrupts disabled.
@@ -3499,20 +3201,19 @@ out_unlock:
  */
 void scheduler_tick(void)
 {
-       unsigned long long now = sched_clock();
-       struct task_struct *p = current;
        int cpu = smp_processor_id();
-       int idle_at_tick = idle_cpu(cpu);
        struct rq *rq = cpu_rq(cpu);
+       struct task_struct *curr = rq->curr;
 
-       update_cpu_clock(p, rq, now);
+       spin_lock(&rq->lock);
+       if (curr != rq->idle) /* FIXME: needed? */
+               curr->sched_class->task_tick(rq, curr);
+       update_cpu_load(rq);
+       spin_unlock(&rq->lock);
 
-       if (!idle_at_tick)
-               task_running_tick(rq, p);
 #ifdef CONFIG_SMP
-       update_load(rq);
-       rq->idle_at_tick = idle_at_tick;
-       trigger_load_balance(cpu);
+       rq->idle_at_tick = idle_cpu(cpu);
+       trigger_load_balance(rq, cpu);
 #endif
 }
 
@@ -3554,170 +3255,129 @@ EXPORT_SYMBOL(sub_preempt_count);
 
 #endif
 
-static inline int interactive_sleep(enum sleep_type sleep_type)
+/*
+ * Print scheduling while atomic bug:
+ */
+static noinline void __schedule_bug(struct task_struct *prev)
 {
-       return (sleep_type == SLEEP_INTERACTIVE ||
-               sleep_type == SLEEP_INTERRUPTED);
+       printk(KERN_ERR "BUG: scheduling while atomic: %s/0x%08x/%d\n",
+               prev->comm, preempt_count(), prev->pid);
+       debug_show_held_locks(prev);
+       if (irqs_disabled())
+               print_irqtrace_events(prev);
+       dump_stack();
 }
 
 /*
- * schedule() is the main scheduler function.
+ * Various schedule()-time debugging checks and statistics:
  */
-asmlinkage void __sched schedule(void)
+static inline void schedule_debug(struct task_struct *prev)
 {
-       struct task_struct *prev, *next;
-       struct prio_array *array;
-       struct list_head *queue;
-       unsigned long long now;
-       unsigned long run_time;
-       int cpu, idx, new_prio;
-       long *switch_count;
-       struct rq *rq;
-
        /*
         * Test if we are atomic.  Since do_exit() needs to call into
         * schedule() atomically, we ignore that path for now.
         * Otherwise, whine if we are scheduling when we should not be.
         */
-       if (unlikely(in_atomic() && !current->exit_state)) {
-               printk(KERN_ERR "BUG: scheduling while atomic: "
-                       "%s/0x%08x/%d\n",
-                       current->comm, preempt_count(), current->pid);
-               debug_show_held_locks(current);
-               if (irqs_disabled())
-                       print_irqtrace_events(current);
-               dump_stack();
-       }
-       profile_hit(SCHED_PROFILING, __builtin_return_address(0));
+       if (unlikely(in_atomic_preempt_off()) && unlikely(!prev->exit_state))
+               __schedule_bug(prev);
 
-need_resched:
-       preempt_disable();
-       prev = current;
-       release_kernel_lock(prev);
-need_resched_nonpreemptible:
-       rq = this_rq();
+       profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
-       /*
-        * The idle thread is not allowed to schedule!
-        * Remove this check after it has been exercised a bit.
-        */
-       if (unlikely(prev == rq->idle) && prev->state != TASK_RUNNING) {
-               printk(KERN_ERR "bad: scheduling from the idle thread!\n");
-               dump_stack();
-       }
+       schedstat_inc(this_rq(), sched_cnt);
+}
 
-       schedstat_inc(rq, sched_cnt);
-       now = sched_clock();
-       if (likely((long long)(now - prev->timestamp) < NS_MAX_SLEEP_AVG)) {
-               run_time = now - prev->timestamp;
-               if (unlikely((long long)(now - prev->timestamp) < 0))
-                       run_time = 0;
-       } else
-               run_time = NS_MAX_SLEEP_AVG;
+/*
+ * Pick up the highest-prio task:
+ */
+static inline struct task_struct *
+pick_next_task(struct rq *rq, struct task_struct *prev, u64 now)
+{
+       struct sched_class *class;
+       struct task_struct *p;
 
        /*
-        * Tasks charged proportionately less run_time at high sleep_avg to
-        * delay them losing their interactive status
+        * Optimization: we know that if all tasks are in
+        * the fair class we can call that function directly:
         */
-       run_time /= (CURRENT_BONUS(prev) ? : 1);
-
-       spin_lock_irq(&rq->lock);
-
-       switch_count = &prev->nivcsw;
-       if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
-               switch_count = &prev->nvcsw;
-               if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
-                               unlikely(signal_pending(prev))))
-                       prev->state = TASK_RUNNING;
-               else {
-                       if (prev->state == TASK_UNINTERRUPTIBLE)
-                               rq->nr_uninterruptible++;
-                       deactivate_task(prev, rq);
-               }
-       }
-
-       cpu = smp_processor_id();
-       if (unlikely(!rq->nr_running)) {
-               idle_balance(cpu, rq);
-               if (!rq->nr_running) {
-                       next = rq->idle;
-                       rq->expired_timestamp = 0;
-                       goto switch_tasks;
-               }
+       if (likely(rq->nr_running == rq->cfs.nr_running)) {
+               p = fair_sched_class.pick_next_task(rq, now);
+               if (likely(p))
+                       return p;
        }
 
-       array = rq->active;
-       if (unlikely(!array->nr_active)) {
+       class = sched_class_highest;
+       for ( ; ; ) {
+               p = class->pick_next_task(rq, now);
+               if (p)
+                       return p;
                /*
-                * Switch the active and expired arrays.
+                * Will never be NULL as the idle class always
+                * returns a non-NULL p:
                 */
-               schedstat_inc(rq, sched_switch);
-               rq->active = rq->expired;
-               rq->expired = array;
-               array = rq->active;
-               rq->expired_timestamp = 0;
-               rq->best_expired_prio = MAX_PRIO;
+               class = class->next;
        }
+}
+
+/*
+ * schedule() is the main scheduler function.
+ */
+asmlinkage void __sched schedule(void)
+{
+       struct task_struct *prev, *next;
+       long *switch_count;
+       struct rq *rq;
+       u64 now;
+       int cpu;
 
-       idx = sched_find_first_bit(array->bitmap);
-       queue = array->queue + idx;
-       next = list_entry(queue->next, struct task_struct, run_list);
+need_resched:
+       preempt_disable();
+       cpu = smp_processor_id();
+       rq = cpu_rq(cpu);
+       rcu_qsctr_inc(cpu);
+       prev = rq->curr;
+       switch_count = &prev->nivcsw;
 
-       if (!rt_task(next) && interactive_sleep(next->sleep_type)) {
-               unsigned long long delta = now - next->timestamp;
-               if (unlikely((long long)(now - next->timestamp) < 0))
-                       delta = 0;
+       release_kernel_lock(prev);
+need_resched_nonpreemptible:
 
-               if (next->sleep_type == SLEEP_INTERACTIVE)
-                       delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
+       schedule_debug(prev);
 
-               array = next->array;
-               new_prio = recalc_task_prio(next, next->timestamp + delta);
+       spin_lock_irq(&rq->lock);
+       clear_tsk_need_resched(prev);
 
-               if (unlikely(next->prio != new_prio)) {
-                       dequeue_task(next, array);
-                       next->prio = new_prio;
-                       enqueue_task(next, array);
+       if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
+               if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
+                               unlikely(signal_pending(prev)))) {
+                       prev->state = TASK_RUNNING;
+               } else {
+                       deactivate_task(rq, prev, 1);
                }
+               switch_count = &prev->nvcsw;
        }
-       next->sleep_type = SLEEP_NORMAL;
-switch_tasks:
-       if (next == rq->idle)
-               schedstat_inc(rq, sched_goidle);
-       prefetch(next);
-       prefetch_stack(next);
-       clear_tsk_need_resched(prev);
-       rcu_qsctr_inc(task_cpu(prev));
 
-       update_cpu_clock(prev, rq, now);
+       if (unlikely(!rq->nr_running))
+               idle_balance(cpu, rq);
 
-       prev->sleep_avg -= run_time;
-       if ((long)prev->sleep_avg <= 0)
-               prev->sleep_avg = 0;
-       prev->timestamp = prev->last_ran = now;
+       now = __rq_clock(rq);
+       prev->sched_class->put_prev_task(rq, prev, now);
+       next = pick_next_task(rq, prev, now);
 
        sched_info_switch(prev, next);
+
        if (likely(prev != next)) {
-               next->timestamp = next->last_ran = now;
                rq->nr_switches++;
                rq->curr = next;
                ++*switch_count;
 
-               prepare_task_switch(rq, next);
-               prev = context_switch(rq, prev, next);
-               barrier();
-               /*
-                * this_rq must be evaluated again because prev may have moved
-                * CPUs since it called schedule(), thus the 'rq' on its stack
-                * frame will be invalid.
-                */
-               finish_task_switch(this_rq(), prev);
+               context_switch(rq, prev, next); /* unlocks the rq */
        } else
                spin_unlock_irq(&rq->lock);
 
-       prev = current;
-       if (unlikely(reacquire_kernel_lock(prev) < 0))
+       if (unlikely(reacquire_kernel_lock(current) < 0)) {
+               cpu = smp_processor_id();
+               rq = cpu_rq(cpu);
                goto need_resched_nonpreemptible;
+       }
        preempt_enable_no_resched();
        if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
                goto need_resched;
@@ -4045,74 +3705,85 @@ out:
 }
 EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
 
-
-#define        SLEEP_ON_VAR                                    \
-       unsigned long flags;                            \
-       wait_queue_t wait;                              \
-       init_waitqueue_entry(&wait, current);
-
-#define SLEEP_ON_HEAD                                  \
-       spin_lock_irqsave(&q->lock,flags);              \
-       __add_wait_queue(q, &wait);                     \
+static inline void
+sleep_on_head(wait_queue_head_t *q, wait_queue_t *wait, unsigned long *flags)
+{
+       spin_lock_irqsave(&q->lock, *flags);
+       __add_wait_queue(q, wait);
        spin_unlock(&q->lock);
+}
 
-#define        SLEEP_ON_TAIL                                   \
-       spin_lock_irq(&q->lock);                        \
-       __remove_wait_queue(q, &wait);                  \
-       spin_unlock_irqrestore(&q->lock, flags);
+static inline void
+sleep_on_tail(wait_queue_head_t *q, wait_queue_t *wait, unsigned long *flags)
+{
+       spin_lock_irq(&q->lock);
+       __remove_wait_queue(q, wait);
+       spin_unlock_irqrestore(&q->lock, *flags);
+}
 
-void fastcall __sched interruptible_sleep_on(wait_queue_head_t *q)
+void __sched interruptible_sleep_on(wait_queue_head_t *q)
 {
-       SLEEP_ON_VAR
+       unsigned long flags;
+       wait_queue_t wait;
+
+       init_waitqueue_entry(&wait, current);
 
        current->state = TASK_INTERRUPTIBLE;
 
-       SLEEP_ON_HEAD
+       sleep_on_head(q, &wait, &flags);
        schedule();
-       SLEEP_ON_TAIL
+       sleep_on_tail(q, &wait, &flags);
 }
 EXPORT_SYMBOL(interruptible_sleep_on);
 
-long fastcall __sched
+long __sched
 interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
-       SLEEP_ON_VAR
+       unsigned long flags;
+       wait_queue_t wait;
+
+       init_waitqueue_entry(&wait, current);
 
        current->state = TASK_INTERRUPTIBLE;
 
-       SLEEP_ON_HEAD
+       sleep_on_head(q, &wait, &flags);
        timeout = schedule_timeout(timeout);
-       SLEEP_ON_TAIL
+       sleep_on_tail(q, &wait, &flags);
 
        return timeout;
 }
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 
-void fastcall __sched sleep_on(wait_queue_head_t *q)
+void __sched sleep_on(wait_queue_head_t *q)
 {
-       SLEEP_ON_VAR
+       unsigned long flags;
+       wait_queue_t wait;
+
+       init_waitqueue_entry(&wait, current);
 
        current->state = TASK_UNINTERRUPTIBLE;
 
-       SLEEP_ON_HEAD
+       sleep_on_head(q, &wait, &flags);
        schedule();
-       SLEEP_ON_TAIL
+       sleep_on_tail(q, &wait, &flags);
 }
 EXPORT_SYMBOL(sleep_on);
 
-long fastcall __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
+long __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
-       SLEEP_ON_VAR
+       unsigned long flags;
+       wait_queue_t wait;
+
+       init_waitqueue_entry(&wait, current);
 
        current->state = TASK_UNINTERRUPTIBLE;
 
-       SLEEP_ON_HEAD
+       sleep_on_head(q, &wait, &flags);
        timeout = schedule_timeout(timeout);
-       SLEEP_ON_TAIL
+       sleep_on_tail(q, &wait, &flags);
 
        return timeout;
 }
-
 EXPORT_SYMBOL(sleep_on_timeout);
 
 #ifdef CONFIG_RT_MUTEXES
@@ -4129,29 +3800,30 @@ EXPORT_SYMBOL(sleep_on_timeout);
  */
 void rt_mutex_setprio(struct task_struct *p, int prio)
 {
-       struct prio_array *array;
        unsigned long flags;
+       int oldprio, on_rq;
        struct rq *rq;
-       int oldprio;
+       u64 now;
 
        BUG_ON(prio < 0 || prio > MAX_PRIO);
 
        rq = task_rq_lock(p, &flags);
+       now = rq_clock(rq);
 
        oldprio = p->prio;
-       array = p->array;
-       if (array)
-               dequeue_task(p, array);
+       on_rq = p->se.on_rq;
+       if (on_rq)
+               dequeue_task(rq, p, 0, now);
+
+       if (rt_prio(prio))
+               p->sched_class = &rt_sched_class;
+       else
+               p->sched_class = &fair_sched_class;
+
        p->prio = prio;
 
-       if (array) {
-               /*
-                * If changing to an RT priority then queue it
-                * in the active array!
-                */
-               if (rt_task(p))
-                       array = rq->active;
-               enqueue_task(p, array);
+       if (on_rq) {
+               enqueue_task(rq, p, 0, now);
                /*
                 * Reschedule if we are currently running on this runqueue and
                 * our priority decreased, or if we are not currently running on
@@ -4160,8 +3832,9 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
                if (task_running(rq, p)) {
                        if (p->prio > oldprio)
                                resched_task(rq->curr);
-               } else if (TASK_PREEMPTS_CURR(p, rq))
-                       resched_task(rq->curr);
+               } else {
+                       check_preempt_curr(rq, p);
+               }
        }
        task_rq_unlock(rq, &flags);
 }
@@ -4170,10 +3843,10 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
 
 void set_user_nice(struct task_struct *p, long nice)
 {
-       struct prio_array *array;
-       int old_prio, delta;
+       int old_prio, delta, on_rq;
        unsigned long flags;
        struct rq *rq;
+       u64 now;
 
        if (TASK_NICE(p) == nice || nice < -20 || nice > 19)
                return;
@@ -4182,20 +3855,21 @@ void set_user_nice(struct task_struct *p, long nice)
         * the task might be in the middle of scheduling on another CPU.
         */
        rq = task_rq_lock(p, &flags);
+       now = rq_clock(rq);
        /*
         * The RT priorities are set via sched_setscheduler(), but we still
         * allow the 'normal' nice value to be set - but as expected
         * it wont have any effect on scheduling until the task is
-        * not SCHED_NORMAL/SCHED_BATCH:
+        * SCHED_FIFO/SCHED_RR:
         */
-       if (has_rt_policy(p)) {
+       if (task_has_rt_policy(p)) {
                p->static_prio = NICE_TO_PRIO(nice);
                goto out_unlock;
        }
-       array = p->array;
-       if (array) {
-               dequeue_task(p, array);
-               dec_raw_weighted_load(rq, p);
+       on_rq = p->se.on_rq;
+       if (on_rq) {
+               dequeue_task(rq, p, 0, now);
+               dec_load(rq, p, now);
        }
 
        p->static_prio = NICE_TO_PRIO(nice);
@@ -4204,9 +3878,9 @@ void set_user_nice(struct task_struct *p, long nice)
        p->prio = effective_prio(p);
        delta = p->prio - old_prio;
 
-       if (array) {
-               enqueue_task(p, array);
-               inc_raw_weighted_load(rq, p);
+       if (on_rq) {
+               enqueue_task(rq, p, 0, now);
+               inc_load(rq, p, now);
                /*
                 * If the task increased its priority or is running and
                 * lowered its priority, then reschedule its CPU:
@@ -4326,20 +4000,28 @@ static inline struct task_struct *find_process_by_pid(pid_t pid)
 }
 
 /* Actually do priority change: must hold rq lock. */
-static void __setscheduler(struct task_struct *p, int policy, int prio)
+static void
+__setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
 {
-       BUG_ON(p->array);
+       BUG_ON(p->se.on_rq);
 
        p->policy = policy;
+       switch (p->policy) {
+       case SCHED_NORMAL:
+       case SCHED_BATCH:
+       case SCHED_IDLE:
+               p->sched_class = &fair_sched_class;
+               break;
+       case SCHED_FIFO:
+       case SCHED_RR:
+               p->sched_class = &rt_sched_class;
+               break;
+       }
+
        p->rt_priority = prio;
        p->normal_prio = normal_prio(p);
        /* we are holding p->pi_lock already */
        p->prio = rt_mutex_getprio(p);
-       /*
-        * SCHED_BATCH tasks are treated as perpetual CPU hogs:
-        */
-       if (policy == SCHED_BATCH)
-               p->sleep_avg = 0;
        set_load_weight(p);
 }
 
@@ -4354,8 +4036,7 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
 int sched_setscheduler(struct task_struct *p, int policy,
                       struct sched_param *param)
 {
-       int retval, oldprio, oldpolicy = -1;
-       struct prio_array *array;
+       int retval, oldprio, oldpolicy = -1, on_rq;
        unsigned long flags;
        struct rq *rq;
 
@@ -4366,27 +4047,27 @@ recheck:
        if (policy < 0)
                policy = oldpolicy = p->policy;
        else if (policy != SCHED_FIFO && policy != SCHED_RR &&
-                       policy != SCHED_NORMAL && policy != SCHED_BATCH)
+                       policy != SCHED_NORMAL && policy != SCHED_BATCH &&
+                       policy != SCHED_IDLE)
                return -EINVAL;
        /*
         * Valid priorities for SCHED_FIFO and SCHED_RR are
-        * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL and
-        * SCHED_BATCH is 0.
+        * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL,
+        * SCHED_BATCH and SCHED_IDLE is 0.
         */
        if (param->sched_priority < 0 ||
            (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) ||
            (!p->mm && param->sched_priority > MAX_RT_PRIO-1))
                return -EINVAL;
-       if (is_rt_policy(policy) != (param->sched_priority != 0))
+       if (rt_policy(policy) != (param->sched_priority != 0))
                return -EINVAL;
 
        /*
         * Allow unprivileged RT tasks to decrease priority:
         */
        if (!capable(CAP_SYS_NICE)) {
-               if (is_rt_policy(policy)) {
+               if (rt_policy(policy)) {
                        unsigned long rlim_rtprio;
-                       unsigned long flags;
 
                        if (!lock_task_sighand(p, &flags))
                                return -ESRCH;
@@ -4402,6 +4083,12 @@ recheck:
                            param->sched_priority > rlim_rtprio)
                                return -EPERM;
                }
+               /*
+                * Like positive nice levels, dont allow tasks to
+                * move out of SCHED_IDLE either:
+                */
+               if (p->policy == SCHED_IDLE && policy != SCHED_IDLE)
+                       return -EPERM;
 
                /* can't change other user's priorities */
                if ((current->euid != p->euid) &&
@@ -4429,13 +4116,13 @@ recheck:
                spin_unlock_irqrestore(&p->pi_lock, flags);
                goto recheck;
        }
-       array = p->array;
-       if (array)
-               deactivate_task(p, rq);
+       on_rq = p->se.on_rq;
+       if (on_rq)
+               deactivate_task(rq, p, 0);
        oldprio = p->prio;
-       __setscheduler(p, policy, param->sched_priority);
-       if (array) {
-               __activate_task(p, rq);
+       __setscheduler(rq, p, policy, param->sched_priority);
+       if (on_rq) {
+               activate_task(rq, p, 0);
                /*
                 * Reschedule if we are currently running on this runqueue and
                 * our priority decreased, or if we are not currently running on
@@ -4444,8 +4131,9 @@ recheck:
                if (task_running(rq, p)) {
                        if (p->prio > oldprio)
                                resched_task(rq->curr);
-               } else if (TASK_PREEMPTS_CURR(p, rq))
-                       resched_task(rq->curr);
+               } else {
+                       check_preempt_curr(rq, p);
+               }
        }
        __task_rq_unlock(rq);
        spin_unlock_irqrestore(&p->pi_lock, flags);
@@ -4717,41 +4405,18 @@ asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
 /**
  * sys_sched_yield - yield the current processor to other threads.
  *
- * This function yields the current CPU by moving the calling thread
- * to the expired array. If there are no other threads running on this
- * CPU then this function will return.
+ * This function yields the current CPU to other tasks. If there are no
+ * other threads running on this CPU then this function will return.
  */
 asmlinkage long sys_sched_yield(void)
 {
        struct rq *rq = this_rq_lock();
-       struct prio_array *array = current->array, *target = rq->expired;
-
-       schedstat_inc(rq, yld_cnt);
-       /*
-        * We implement yielding by moving the task into the expired
-        * queue.
-        *
-        * (special rule: RT tasks will just roundrobin in the active
-        *  array.)
-        */
-       if (rt_task(current))
-               target = rq->active;
 
-       if (array->nr_active == 1) {
+       schedstat_inc(rq, yld_cnt);
+       if (unlikely(rq->nr_running == 1))
                schedstat_inc(rq, yld_act_empty);
-               if (!rq->expired->nr_active)
-                       schedstat_inc(rq, yld_both_empty);
-       } else if (!rq->expired->nr_active)
-               schedstat_inc(rq, yld_exp_empty);
-
-       if (array != target) {
-               dequeue_task(current, array);
-               enqueue_task(current, target);
-       } else
-               /*
-                * requeue_task is cheaper so perform that if possible.
-                */
-               requeue_task(current, array);
+       else
+               current->sched_class->yield_task(rq, current);
 
        /*
         * Since we are going to call schedule() anyway, there's
@@ -4902,6 +4567,7 @@ asmlinkage long sys_sched_get_priority_max(int policy)
                break;
        case SCHED_NORMAL:
        case SCHED_BATCH:
+       case SCHED_IDLE:
                ret = 0;
                break;
        }
@@ -4926,6 +4592,7 @@ asmlinkage long sys_sched_get_priority_min(int policy)
                break;
        case SCHED_NORMAL:
        case SCHED_BATCH:
+       case SCHED_IDLE:
                ret = 0;
        }
        return ret;
@@ -4960,7 +4627,7 @@ long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval)
                goto out_unlock;
 
        jiffies_to_timespec(p->policy == SCHED_FIFO ?
-                               0 : task_timeslice(p), &t);
+                               0 : static_prio_timeslice(p->static_prio), &t);
        read_unlock(&tasklist_lock);
        retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
 out_nounlock:
@@ -5035,6 +4702,9 @@ void show_state_filter(unsigned long state_filter)
 
        touch_all_softlockup_watchdogs();
 
+#ifdef CONFIG_SCHED_DEBUG
+       sysrq_sched_debug_show();
+#endif
        read_unlock(&tasklist_lock);
        /*
         * Only show locks if all tasks are dumped:
@@ -5043,6 +4713,11 @@ void show_state_filter(unsigned long state_filter)
                debug_show_all_locks();
 }
 
+void __cpuinit init_idle_bootup_task(struct task_struct *idle)
+{
+       idle->sched_class = &idle_sched_class;
+}
+
 /**
  * init_idle - set up an idle thread for a given CPU
  * @idle: task in question
@@ -5056,13 +4731,12 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        struct rq *rq = cpu_rq(cpu);
        unsigned long flags;
 
-       idle->timestamp = sched_clock();
-       idle->sleep_avg = 0;
-       idle->array = NULL;
+       __sched_fork(idle);
+       idle->se.exec_start = sched_clock();
+
        idle->prio = idle->normal_prio = MAX_PRIO;
-       idle->state = TASK_RUNNING;
        idle->cpus_allowed = cpumask_of_cpu(cpu);
-       set_task_cpu(idle, cpu);
+       __set_task_cpu(idle, cpu);
 
        spin_lock_irqsave(&rq->lock, flags);
        rq->curr = rq->idle = idle;
@@ -5077,6 +4751,10 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
 #else
        task_thread_info(idle)->preempt_count = 0;
 #endif
+       /*
+        * The idle tasks have their own, simple scheduling class:
+        */
+       idle->sched_class = &idle_sched_class;
 }
 
 /*
@@ -5088,6 +4766,28 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
  */
 cpumask_t nohz_cpu_mask = CPU_MASK_NONE;
 
+/*
+ * Increase the granularity value when there are more CPUs,
+ * because with more CPUs the 'effective latency' as visible
+ * to users decreases. But the relationship is not linear,
+ * so pick a second-best guess by going with the log2 of the
+ * number of CPUs.
+ *
+ * This idea comes from the SD scheduler of Con Kolivas:
+ */
+static inline void sched_init_granularity(void)
+{
+       unsigned int factor = 1 + ilog2(num_online_cpus());
+       const unsigned long gran_limit = 10000000;
+
+       sysctl_sched_granularity *= factor;
+       if (sysctl_sched_granularity > gran_limit)
+               sysctl_sched_granularity = gran_limit;
+
+       sysctl_sched_runtime_limit = sysctl_sched_granularity * 4;
+       sysctl_sched_wakeup_granularity = sysctl_sched_granularity / 2;
+}
+
 #ifdef CONFIG_SMP
 /*
  * This is how migration works:
@@ -5161,7 +4861,7 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed);
 static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
 {
        struct rq *rq_dest, *rq_src;
-       int ret = 0;
+       int ret = 0, on_rq;
 
        if (unlikely(cpu_is_offline(dest_cpu)))
                return ret;
@@ -5177,20 +4877,13 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
        if (!cpu_isset(dest_cpu, p->cpus_allowed))
                goto out;
 
+       on_rq = p->se.on_rq;
+       if (on_rq)
+               deactivate_task(rq_src, p, 0);
        set_task_cpu(p, dest_cpu);
-       if (p->array) {
-               /*
-                * Sync timestamp with rq_dest's before activating.
-                * The same thing could be achieved by doing this step
-                * afterwards, and pretending it was a local activate.
-                * This way is cleaner and logically correct.
-                */
-               p->timestamp = p->timestamp - rq_src->most_recent_timestamp
-                               + rq_dest->most_recent_timestamp;
-               deactivate_task(p, rq_src);
-               __activate_task(p, rq_dest);
-               if (TASK_PREEMPTS_CURR(p, rq_dest))
-                       resched_task(rq_dest->curr);
+       if (on_rq) {
+               activate_task(rq_dest, p, 0);
+               check_preempt_curr(rq_dest, p);
        }
        ret = 1;
 out:
@@ -5342,7 +5035,8 @@ static void migrate_live_tasks(int src_cpu)
        write_unlock_irq(&tasklist_lock);
 }
 
-/* Schedules idle task to be the next runnable task on current CPU.
+/*
+ * Schedules idle task to be the next runnable task on current CPU.
  * It does so by boosting its priority to highest possible and adding it to
  * the _front_ of the runqueue. Used by CPU offline code.
  */
@@ -5362,10 +5056,10 @@ void sched_idle_next(void)
         */
        spin_lock_irqsave(&rq->lock, flags);
 
-       __setscheduler(p, SCHED_FIFO, MAX_RT_PRIO-1);
+       __setscheduler(rq, p, SCHED_FIFO, MAX_RT_PRIO-1);
 
        /* Add idle task to the _front_ of its priority queue: */
-       __activate_idle_task(p, rq);
+       activate_idle_task(p, rq);
 
        spin_unlock_irqrestore(&rq->lock, flags);
 }
@@ -5415,16 +5109,15 @@ static void migrate_dead(unsigned int dead_cpu, struct task_struct *p)
 static void migrate_dead_tasks(unsigned int dead_cpu)
 {
        struct rq *rq = cpu_rq(dead_cpu);
-       unsigned int arr, i;
+       struct task_struct *next;
 
-       for (arr = 0; arr < 2; arr++) {
-               for (i = 0; i < MAX_PRIO; i++) {
-                       struct list_head *list = &rq->arrays[arr].queue[i];
-
-                       while (!list_empty(list))
-                               migrate_dead(dead_cpu, list_entry(list->next,
-                                            struct task_struct, run_list));
-               }
+       for ( ; ; ) {
+               if (!rq->nr_running)
+                       break;
+               next = pick_next_task(rq, rq->curr, rq_clock(rq));
+               if (!next)
+                       break;
+               migrate_dead(dead_cpu, next);
        }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
@@ -5448,14 +5141,14 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
 
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
+               p = kthread_create(migration_thread, hcpu, "migration/%d", cpu);
                if (IS_ERR(p))
                        return NOTIFY_BAD;
                p->flags |= PF_NOFREEZE;
                kthread_bind(p, cpu);
                /* Must be high prio: stop_machine expects to yield to it. */
                rq = task_rq_lock(p, &flags);
-               __setscheduler(p, SCHED_FIFO, MAX_RT_PRIO-1);
+               __setscheduler(rq, p, SCHED_FIFO, MAX_RT_PRIO-1);
                task_rq_unlock(rq, &flags);
                cpu_rq(cpu)->migration_thread = p;
                break;
@@ -5486,9 +5179,10 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                rq->migration_thread = NULL;
                /* Idle task back to normal (off runqueue, low prio) */
                rq = task_rq_lock(rq->idle, &flags);
-               deactivate_task(rq->idle, rq);
+               deactivate_task(rq, rq->idle, 0);
                rq->idle->static_prio = MAX_PRIO;
-               __setscheduler(rq->idle, SCHED_NORMAL, 0);
+               __setscheduler(rq, rq->idle, SCHED_NORMAL, 0);
+               rq->idle->sched_class = &idle_sched_class;
                migrate_dead_tasks(cpu);
                task_rq_unlock(rq, &flags);
                migrate_nr_uninterruptible(rq);
@@ -5797,483 +5491,6 @@ init_sched_build_groups(cpumask_t span, const cpumask_t *cpu_map,
 
 #define SD_NODES_PER_DOMAIN 16
 
-/*
- * Self-tuning task migration cost measurement between source and target CPUs.
- *
- * This is done by measuring the cost of manipulating buffers of varying
- * sizes. For a given buffer-size here are the steps that are taken:
- *
- * 1) the source CPU reads+dirties a shared buffer
- * 2) the target CPU reads+dirties the same shared buffer
- *
- * We measure how long they take, in the following 4 scenarios:
- *
- *  - source: CPU1, target: CPU2 | cost1
- *  - source: CPU2, target: CPU1 | cost2
- *  - source: CPU1, target: CPU1 | cost3
- *  - source: CPU2, target: CPU2 | cost4
- *
- * We then calculate the cost3+cost4-cost1-cost2 difference - this is
- * the cost of migration.
- *
- * We then start off from a small buffer-size and iterate up to larger
- * buffer sizes, in 5% steps - measuring each buffer-size separately, and
- * doing a maximum search for the cost. (The maximum cost for a migration
- * normally occurs when the working set size is around the effective cache
- * size.)
- */
-#define SEARCH_SCOPE           2
-#define MIN_CACHE_SIZE         (64*1024U)
-#define DEFAULT_CACHE_SIZE     (5*1024*1024U)
-#define ITERATIONS             1
-#define SIZE_THRESH            130
-#define COST_THRESH            130
-
-/*
- * The migration cost is a function of 'domain distance'. Domain
- * distance is the number of steps a CPU has to iterate down its
- * domain tree to share a domain with the other CPU. The farther
- * two CPUs are from each other, the larger the distance gets.
- *
- * Note that we use the distance only to cache measurement results,
- * the distance value is not used numerically otherwise. When two
- * CPUs have the same distance it is assumed that the migration
- * cost is the same. (this is a simplification but quite practical)
- */
-#define MAX_DOMAIN_DISTANCE 32
-
-static unsigned long long migration_cost[MAX_DOMAIN_DISTANCE] =
-               { [ 0 ... MAX_DOMAIN_DISTANCE-1 ] =
-/*
- * Architectures may override the migration cost and thus avoid
- * boot-time calibration. Unit is nanoseconds. Mostly useful for
- * virtualized hardware:
- */
-#ifdef CONFIG_DEFAULT_MIGRATION_COST
-                       CONFIG_DEFAULT_MIGRATION_COST
-#else
-                       -1LL
-#endif
-};
-
-/*
- * Allow override of migration cost - in units of microseconds.
- * E.g. migration_cost=1000,2000,3000 will set up a level-1 cost
- * of 1 msec, level-2 cost of 2 msecs and level3 cost of 3 msecs:
- */
-static int __init migration_cost_setup(char *str)
-{
-       int ints[MAX_DOMAIN_DISTANCE+1], i;
-
-       str = get_options(str, ARRAY_SIZE(ints), ints);
-
-       printk("#ints: %d\n", ints[0]);
-       for (i = 1; i <= ints[0]; i++) {
-               migration_cost[i-1] = (unsigned long long)ints[i]*1000;
-               printk("migration_cost[%d]: %Ld\n", i-1, migration_cost[i-1]);
-       }
-       return 1;
-}
-
-__setup ("migration_cost=", migration_cost_setup);
-
-/*
- * Global multiplier (divisor) for migration-cutoff values,
- * in percentiles. E.g. use a value of 150 to get 1.5 times
- * longer cache-hot cutoff times.
- *
- * (We scale it from 100 to 128 to long long handling easier.)
- */
-
-#define MIGRATION_FACTOR_SCALE 128
-
-static unsigned int migration_factor = MIGRATION_FACTOR_SCALE;
-
-static int __init setup_migration_factor(char *str)
-{
-       get_option(&str, &migration_factor);
-       migration_factor = migration_factor * MIGRATION_FACTOR_SCALE / 100;
-       return 1;
-}
-
-__setup("migration_factor=", setup_migration_factor);
-
-/*
- * Estimated distance of two CPUs, measured via the number of domains
- * we have to pass for the two CPUs to be in the same span:
- */
-static unsigned long domain_distance(int cpu1, int cpu2)
-{
-       unsigned long distance = 0;
-       struct sched_domain *sd;
-
-       for_each_domain(cpu1, sd) {
-               WARN_ON(!cpu_isset(cpu1, sd->span));
-               if (cpu_isset(cpu2, sd->span))
-                       return distance;
-               distance++;
-       }
-       if (distance >= MAX_DOMAIN_DISTANCE) {
-               WARN_ON(1);
-               distance = MAX_DOMAIN_DISTANCE-1;
-       }
-
-       return distance;
-}
-
-static unsigned int migration_debug;
-
-static int __init setup_migration_debug(char *str)
-{
-       get_option(&str, &migration_debug);
-       return 1;
-}
-
-__setup("migration_debug=", setup_migration_debug);
-
-/*
- * Maximum cache-size that the scheduler should try to measure.
- * Architectures with larger caches should tune this up during
- * bootup. Gets used in the domain-setup code (i.e. during SMP
- * bootup).
- */
-unsigned int max_cache_size;
-
-static int __init setup_max_cache_size(char *str)
-{
-       get_option(&str, &max_cache_size);
-       return 1;
-}
-
-__setup("max_cache_size=", setup_max_cache_size);
-
-/*
- * Dirty a big buffer in a hard-to-predict (for the L2 cache) way. This
- * is the operation that is timed, so we try to generate unpredictable
- * cachemisses that still end up filling the L2 cache:
- */
-static void touch_cache(void *__cache, unsigned long __size)
-{
-       unsigned long size = __size / sizeof(long);
-       unsigned long chunk1 = size / 3;
-       unsigned long chunk2 = 2 * size / 3;
-       unsigned long *cache = __cache;
-       int i;
-
-       for (i = 0; i < size/6; i += 8) {
-               switch (i % 6) {
-                       case 0: cache[i]++;
-                       case 1: cache[size-1-i]++;
-                       case 2: cache[chunk1-i]++;
-                       case 3: cache[chunk1+i]++;
-                       case 4: cache[chunk2-i]++;
-                       case 5: cache[chunk2+i]++;
-               }
-       }
-}
-
-/*
- * Measure the cache-cost of one task migration. Returns in units of nsec.
- */
-static unsigned long long
-measure_one(void *cache, unsigned long size, int source, int target)
-{
-       cpumask_t mask, saved_mask;
-       unsigned long long t0, t1, t2, t3, cost;
-
-       saved_mask = current->cpus_allowed;
-
-       /*
-        * Flush source caches to RAM and invalidate them:
-        */
-       sched_cacheflush();
-
-       /*
-        * Migrate to the source CPU:
-        */
-       mask = cpumask_of_cpu(source);
-       set_cpus_allowed(current, mask);
-       WARN_ON(smp_processor_id() != source);
-
-       /*
-        * Dirty the working set:
-        */
-       t0 = sched_clock();
-       touch_cache(cache, size);
-       t1 = sched_clock();
-
-       /*
-        * Migrate to the target CPU, dirty the L2 cache and access
-        * the shared buffer. (which represents the working set
-        * of a migrated task.)
-        */
-       mask = cpumask_of_cpu(target);
-       set_cpus_allowed(current, mask);
-       WARN_ON(smp_processor_id() != target);
-
-       t2 = sched_clock();
-       touch_cache(cache, size);
-       t3 = sched_clock();
-
-       cost = t1-t0 + t3-t2;
-
-       if (migration_debug >= 2)
-               printk("[%d->%d]: %8Ld %8Ld %8Ld => %10Ld.\n",
-                       source, target, t1-t0, t1-t0, t3-t2, cost);
-       /*
-        * Flush target caches to RAM and invalidate them:
-        */
-       sched_cacheflush();
-
-       set_cpus_allowed(current, saved_mask);
-
-       return cost;
-}
-
-/*
- * Measure a series of task migrations and return the average
- * result. Since this code runs early during bootup the system
- * is 'undisturbed' and the average latency makes sense.
- *
- * The algorithm in essence auto-detects the relevant cache-size,
- * so it will properly detect different cachesizes for different
- * cache-hierarchies, depending on how the CPUs are connected.
- *
- * Architectures can prime the upper limit of the search range via
- * max_cache_size, otherwise the search range defaults to 20MB...64K.
- */
-static unsigned long long
-measure_cost(int cpu1, int cpu2, void *cache, unsigned int size)
-{
-       unsigned long long cost1, cost2;
-       int i;
-
-       /*
-        * Measure the migration cost of 'size' bytes, over an
-        * average of 10 runs:
-        *
-        * (We perturb the cache size by a small (0..4k)
-        *  value to compensate size/alignment related artifacts.
-        *  We also subtract the cost of the operation done on
-        *  the same CPU.)
-        */
-       cost1 = 0;
-
-       /*
-        * dry run, to make sure we start off cache-cold on cpu1,
-        * and to get any vmalloc pagefaults in advance:
-        */
-       measure_one(cache, size, cpu1, cpu2);
-       for (i = 0; i < ITERATIONS; i++)
-               cost1 += measure_one(cache, size - i * 1024, cpu1, cpu2);
-
-       measure_one(cache, size, cpu2, cpu1);
-       for (i = 0; i < ITERATIONS; i++)
-               cost1 += measure_one(cache, size - i * 1024, cpu2, cpu1);
-
-       /*
-        * (We measure the non-migrating [cached] cost on both
-        *  cpu1 and cpu2, to handle CPUs with different speeds)
-        */
-       cost2 = 0;
-
-       measure_one(cache, size, cpu1, cpu1);
-       for (i = 0; i < ITERATIONS; i++)
-               cost2 += measure_one(cache, size - i * 1024, cpu1, cpu1);
-
-       measure_one(cache, size, cpu2, cpu2);
-       for (i = 0; i < ITERATIONS; i++)
-               cost2 += measure_one(cache, size - i * 1024, cpu2, cpu2);
-
-       /*
-        * Get the per-iteration migration cost:
-        */
-       do_div(cost1, 2 * ITERATIONS);
-       do_div(cost2, 2 * ITERATIONS);
-
-       return cost1 - cost2;
-}
-
-static unsigned long long measure_migration_cost(int cpu1, int cpu2)
-{
-       unsigned long long max_cost = 0, fluct = 0, avg_fluct = 0;
-       unsigned int max_size, size, size_found = 0;
-       long long cost = 0, prev_cost;
-       void *cache;
-
-       /*
-        * Search from max_cache_size*5 down to 64K - the real relevant
-        * cachesize has to lie somewhere inbetween.
-        */
-       if (max_cache_size) {
-               max_size = max(max_cache_size * SEARCH_SCOPE, MIN_CACHE_SIZE);
-               size = max(max_cache_size / SEARCH_SCOPE, MIN_CACHE_SIZE);
-       } else {
-               /*
-                * Since we have no estimation about the relevant
-                * search range
-                */
-               max_size = DEFAULT_CACHE_SIZE * SEARCH_SCOPE;
-               size = MIN_CACHE_SIZE;
-       }
-
-       if (!cpu_online(cpu1) || !cpu_online(cpu2)) {
-               printk("cpu %d and %d not both online!\n", cpu1, cpu2);
-               return 0;
-       }
-
-       /*
-        * Allocate the working set:
-        */
-       cache = vmalloc(max_size);
-       if (!cache) {
-               printk("could not vmalloc %d bytes for cache!\n", 2 * max_size);
-               return 1000000; /* return 1 msec on very small boxen */
-       }
-
-       while (size <= max_size) {
-               prev_cost = cost;
-               cost = measure_cost(cpu1, cpu2, cache, size);
-
-               /*
-                * Update the max:
-                */
-               if (cost > 0) {
-                       if (max_cost < cost) {
-                               max_cost = cost;
-                               size_found = size;
-                       }
-               }
-               /*
-                * Calculate average fluctuation, we use this to prevent
-                * noise from triggering an early break out of the loop:
-                */
-               fluct = abs(cost - prev_cost);
-               avg_fluct = (avg_fluct + fluct)/2;
-
-               if (migration_debug)
-                       printk("-> [%d][%d][%7d] %3ld.%ld [%3ld.%ld] (%ld): "
-                               "(%8Ld %8Ld)\n",
-                               cpu1, cpu2, size,
-                               (long)cost / 1000000,
-                               ((long)cost / 100000) % 10,
-                               (long)max_cost / 1000000,
-                               ((long)max_cost / 100000) % 10,
-                               domain_distance(cpu1, cpu2),
-                               cost, avg_fluct);
-
-               /*
-                * If we iterated at least 20% past the previous maximum,
-                * and the cost has dropped by more than 20% already,
-                * (taking fluctuations into account) then we assume to
-                * have found the maximum and break out of the loop early:
-                */
-               if (size_found && (size*100 > size_found*SIZE_THRESH))
-                       if (cost+avg_fluct <= 0 ||
-                               max_cost*100 > (cost+avg_fluct)*COST_THRESH) {
-
-                               if (migration_debug)
-                                       printk("-> found max.\n");
-                               break;
-                       }
-               /*
-                * Increase the cachesize in 10% steps:
-                */
-               size = size * 10 / 9;
-       }
-
-       if (migration_debug)
-               printk("[%d][%d] working set size found: %d, cost: %Ld\n",
-                       cpu1, cpu2, size_found, max_cost);
-
-       vfree(cache);
-
-       /*
-        * A task is considered 'cache cold' if at least 2 times
-        * the worst-case cost of migration has passed.
-        *
-        * (this limit is only listened to if the load-balancing
-        * situation is 'nice' - if there is a large imbalance we
-        * ignore it for the sake of CPU utilization and
-        * processing fairness.)
-        */
-       return 2 * max_cost * migration_factor / MIGRATION_FACTOR_SCALE;
-}
-
-static void calibrate_migration_costs(const cpumask_t *cpu_map)
-{
-       int cpu1 = -1, cpu2 = -1, cpu, orig_cpu = raw_smp_processor_id();
-       unsigned long j0, j1, distance, max_distance = 0;
-       struct sched_domain *sd;
-
-       j0 = jiffies;
-
-       /*
-        * First pass - calculate the cacheflush times:
-        */
-       for_each_cpu_mask(cpu1, *cpu_map) {
-               for_each_cpu_mask(cpu2, *cpu_map) {
-                       if (cpu1 == cpu2)
-                               continue;
-                       distance = domain_distance(cpu1, cpu2);
-                       max_distance = max(max_distance, distance);
-                       /*
-                        * No result cached yet?
-                        */
-                       if (migration_cost[distance] == -1LL)
-                               migration_cost[distance] =
-                                       measure_migration_cost(cpu1, cpu2);
-               }
-       }
-       /*
-        * Second pass - update the sched domain hierarchy with
-        * the new cache-hot-time estimations:
-        */
-       for_each_cpu_mask(cpu, *cpu_map) {
-               distance = 0;
-               for_each_domain(cpu, sd) {
-                       sd->cache_hot_time = migration_cost[distance];
-                       distance++;
-               }
-       }
-       /*
-        * Print the matrix:
-        */
-       if (migration_debug)
-               printk("migration: max_cache_size: %d, cpu: %d MHz:\n",
-                       max_cache_size,
-#ifdef CONFIG_X86
-                       cpu_khz/1000
-#else
-                       -1
-#endif
-               );
-       if (system_state == SYSTEM_BOOTING && num_online_cpus() > 1) {
-               printk("migration_cost=");
-               for (distance = 0; distance <= max_distance; distance++) {
-                       if (distance)
-                               printk(",");
-                       printk("%ld", (long)migration_cost[distance] / 1000);
-               }
-               printk("\n");
-       }
-       j1 = jiffies;
-       if (migration_debug)
-               printk("migration: %ld seconds\n", (j1-j0) / HZ);
-
-       /*
-        * Move back to the original CPU. NUMA-Q gets confused
-        * if we migrate to another quad during bootup.
-        */
-       if (raw_smp_processor_id() != orig_cpu) {
-               cpumask_t mask = cpumask_of_cpu(orig_cpu),
-                       saved_mask = current->cpus_allowed;
-
-               set_cpus_allowed(current, mask);
-               set_cpus_allowed(current, saved_mask);
-       }
-}
-
 #ifdef CONFIG_NUMA
 
 /**
@@ -6574,7 +5791,6 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 static int build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
-       struct sched_domain *sd;
 #ifdef CONFIG_NUMA
        struct sched_group **sched_group_nodes = NULL;
        int sd_allnodes = 0;
@@ -6582,7 +5798,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
        /*
         * Allocate the per-node list of sched groups
         */
-       sched_group_nodes = kzalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
+       sched_group_nodes = kzalloc(sizeof(struct sched_group *)*MAX_NUMNODES,
                                           GFP_KERNEL);
        if (!sched_group_nodes) {
                printk(KERN_WARNING "Can not alloc sched group node list\n");
@@ -6601,8 +5817,8 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                cpus_and(nodemask, nodemask, *cpu_map);
 
 #ifdef CONFIG_NUMA
-               if (cpus_weight(*cpu_map)
-                               SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
+               if (cpus_weight(*cpu_map) >
+                               SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
                        sd = &per_cpu(allnodes_domains, i);
                        *sd = SD_ALLNODES_INIT;
                        sd->span = *cpu_map;
@@ -6661,7 +5877,8 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                if (i != first_cpu(this_sibling_map))
                        continue;
 
-               init_sched_build_groups(this_sibling_map, cpu_map, &cpu_to_cpu_group);
+               init_sched_build_groups(this_sibling_map, cpu_map,
+                                       &cpu_to_cpu_group);
        }
 #endif
 
@@ -6672,11 +5889,11 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                cpus_and(this_core_map, this_core_map, *cpu_map);
                if (i != first_cpu(this_core_map))
                        continue;
-               init_sched_build_groups(this_core_map, cpu_map, &cpu_to_core_group);
+               init_sched_build_groups(this_core_map, cpu_map,
+                                       &cpu_to_core_group);
        }
 #endif
 
-
        /* Set up physical groups */
        for (i = 0; i < MAX_NUMNODES; i++) {
                cpumask_t nodemask = node_to_cpumask(i);
@@ -6691,7 +5908,8 @@ static int build_sched_domains(const cpumask_t *cpu_map)
 #ifdef CONFIG_NUMA
        /* Set up node groups */
        if (sd_allnodes)
-               init_sched_build_groups(*cpu_map, cpu_map, &cpu_to_allnodes_group);
+               init_sched_build_groups(*cpu_map, cpu_map,
+                                       &cpu_to_allnodes_group);
 
        for (i = 0; i < MAX_NUMNODES; i++) {
                /* Set up node groups */
@@ -6719,6 +5937,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                sched_group_nodes[i] = sg;
                for_each_cpu_mask(j, nodemask) {
                        struct sched_domain *sd;
+
                        sd = &per_cpu(node_domains, j);
                        sd->groups = sg;
                }
@@ -6763,19 +5982,22 @@ static int build_sched_domains(const cpumask_t *cpu_map)
        /* Calculate CPU power for physical packages and nodes */
 #ifdef CONFIG_SCHED_SMT
        for_each_cpu_mask(i, *cpu_map) {
-               sd = &per_cpu(cpu_domains, i);
+               struct sched_domain *sd = &per_cpu(cpu_domains, i);
+
                init_sched_groups_power(i, sd);
        }
 #endif
 #ifdef CONFIG_SCHED_MC
        for_each_cpu_mask(i, *cpu_map) {
-               sd = &per_cpu(core_domains, i);
+               struct sched_domain *sd = &per_cpu(core_domains, i);
+
                init_sched_groups_power(i, sd);
        }
 #endif
 
        for_each_cpu_mask(i, *cpu_map) {
-               sd = &per_cpu(phys_domains, i);
+               struct sched_domain *sd = &per_cpu(phys_domains, i);
+
                init_sched_groups_power(i, sd);
        }
 
@@ -6803,10 +6025,6 @@ static int build_sched_domains(const cpumask_t *cpu_map)
 #endif
                cpu_attach_domain(sd, i);
        }
-       /*
-        * Tune cache-hot values:
-        */
-       calibrate_migration_costs(cpu_map);
 
        return 0;
 
@@ -7013,10 +6231,12 @@ void __init sched_init_smp(void)
        /* Move init over to a non-isolated CPU */
        if (set_cpus_allowed(current, non_isolated_cpus) < 0)
                BUG();
+       sched_init_granularity();
 }
 #else
 void __init sched_init_smp(void)
 {
+       sched_init_granularity();
 }
 #endif /* CONFIG_SMP */
 
@@ -7030,28 +6250,51 @@ int in_sched_functions(unsigned long addr)
                && addr < (unsigned long)__sched_text_end);
 }
 
+static inline void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
+{
+       cfs_rq->tasks_timeline = RB_ROOT;
+       cfs_rq->fair_clock = 1;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       cfs_rq->rq = rq;
+#endif
+}
+
 void __init sched_init(void)
 {
-       int i, j, k;
+       u64 now = sched_clock();
        int highest_cpu = 0;
+       int i, j;
+
+       /*
+        * Link up the scheduling class hierarchy:
+        */
+       rt_sched_class.next = &fair_sched_class;
+       fair_sched_class.next = &idle_sched_class;
+       idle_sched_class.next = NULL;
 
        for_each_possible_cpu(i) {
-               struct prio_array *array;
+               struct rt_prio_array *array;
                struct rq *rq;
 
                rq = cpu_rq(i);
                spin_lock_init(&rq->lock);
                lockdep_set_class(&rq->lock, &rq->rq_lock_key);
                rq->nr_running = 0;
-               rq->active = rq->arrays;
-               rq->expired = rq->arrays + 1;
-               rq->best_expired_prio = MAX_PRIO;
+               rq->clock = 1;
+               init_cfs_rq(&rq->cfs, rq);
+#ifdef CONFIG_FAIR_GROUP_SCHED
+               INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
+               list_add(&rq->cfs.leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+#endif
+               rq->ls.load_update_last = now;
+               rq->ls.load_update_start = now;
 
+               for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
+                       rq->cpu_load[j] = 0;
 #ifdef CONFIG_SMP
                rq->sd = NULL;
-               for (j = 1; j < 3; j++)
-                       rq->cpu_load[j] = 0;
                rq->active_balance = 0;
+               rq->next_balance = jiffies;
                rq->push_cpu = 0;
                rq->cpu = i;
                rq->migration_thread = NULL;
@@ -7059,16 +6302,14 @@ void __init sched_init(void)
 #endif
                atomic_set(&rq->nr_iowait, 0);
 
-               for (j = 0; j < 2; j++) {
-                       array = rq->arrays + j;
-                       for (k = 0; k < MAX_PRIO; k++) {
-                               INIT_LIST_HEAD(array->queue + k);
-                               __clear_bit(k, array->bitmap);
-                       }
-                       // delimiter for bitsearch
-                       __set_bit(MAX_PRIO, array->bitmap);
+               array = &rq->rt.active;
+               for (j = 0; j < MAX_RT_PRIO; j++) {
+                       INIT_LIST_HEAD(array->queue + j);
+                       __clear_bit(j, array->bitmap);
                }
                highest_cpu = i;
+               /* delimiter for bitsearch: */
+               __set_bit(MAX_RT_PRIO, array->bitmap);
        }
 
        set_load_weight(&init_task);
@@ -7095,6 +6336,10 @@ void __init sched_init(void)
         * when this runqueue becomes "idle".
         */
        init_idle(current, smp_processor_id());
+       /*
+        * During early bootup we pretend to be a normal task:
+        */
+       current->sched_class = &fair_sched_class;
 }
 
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
@@ -7125,29 +6370,55 @@ EXPORT_SYMBOL(__might_sleep);
 #ifdef CONFIG_MAGIC_SYSRQ
 void normalize_rt_tasks(void)
 {
-       struct prio_array *array;
        struct task_struct *g, *p;
        unsigned long flags;
        struct rq *rq;
+       int on_rq;
 
        read_lock_irq(&tasklist_lock);
-
        do_each_thread(g, p) {
-               if (!rt_task(p))
+               p->se.fair_key                  = 0;
+               p->se.wait_runtime              = 0;
+               p->se.wait_start_fair           = 0;
+               p->se.wait_start                = 0;
+               p->se.exec_start                = 0;
+               p->se.sleep_start               = 0;
+               p->se.sleep_start_fair          = 0;
+               p->se.block_start               = 0;
+               task_rq(p)->cfs.fair_clock      = 0;
+               task_rq(p)->clock               = 0;
+
+               if (!rt_task(p)) {
+                       /*
+                        * Renice negative nice level userspace
+                        * tasks back to 0:
+                        */
+                       if (TASK_NICE(p) < 0 && p->mm)
+                               set_user_nice(p, 0);
                        continue;
+               }
 
                spin_lock_irqsave(&p->pi_lock, flags);
                rq = __task_rq_lock(p);
+#ifdef CONFIG_SMP
+               /*
+                * Do not touch the migration thread:
+                */
+               if (p == rq->migration_thread)
+                       goto out_unlock;
+#endif
 
-               array = p->array;
-               if (array)
-                       deactivate_task(p, task_rq(p));
-               __setscheduler(p, SCHED_NORMAL, 0);
-               if (array) {
-                       __activate_task(p, task_rq(p));
+               on_rq = p->se.on_rq;
+               if (on_rq)
+                       deactivate_task(task_rq(p), p, 0);
+               __setscheduler(rq, p, SCHED_NORMAL, 0);
+               if (on_rq) {
+                       activate_task(task_rq(p), p, 0);
                        resched_task(rq->curr);
                }
-
+#ifdef CONFIG_SMP
+ out_unlock:
+#endif
                __task_rq_unlock(rq);
                spin_unlock_irqrestore(&p->pi_lock, flags);
        } while_each_thread(g, p);
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
new file mode 100644 (file)
index 0000000..1baf87c
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * kernel/time/sched_debug.c
+ *
+ * Print the CFS rbtree
+ *
+ * Copyright(C) 2007, Red Hat, Inc., Ingo Molnar
+ *
+ * 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 <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+#include <linux/utsname.h>
+
+/*
+ * This allows printing both to /proc/sched_debug and
+ * to the console
+ */
+#define SEQ_printf(m, x...)                    \
+ do {                                          \
+       if (m)                                  \
+               seq_printf(m, x);               \
+       else                                    \
+               printk(x);                      \
+ } while (0)
+
+static void
+print_task(struct seq_file *m, struct rq *rq, struct task_struct *p, u64 now)
+{
+       if (rq->curr == p)
+               SEQ_printf(m, "R");
+       else
+               SEQ_printf(m, " ");
+
+       SEQ_printf(m, "%15s %5d %15Ld %13Ld %13Ld %9Ld %5d "
+                     "%15Ld %15Ld %15Ld %15Ld %15Ld\n",
+               p->comm, p->pid,
+               (long long)p->se.fair_key,
+               (long long)(p->se.fair_key - rq->cfs.fair_clock),
+               (long long)p->se.wait_runtime,
+               (long long)(p->nvcsw + p->nivcsw),
+               p->prio,
+               (long long)p->se.sum_exec_runtime,
+               (long long)p->se.sum_wait_runtime,
+               (long long)p->se.sum_sleep_runtime,
+               (long long)p->se.wait_runtime_overruns,
+               (long long)p->se.wait_runtime_underruns);
+}
+
+static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu, u64 now)
+{
+       struct task_struct *g, *p;
+
+       SEQ_printf(m,
+       "\nrunnable tasks:\n"
+       "            task   PID        tree-key         delta       waiting"
+       "  switches  prio"
+       "        sum-exec        sum-wait       sum-sleep"
+       "    wait-overrun   wait-underrun\n"
+       "------------------------------------------------------------------"
+       "----------------"
+       "------------------------------------------------"
+       "--------------------------------\n");
+
+       read_lock_irq(&tasklist_lock);
+
+       do_each_thread(g, p) {
+               if (!p->se.on_rq || task_cpu(p) != rq_cpu)
+                       continue;
+
+               print_task(m, rq, p, now);
+       } while_each_thread(g, p);
+
+       read_unlock_irq(&tasklist_lock);
+}
+
+static void
+print_cfs_rq_runtime_sum(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
+{
+       s64 wait_runtime_rq_sum = 0;
+       struct task_struct *p;
+       struct rb_node *curr;
+       unsigned long flags;
+       struct rq *rq = &per_cpu(runqueues, cpu);
+
+       spin_lock_irqsave(&rq->lock, flags);
+       curr = first_fair(cfs_rq);
+       while (curr) {
+               p = rb_entry(curr, struct task_struct, se.run_node);
+               wait_runtime_rq_sum += p->se.wait_runtime;
+
+               curr = rb_next(curr);
+       }
+       spin_unlock_irqrestore(&rq->lock, flags);
+
+       SEQ_printf(m, "  .%-30s: %Ld\n", "wait_runtime_rq_sum",
+               (long long)wait_runtime_rq_sum);
+}
+
+void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq, u64 now)
+{
+       SEQ_printf(m, "\ncfs_rq %p\n", cfs_rq);
+
+#define P(x) \
+       SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(cfs_rq->x))
+
+       P(fair_clock);
+       P(exec_clock);
+       P(wait_runtime);
+       P(wait_runtime_overruns);
+       P(wait_runtime_underruns);
+       P(sleeper_bonus);
+#undef P
+
+       print_cfs_rq_runtime_sum(m, cpu, cfs_rq);
+}
+
+static void print_cpu(struct seq_file *m, int cpu, u64 now)
+{
+       struct rq *rq = &per_cpu(runqueues, cpu);
+
+#ifdef CONFIG_X86
+       {
+               unsigned int freq = cpu_khz ? : 1;
+
+               SEQ_printf(m, "\ncpu#%d, %u.%03u MHz\n",
+                          cpu, freq / 1000, (freq % 1000));
+       }
+#else
+       SEQ_printf(m, "\ncpu#%d\n", cpu);
+#endif
+
+#define P(x) \
+       SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(rq->x))
+
+       P(nr_running);
+       SEQ_printf(m, "  .%-30s: %lu\n", "load",
+                  rq->ls.load.weight);
+       P(ls.delta_fair);
+       P(ls.delta_exec);
+       P(nr_switches);
+       P(nr_load_updates);
+       P(nr_uninterruptible);
+       SEQ_printf(m, "  .%-30s: %lu\n", "jiffies", jiffies);
+       P(next_balance);
+       P(curr->pid);
+       P(clock);
+       P(prev_clock_raw);
+       P(clock_warps);
+       P(clock_overflows);
+       P(clock_unstable_events);
+       P(clock_max_delta);
+       P(cpu_load[0]);
+       P(cpu_load[1]);
+       P(cpu_load[2]);
+       P(cpu_load[3]);
+       P(cpu_load[4]);
+#undef P
+
+       print_cfs_stats(m, cpu, now);
+
+       print_rq(m, rq, cpu, now);
+}
+
+static int sched_debug_show(struct seq_file *m, void *v)
+{
+       u64 now = ktime_to_ns(ktime_get());
+       int cpu;
+
+       SEQ_printf(m, "Sched Debug Version: v0.04, cfs-v20, %s %.*s\n",
+               init_utsname()->release,
+               (int)strcspn(init_utsname()->version, " "),
+               init_utsname()->version);
+
+       SEQ_printf(m, "now at %Lu nsecs\n", (unsigned long long)now);
+
+       for_each_online_cpu(cpu)
+               print_cpu(m, cpu, now);
+
+       SEQ_printf(m, "\n");
+
+       return 0;
+}
+
+void sysrq_sched_debug_show(void)
+{
+       sched_debug_show(NULL, NULL);
+}
+
+static int sched_debug_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, sched_debug_show, NULL);
+}
+
+static struct file_operations sched_debug_fops = {
+       .open           = sched_debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __init init_sched_debug_procfs(void)
+{
+       struct proc_dir_entry *pe;
+
+       pe = create_proc_entry("sched_debug", 0644, NULL);
+       if (!pe)
+               return -ENOMEM;
+
+       pe->proc_fops = &sched_debug_fops;
+
+       return 0;
+}
+
+__initcall(init_sched_debug_procfs);
+
+void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
+{
+       unsigned long flags;
+       int num_threads = 1;
+
+       rcu_read_lock();
+       if (lock_task_sighand(p, &flags)) {
+               num_threads = atomic_read(&p->signal->count);
+               unlock_task_sighand(p, &flags);
+       }
+       rcu_read_unlock();
+
+       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
+       SEQ_printf(m, "----------------------------------------------\n");
+#define P(F) \
+       SEQ_printf(m, "%-25s:%20Ld\n", #F, (long long)p->F)
+
+       P(se.wait_start);
+       P(se.wait_start_fair);
+       P(se.exec_start);
+       P(se.sleep_start);
+       P(se.sleep_start_fair);
+       P(se.block_start);
+       P(se.sleep_max);
+       P(se.block_max);
+       P(se.exec_max);
+       P(se.wait_max);
+       P(se.wait_runtime);
+       P(se.wait_runtime_overruns);
+       P(se.wait_runtime_underruns);
+       P(se.sum_wait_runtime);
+       P(se.sum_exec_runtime);
+       SEQ_printf(m, "%-25s:%20Ld\n",
+                  "nr_switches", (long long)(p->nvcsw + p->nivcsw));
+       P(se.load.weight);
+       P(policy);
+       P(prio);
+#undef P
+
+       {
+               u64 t0, t1;
+
+               t0 = sched_clock();
+               t1 = sched_clock();
+               SEQ_printf(m, "%-25s:%20Ld\n",
+                          "clock-delta", (long long)(t1-t0));
+       }
+}
+
+void proc_sched_set_task(struct task_struct *p)
+{
+       p->se.sleep_max = p->se.block_max = p->se.exec_max = p->se.wait_max = 0;
+       p->se.wait_runtime_overruns = p->se.wait_runtime_underruns = 0;
+       p->se.sum_exec_runtime = 0;
+}
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
new file mode 100644 (file)
index 0000000..6971db0
--- /dev/null
@@ -0,0 +1,1131 @@
+/*
+ * Completely Fair Scheduling (CFS) Class (SCHED_NORMAL/SCHED_BATCH)
+ *
+ *  Copyright (C) 2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *
+ *  Interactivity improvements by Mike Galbraith
+ *  (C) 2007 Mike Galbraith <efault@gmx.de>
+ *
+ *  Various enhancements by Dmitry Adamushko.
+ *  (C) 2007 Dmitry Adamushko <dmitry.adamushko@gmail.com>
+ *
+ *  Group scheduling enhancements by Srivatsa Vaddagiri
+ *  Copyright IBM Corporation, 2007
+ *  Author: Srivatsa Vaddagiri <vatsa@linux.vnet.ibm.com>
+ *
+ *  Scaled math optimizations by Thomas Gleixner
+ *  Copyright (C) 2007, Thomas Gleixner <tglx@linutronix.de>
+ */
+
+/*
+ * Preemption granularity:
+ * (default: 2 msec, units: nanoseconds)
+ *
+ * NOTE: this granularity value is not the same as the concept of
+ * 'timeslice length' - timeslices in CFS will typically be somewhat
+ * larger than this value. (to see the precise effective timeslice
+ * length of your workload, run vmstat and monitor the context-switches
+ * field)
+ *
+ * On SMP systems the value of this is multiplied by the log2 of the
+ * number of CPUs. (i.e. factor 2x on 2-way systems, 3x on 4-way
+ * systems, 4x on 8-way systems, 5x on 16-way systems, etc.)
+ */
+unsigned int sysctl_sched_granularity __read_mostly = 2000000000ULL/HZ;
+
+/*
+ * SCHED_BATCH wake-up granularity.
+ * (default: 10 msec, units: nanoseconds)
+ *
+ * This option delays the preemption effects of decoupled workloads
+ * and reduces their over-scheduling. Synchronous workloads will still
+ * have immediate wakeup/sleep latencies.
+ */
+unsigned int sysctl_sched_batch_wakeup_granularity __read_mostly =
+                                                       10000000000ULL/HZ;
+
+/*
+ * SCHED_OTHER wake-up granularity.
+ * (default: 1 msec, units: nanoseconds)
+ *
+ * This option delays the preemption effects of decoupled workloads
+ * and reduces their over-scheduling. Synchronous workloads will still
+ * have immediate wakeup/sleep latencies.
+ */
+unsigned int sysctl_sched_wakeup_granularity __read_mostly = 1000000000ULL/HZ;
+
+unsigned int sysctl_sched_stat_granularity __read_mostly;
+
+/*
+ * Initialized in sched_init_granularity():
+ */
+unsigned int sysctl_sched_runtime_limit __read_mostly;
+
+/*
+ * Debugging: various feature bits
+ */
+enum {
+       SCHED_FEAT_FAIR_SLEEPERS        = 1,
+       SCHED_FEAT_SLEEPER_AVG          = 2,
+       SCHED_FEAT_SLEEPER_LOAD_AVG     = 4,
+       SCHED_FEAT_PRECISE_CPU_LOAD     = 8,
+       SCHED_FEAT_START_DEBIT          = 16,
+       SCHED_FEAT_SKIP_INITIAL         = 32,
+};
+
+unsigned int sysctl_sched_features __read_mostly =
+               SCHED_FEAT_FAIR_SLEEPERS        *1 |
+               SCHED_FEAT_SLEEPER_AVG          *1 |
+               SCHED_FEAT_SLEEPER_LOAD_AVG     *1 |
+               SCHED_FEAT_PRECISE_CPU_LOAD     *1 |
+               SCHED_FEAT_START_DEBIT          *1 |
+               SCHED_FEAT_SKIP_INITIAL         *0;
+
+extern struct sched_class fair_sched_class;
+
+/**************************************************************
+ * CFS operations on generic schedulable entities:
+ */
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+/* cpu runqueue to which this cfs_rq is attached */
+static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
+{
+       return cfs_rq->rq;
+}
+
+/* currently running entity (if any) on this cfs_rq */
+static inline struct sched_entity *cfs_rq_curr(struct cfs_rq *cfs_rq)
+{
+       return cfs_rq->curr;
+}
+
+/* An entity is a task if it doesn't "own" a runqueue */
+#define entity_is_task(se)     (!se->my_q)
+
+static inline void
+set_cfs_rq_curr(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       cfs_rq->curr = se;
+}
+
+#else  /* CONFIG_FAIR_GROUP_SCHED */
+
+static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
+{
+       return container_of(cfs_rq, struct rq, cfs);
+}
+
+static inline struct sched_entity *cfs_rq_curr(struct cfs_rq *cfs_rq)
+{
+       struct rq *rq = rq_of(cfs_rq);
+
+       if (unlikely(rq->curr->sched_class != &fair_sched_class))
+               return NULL;
+
+       return &rq->curr->se;
+}
+
+#define entity_is_task(se)     1
+
+static inline void
+set_cfs_rq_curr(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
+static inline struct task_struct *task_of(struct sched_entity *se)
+{
+       return container_of(se, struct task_struct, se);
+}
+
+
+/**************************************************************
+ * Scheduling class tree data structure manipulation methods:
+ */
+
+/*
+ * Enqueue an entity into the rb-tree:
+ */
+static inline void
+__enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
+       struct rb_node *parent = NULL;
+       struct sched_entity *entry;
+       s64 key = se->fair_key;
+       int leftmost = 1;
+
+       /*
+        * Find the right place in the rbtree:
+        */
+       while (*link) {
+               parent = *link;
+               entry = rb_entry(parent, struct sched_entity, run_node);
+               /*
+                * We dont care about collisions. Nodes with
+                * the same key stay together.
+                */
+               if (key - entry->fair_key < 0) {
+                       link = &parent->rb_left;
+               } else {
+                       link = &parent->rb_right;
+                       leftmost = 0;
+               }
+       }
+
+       /*
+        * Maintain a cache of leftmost tree entries (it is frequently
+        * used):
+        */
+       if (leftmost)
+               cfs_rq->rb_leftmost = &se->run_node;
+
+       rb_link_node(&se->run_node, parent, link);
+       rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
+       update_load_add(&cfs_rq->load, se->load.weight);
+       cfs_rq->nr_running++;
+       se->on_rq = 1;
+}
+
+static inline void
+__dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       if (cfs_rq->rb_leftmost == &se->run_node)
+               cfs_rq->rb_leftmost = rb_next(&se->run_node);
+       rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
+       update_load_sub(&cfs_rq->load, se->load.weight);
+       cfs_rq->nr_running--;
+       se->on_rq = 0;
+}
+
+static inline struct rb_node *first_fair(struct cfs_rq *cfs_rq)
+{
+       return cfs_rq->rb_leftmost;
+}
+
+static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
+{
+       return rb_entry(first_fair(cfs_rq), struct sched_entity, run_node);
+}
+
+/**************************************************************
+ * Scheduling class statistics methods:
+ */
+
+/*
+ * We rescale the rescheduling granularity of tasks according to their
+ * nice level, but only linearly, not exponentially:
+ */
+static long
+niced_granularity(struct sched_entity *curr, unsigned long granularity)
+{
+       u64 tmp;
+
+       /*
+        * Negative nice levels get the same granularity as nice-0:
+        */
+       if (likely(curr->load.weight >= NICE_0_LOAD))
+               return granularity;
+       /*
+        * Positive nice level tasks get linearly finer
+        * granularity:
+        */
+       tmp = curr->load.weight * (u64)granularity;
+
+       /*
+        * It will always fit into 'long':
+        */
+       return (long) (tmp >> NICE_0_SHIFT);
+}
+
+static inline void
+limit_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       long limit = sysctl_sched_runtime_limit;
+
+       /*
+        * Niced tasks have the same history dynamic range as
+        * non-niced tasks:
+        */
+       if (unlikely(se->wait_runtime > limit)) {
+               se->wait_runtime = limit;
+               schedstat_inc(se, wait_runtime_overruns);
+               schedstat_inc(cfs_rq, wait_runtime_overruns);
+       }
+       if (unlikely(se->wait_runtime < -limit)) {
+               se->wait_runtime = -limit;
+               schedstat_inc(se, wait_runtime_underruns);
+               schedstat_inc(cfs_rq, wait_runtime_underruns);
+       }
+}
+
+static inline void
+__add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
+{
+       se->wait_runtime += delta;
+       schedstat_add(se, sum_wait_runtime, delta);
+       limit_wait_runtime(cfs_rq, se);
+}
+
+static void
+add_wait_runtime(struct cfs_rq *cfs_rq, struct sched_entity *se, long delta)
+{
+       schedstat_add(cfs_rq, wait_runtime, -se->wait_runtime);
+       __add_wait_runtime(cfs_rq, se, delta);
+       schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
+}
+
+/*
+ * Update the current task's runtime statistics. Skip current tasks that
+ * are not in our scheduling class.
+ */
+static inline void
+__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr, u64 now)
+{
+       unsigned long delta, delta_exec, delta_fair;
+       long delta_mine;
+       struct load_weight *lw = &cfs_rq->load;
+       unsigned long load = lw->weight;
+
+       if (unlikely(!load))
+               return;
+
+       delta_exec = curr->delta_exec;
+#ifdef CONFIG_SCHEDSTATS
+       if (unlikely(delta_exec > curr->exec_max))
+               curr->exec_max = delta_exec;
+#endif
+
+       curr->sum_exec_runtime += delta_exec;
+       cfs_rq->exec_clock += delta_exec;
+
+       delta_fair = calc_delta_fair(delta_exec, lw);
+       delta_mine = calc_delta_mine(delta_exec, curr->load.weight, lw);
+
+       if (cfs_rq->sleeper_bonus > sysctl_sched_stat_granularity) {
+               delta = calc_delta_mine(cfs_rq->sleeper_bonus,
+                                       curr->load.weight, lw);
+               if (unlikely(delta > cfs_rq->sleeper_bonus))
+                       delta = cfs_rq->sleeper_bonus;
+
+               cfs_rq->sleeper_bonus -= delta;
+               delta_mine -= delta;
+       }
+
+       cfs_rq->fair_clock += delta_fair;
+       /*
+        * We executed delta_exec amount of time on the CPU,
+        * but we were only entitled to delta_mine amount of
+        * time during that period (if nr_running == 1 then
+        * the two values are equal)
+        * [Note: delta_mine - delta_exec is negative]:
+        */
+       add_wait_runtime(cfs_rq, curr, delta_mine - delta_exec);
+}
+
+static void update_curr(struct cfs_rq *cfs_rq, u64 now)
+{
+       struct sched_entity *curr = cfs_rq_curr(cfs_rq);
+       unsigned long delta_exec;
+
+       if (unlikely(!curr))
+               return;
+
+       /*
+        * Get the amount of time the current task was running
+        * since the last time we changed load (this cannot
+        * overflow on 32 bits):
+        */
+       delta_exec = (unsigned long)(now - curr->exec_start);
+
+       curr->delta_exec += delta_exec;
+
+       if (unlikely(curr->delta_exec > sysctl_sched_stat_granularity)) {
+               __update_curr(cfs_rq, curr, now);
+               curr->delta_exec = 0;
+       }
+       curr->exec_start = now;
+}
+
+static inline void
+update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       se->wait_start_fair = cfs_rq->fair_clock;
+       se->wait_start = now;
+}
+
+/*
+ * We calculate fair deltas here, so protect against the random effects
+ * of a multiplication overflow by capping it to the runtime limit:
+ */
+#if BITS_PER_LONG == 32
+static inline unsigned long
+calc_weighted(unsigned long delta, unsigned long weight, int shift)
+{
+       u64 tmp = (u64)delta * weight >> shift;
+
+       if (unlikely(tmp > sysctl_sched_runtime_limit*2))
+               return sysctl_sched_runtime_limit*2;
+       return tmp;
+}
+#else
+static inline unsigned long
+calc_weighted(unsigned long delta, unsigned long weight, int shift)
+{
+       return delta * weight >> shift;
+}
+#endif
+
+/*
+ * Task is being enqueued - update stats:
+ */
+static void
+update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       s64 key;
+
+       /*
+        * Are we enqueueing a waiting task? (for current tasks
+        * a dequeue/enqueue event is a NOP)
+        */
+       if (se != cfs_rq_curr(cfs_rq))
+               update_stats_wait_start(cfs_rq, se, now);
+       /*
+        * Update the key:
+        */
+       key = cfs_rq->fair_clock;
+
+       /*
+        * Optimize the common nice 0 case:
+        */
+       if (likely(se->load.weight == NICE_0_LOAD)) {
+               key -= se->wait_runtime;
+       } else {
+               u64 tmp;
+
+               if (se->wait_runtime < 0) {
+                       tmp = -se->wait_runtime;
+                       key += (tmp * se->load.inv_weight) >>
+                                       (WMULT_SHIFT - NICE_0_SHIFT);
+               } else {
+                       tmp = se->wait_runtime;
+                       key -= (tmp * se->load.weight) >> NICE_0_SHIFT;
+               }
+       }
+
+       se->fair_key = key;
+}
+
+/*
+ * Note: must be called with a freshly updated rq->fair_clock.
+ */
+static inline void
+__update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       unsigned long delta_fair = se->delta_fair_run;
+
+#ifdef CONFIG_SCHEDSTATS
+       {
+               s64 delta_wait = now - se->wait_start;
+               if (unlikely(delta_wait > se->wait_max))
+                       se->wait_max = delta_wait;
+       }
+#endif
+
+       if (unlikely(se->load.weight != NICE_0_LOAD))
+               delta_fair = calc_weighted(delta_fair, se->load.weight,
+                                                       NICE_0_SHIFT);
+
+       add_wait_runtime(cfs_rq, se, delta_fair);
+}
+
+static void
+update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       unsigned long delta_fair;
+
+       delta_fair = (unsigned long)min((u64)(2*sysctl_sched_runtime_limit),
+                       (u64)(cfs_rq->fair_clock - se->wait_start_fair));
+
+       se->delta_fair_run += delta_fair;
+       if (unlikely(abs(se->delta_fair_run) >=
+                               sysctl_sched_stat_granularity)) {
+               __update_stats_wait_end(cfs_rq, se, now);
+               se->delta_fair_run = 0;
+       }
+
+       se->wait_start_fair = 0;
+       se->wait_start = 0;
+}
+
+static inline void
+update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       update_curr(cfs_rq, now);
+       /*
+        * Mark the end of the wait period if dequeueing a
+        * waiting task:
+        */
+       if (se != cfs_rq_curr(cfs_rq))
+               update_stats_wait_end(cfs_rq, se, now);
+}
+
+/*
+ * We are picking a new current task - update its stats:
+ */
+static inline void
+update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       /*
+        * We are starting a new run period:
+        */
+       se->exec_start = now;
+}
+
+/*
+ * We are descheduling a task - update its stats:
+ */
+static inline void
+update_stats_curr_end(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       se->exec_start = 0;
+}
+
+/**************************************************
+ * Scheduling class queueing methods:
+ */
+
+static void
+__enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       unsigned long load = cfs_rq->load.weight, delta_fair;
+       long prev_runtime;
+
+       if (sysctl_sched_features & SCHED_FEAT_SLEEPER_LOAD_AVG)
+               load = rq_of(cfs_rq)->cpu_load[2];
+
+       delta_fair = se->delta_fair_sleep;
+
+       /*
+        * Fix up delta_fair with the effect of us running
+        * during the whole sleep period:
+        */
+       if (sysctl_sched_features & SCHED_FEAT_SLEEPER_AVG)
+               delta_fair = div64_likely32((u64)delta_fair * load,
+                                               load + se->load.weight);
+
+       if (unlikely(se->load.weight != NICE_0_LOAD))
+               delta_fair = calc_weighted(delta_fair, se->load.weight,
+                                                       NICE_0_SHIFT);
+
+       prev_runtime = se->wait_runtime;
+       __add_wait_runtime(cfs_rq, se, delta_fair);
+       delta_fair = se->wait_runtime - prev_runtime;
+
+       /*
+        * Track the amount of bonus we've given to sleepers:
+        */
+       cfs_rq->sleeper_bonus += delta_fair;
+
+       schedstat_add(cfs_rq, wait_runtime, se->wait_runtime);
+}
+
+static void
+enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       struct task_struct *tsk = task_of(se);
+       unsigned long delta_fair;
+
+       if ((entity_is_task(se) && tsk->policy == SCHED_BATCH) ||
+                        !(sysctl_sched_features & SCHED_FEAT_FAIR_SLEEPERS))
+               return;
+
+       delta_fair = (unsigned long)min((u64)(2*sysctl_sched_runtime_limit),
+               (u64)(cfs_rq->fair_clock - se->sleep_start_fair));
+
+       se->delta_fair_sleep += delta_fair;
+       if (unlikely(abs(se->delta_fair_sleep) >=
+                               sysctl_sched_stat_granularity)) {
+               __enqueue_sleeper(cfs_rq, se, now);
+               se->delta_fair_sleep = 0;
+       }
+
+       se->sleep_start_fair = 0;
+
+#ifdef CONFIG_SCHEDSTATS
+       if (se->sleep_start) {
+               u64 delta = now - se->sleep_start;
+
+               if ((s64)delta < 0)
+                       delta = 0;
+
+               if (unlikely(delta > se->sleep_max))
+                       se->sleep_max = delta;
+
+               se->sleep_start = 0;
+               se->sum_sleep_runtime += delta;
+       }
+       if (se->block_start) {
+               u64 delta = now - se->block_start;
+
+               if ((s64)delta < 0)
+                       delta = 0;
+
+               if (unlikely(delta > se->block_max))
+                       se->block_max = delta;
+
+               se->block_start = 0;
+               se->sum_sleep_runtime += delta;
+       }
+#endif
+}
+
+static void
+enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
+              int wakeup, u64 now)
+{
+       /*
+        * Update the fair clock.
+        */
+       update_curr(cfs_rq, now);
+
+       if (wakeup)
+               enqueue_sleeper(cfs_rq, se, now);
+
+       update_stats_enqueue(cfs_rq, se, now);
+       __enqueue_entity(cfs_rq, se);
+}
+
+static void
+dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
+              int sleep, u64 now)
+{
+       update_stats_dequeue(cfs_rq, se, now);
+       if (sleep) {
+               se->sleep_start_fair = cfs_rq->fair_clock;
+#ifdef CONFIG_SCHEDSTATS
+               if (entity_is_task(se)) {
+                       struct task_struct *tsk = task_of(se);
+
+                       if (tsk->state & TASK_INTERRUPTIBLE)
+                               se->sleep_start = now;
+                       if (tsk->state & TASK_UNINTERRUPTIBLE)
+                               se->block_start = now;
+               }
+               cfs_rq->wait_runtime -= se->wait_runtime;
+#endif
+       }
+       __dequeue_entity(cfs_rq, se);
+}
+
+/*
+ * Preempt the current task with a newly woken task if needed:
+ */
+static void
+__check_preempt_curr_fair(struct cfs_rq *cfs_rq, struct sched_entity *se,
+                         struct sched_entity *curr, unsigned long granularity)
+{
+       s64 __delta = curr->fair_key - se->fair_key;
+
+       /*
+        * Take scheduling granularity into account - do not
+        * preempt the current task unless the best task has
+        * a larger than sched_granularity fairness advantage:
+        */
+       if (__delta > niced_granularity(curr, granularity))
+               resched_task(rq_of(cfs_rq)->curr);
+}
+
+static inline void
+set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 now)
+{
+       /*
+        * Any task has to be enqueued before it get to execute on
+        * a CPU. So account for the time it spent waiting on the
+        * runqueue. (note, here we rely on pick_next_task() having
+        * done a put_prev_task_fair() shortly before this, which
+        * updated rq->fair_clock - used by update_stats_wait_end())
+        */
+       update_stats_wait_end(cfs_rq, se, now);
+       update_stats_curr_start(cfs_rq, se, now);
+       set_cfs_rq_curr(cfs_rq, se);
+}
+
+static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq, u64 now)
+{
+       struct sched_entity *se = __pick_next_entity(cfs_rq);
+
+       set_next_entity(cfs_rq, se, now);
+
+       return se;
+}
+
+static void
+put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev, u64 now)
+{
+       /*
+        * If still on the runqueue then deactivate_task()
+        * was not called and update_curr() has to be done:
+        */
+       if (prev->on_rq)
+               update_curr(cfs_rq, now);
+
+       update_stats_curr_end(cfs_rq, prev, now);
+
+       if (prev->on_rq)
+               update_stats_wait_start(cfs_rq, prev, now);
+       set_cfs_rq_curr(cfs_rq, NULL);
+}
+
+static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
+{
+       struct rq *rq = rq_of(cfs_rq);
+       struct sched_entity *next;
+       u64 now = __rq_clock(rq);
+
+       /*
+        * Dequeue and enqueue the task to update its
+        * position within the tree:
+        */
+       dequeue_entity(cfs_rq, curr, 0, now);
+       enqueue_entity(cfs_rq, curr, 0, now);
+
+       /*
+        * Reschedule if another task tops the current one.
+        */
+       next = __pick_next_entity(cfs_rq);
+       if (next == curr)
+               return;
+
+       __check_preempt_curr_fair(cfs_rq, next, curr, sysctl_sched_granularity);
+}
+
+/**************************************************
+ * CFS operations on tasks:
+ */
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+/* Walk up scheduling entities hierarchy */
+#define for_each_sched_entity(se) \
+               for (; se; se = se->parent)
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+       return p->se.cfs_rq;
+}
+
+/* runqueue on which this entity is (to be) queued */
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+       return se->cfs_rq;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+       return grp->my_q;
+}
+
+/* Given a group's cfs_rq on one cpu, return its corresponding cfs_rq on
+ * another cpu ('this_cpu')
+ */
+static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
+{
+       /* A later patch will take group into account */
+       return &cpu_rq(this_cpu)->cfs;
+}
+
+/* Iterate thr' all leaf cfs_rq's on a runqueue */
+#define for_each_leaf_cfs_rq(rq, cfs_rq) \
+       list_for_each_entry(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
+
+/* Do the two (enqueued) tasks belong to the same group ? */
+static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
+{
+       if (curr->se.cfs_rq == p->se.cfs_rq)
+               return 1;
+
+       return 0;
+}
+
+#else  /* CONFIG_FAIR_GROUP_SCHED */
+
+#define for_each_sched_entity(se) \
+               for (; se; se = NULL)
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+       return &task_rq(p)->cfs;
+}
+
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+       struct task_struct *p = task_of(se);
+       struct rq *rq = task_rq(p);
+
+       return &rq->cfs;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+       return NULL;
+}
+
+static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
+{
+       return &cpu_rq(this_cpu)->cfs;
+}
+
+#define for_each_leaf_cfs_rq(rq, cfs_rq) \
+               for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
+
+static inline int is_same_group(struct task_struct *curr, struct task_struct *p)
+{
+       return 1;
+}
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
+/*
+ * The enqueue_task method is called before nr_running is
+ * increased. Here we update the fair scheduling stats and
+ * then put the task into the rbtree:
+ */
+static void
+enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
+{
+       struct cfs_rq *cfs_rq;
+       struct sched_entity *se = &p->se;
+
+       for_each_sched_entity(se) {
+               if (se->on_rq)
+                       break;
+               cfs_rq = cfs_rq_of(se);
+               enqueue_entity(cfs_rq, se, wakeup, now);
+       }
+}
+
+/*
+ * The dequeue_task method is called before nr_running is
+ * decreased. We remove the task from the rbtree and
+ * update the fair scheduling stats:
+ */
+static void
+dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep, u64 now)
+{
+       struct cfs_rq *cfs_rq;
+       struct sched_entity *se = &p->se;
+
+       for_each_sched_entity(se) {
+               cfs_rq = cfs_rq_of(se);
+               dequeue_entity(cfs_rq, se, sleep, now);
+               /* Don't dequeue parent if it has other entities besides us */
+               if (cfs_rq->load.weight)
+                       break;
+       }
+}
+
+/*
+ * sched_yield() support is very simple - we dequeue and enqueue
+ */
+static void yield_task_fair(struct rq *rq, struct task_struct *p)
+{
+       struct cfs_rq *cfs_rq = task_cfs_rq(p);
+       u64 now = __rq_clock(rq);
+
+       /*
+        * Dequeue and enqueue the task to update its
+        * position within the tree:
+        */
+       dequeue_entity(cfs_rq, &p->se, 0, now);
+       enqueue_entity(cfs_rq, &p->se, 0, now);
+}
+
+/*
+ * Preempt the current task with a newly woken task if needed:
+ */
+static void check_preempt_curr_fair(struct rq *rq, struct task_struct *p)
+{
+       struct task_struct *curr = rq->curr;
+       struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+       unsigned long gran;
+
+       if (unlikely(rt_prio(p->prio))) {
+               update_curr(cfs_rq, rq_clock(rq));
+               resched_task(curr);
+               return;
+       }
+
+       gran = sysctl_sched_wakeup_granularity;
+       /*
+        * Batch tasks prefer throughput over latency:
+        */
+       if (unlikely(p->policy == SCHED_BATCH))
+               gran = sysctl_sched_batch_wakeup_granularity;
+
+       if (is_same_group(curr, p))
+               __check_preempt_curr_fair(cfs_rq, &p->se, &curr->se, gran);
+}
+
+static struct task_struct *pick_next_task_fair(struct rq *rq, u64 now)
+{
+       struct cfs_rq *cfs_rq = &rq->cfs;
+       struct sched_entity *se;
+
+       if (unlikely(!cfs_rq->nr_running))
+               return NULL;
+
+       do {
+               se = pick_next_entity(cfs_rq, now);
+               cfs_rq = group_cfs_rq(se);
+       } while (cfs_rq);
+
+       return task_of(se);
+}
+
+/*
+ * Account for a descheduled task:
+ */
+static void put_prev_task_fair(struct rq *rq, struct task_struct *prev, u64 now)
+{
+       struct sched_entity *se = &prev->se;
+       struct cfs_rq *cfs_rq;
+
+       for_each_sched_entity(se) {
+               cfs_rq = cfs_rq_of(se);
+               put_prev_entity(cfs_rq, se, now);
+       }
+}
+
+/**************************************************
+ * Fair scheduling class load-balancing methods:
+ */
+
+/*
+ * Load-balancing iterator. Note: while the runqueue stays locked
+ * during the whole iteration, the current task might be
+ * dequeued so the iterator has to be dequeue-safe. Here we
+ * achieve that by always pre-iterating before returning
+ * the current task:
+ */
+static inline struct task_struct *
+__load_balance_iterator(struct cfs_rq *cfs_rq, struct rb_node *curr)
+{
+       struct task_struct *p;
+
+       if (!curr)
+               return NULL;
+
+       p = rb_entry(curr, struct task_struct, se.run_node);
+       cfs_rq->rb_load_balance_curr = rb_next(curr);
+
+       return p;
+}
+
+static struct task_struct *load_balance_start_fair(void *arg)
+{
+       struct cfs_rq *cfs_rq = arg;
+
+       return __load_balance_iterator(cfs_rq, first_fair(cfs_rq));
+}
+
+static struct task_struct *load_balance_next_fair(void *arg)
+{
+       struct cfs_rq *cfs_rq = arg;
+
+       return __load_balance_iterator(cfs_rq, cfs_rq->rb_load_balance_curr);
+}
+
+static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
+{
+       struct sched_entity *curr;
+       struct task_struct *p;
+
+       if (!cfs_rq->nr_running)
+               return MAX_PRIO;
+
+       curr = __pick_next_entity(cfs_rq);
+       p = task_of(curr);
+
+       return p->prio;
+}
+
+static int
+load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+                       unsigned long max_nr_move, unsigned long max_load_move,
+                       struct sched_domain *sd, enum cpu_idle_type idle,
+                       int *all_pinned, unsigned long *total_load_moved)
+{
+       struct cfs_rq *busy_cfs_rq;
+       unsigned long load_moved, total_nr_moved = 0, nr_moved;
+       long rem_load_move = max_load_move;
+       struct rq_iterator cfs_rq_iterator;
+
+       cfs_rq_iterator.start = load_balance_start_fair;
+       cfs_rq_iterator.next = load_balance_next_fair;
+
+       for_each_leaf_cfs_rq(busiest, busy_cfs_rq) {
+               struct cfs_rq *this_cfs_rq;
+               long imbalance;
+               unsigned long maxload;
+               int this_best_prio, best_prio, best_prio_seen = 0;
+
+               this_cfs_rq = cpu_cfs_rq(busy_cfs_rq, this_cpu);
+
+               imbalance = busy_cfs_rq->load.weight -
+                                                this_cfs_rq->load.weight;
+               /* Don't pull if this_cfs_rq has more load than busy_cfs_rq */
+               if (imbalance <= 0)
+                       continue;
+
+               /* Don't pull more than imbalance/2 */
+               imbalance /= 2;
+               maxload = min(rem_load_move, imbalance);
+
+               this_best_prio = cfs_rq_best_prio(this_cfs_rq);
+               best_prio = cfs_rq_best_prio(busy_cfs_rq);
+
+               /*
+                * Enable handling of the case where there is more than one task
+                * with the best priority. If the current running task is one
+                * of those with prio==best_prio we know it won't be moved
+                * and therefore it's safe to override the skip (based on load)
+                * of any task we find with that prio.
+                */
+               if (cfs_rq_curr(busy_cfs_rq) == &busiest->curr->se)
+                       best_prio_seen = 1;
+
+               /* pass busy_cfs_rq argument into
+                * load_balance_[start|next]_fair iterators
+                */
+               cfs_rq_iterator.arg = busy_cfs_rq;
+               nr_moved = balance_tasks(this_rq, this_cpu, busiest,
+                               max_nr_move, maxload, sd, idle, all_pinned,
+                               &load_moved, this_best_prio, best_prio,
+                               best_prio_seen, &cfs_rq_iterator);
+
+               total_nr_moved += nr_moved;
+               max_nr_move -= nr_moved;
+               rem_load_move -= load_moved;
+
+               if (max_nr_move <= 0 || rem_load_move <= 0)
+                       break;
+       }
+
+       *total_load_moved = max_load_move - rem_load_move;
+
+       return total_nr_moved;
+}
+
+/*
+ * scheduler tick hitting a task of our scheduling class:
+ */
+static void task_tick_fair(struct rq *rq, struct task_struct *curr)
+{
+       struct cfs_rq *cfs_rq;
+       struct sched_entity *se = &curr->se;
+
+       for_each_sched_entity(se) {
+               cfs_rq = cfs_rq_of(se);
+               entity_tick(cfs_rq, se);
+       }
+}
+
+/*
+ * Share the fairness runtime between parent and child, thus the
+ * total amount of pressure for CPU stays equal - new tasks
+ * get a chance to run but frequent forkers are not allowed to
+ * monopolize the CPU. Note: the parent runqueue is locked,
+ * the child is not running yet.
+ */
+static void task_new_fair(struct rq *rq, struct task_struct *p)
+{
+       struct cfs_rq *cfs_rq = task_cfs_rq(p);
+       struct sched_entity *se = &p->se;
+       u64 now = rq_clock(rq);
+
+       sched_info_queued(p);
+
+       update_stats_enqueue(cfs_rq, se, now);
+       /*
+        * Child runs first: we let it run before the parent
+        * until it reschedules once. We set up the key so that
+        * it will preempt the parent:
+        */
+       p->se.fair_key = current->se.fair_key -
+               niced_granularity(&rq->curr->se, sysctl_sched_granularity) - 1;
+       /*
+        * The first wait is dominated by the child-runs-first logic,
+        * so do not credit it with that waiting time yet:
+        */
+       if (sysctl_sched_features & SCHED_FEAT_SKIP_INITIAL)
+               p->se.wait_start_fair = 0;
+
+       /*
+        * The statistical average of wait_runtime is about
+        * -granularity/2, so initialize the task with that:
+        */
+       if (sysctl_sched_features & SCHED_FEAT_START_DEBIT)
+               p->se.wait_runtime = -(sysctl_sched_granularity / 2);
+
+       __enqueue_entity(cfs_rq, se);
+       inc_nr_running(p, rq, now);
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/* Account for a task changing its policy or group.
+ *
+ * This routine is mostly called to set cfs_rq->curr field when a task
+ * migrates between groups/classes.
+ */
+static void set_curr_task_fair(struct rq *rq)
+{
+       struct task_struct *curr = rq->curr;
+       struct sched_entity *se = &curr->se;
+       u64 now = rq_clock(rq);
+       struct cfs_rq *cfs_rq;
+
+       for_each_sched_entity(se) {
+               cfs_rq = cfs_rq_of(se);
+               set_next_entity(cfs_rq, se, now);
+       }
+}
+#else
+static void set_curr_task_fair(struct rq *rq)
+{
+}
+#endif
+
+/*
+ * All the scheduling class methods:
+ */
+struct sched_class fair_sched_class __read_mostly = {
+       .enqueue_task           = enqueue_task_fair,
+       .dequeue_task           = dequeue_task_fair,
+       .yield_task             = yield_task_fair,
+
+       .check_preempt_curr     = check_preempt_curr_fair,
+
+       .pick_next_task         = pick_next_task_fair,
+       .put_prev_task          = put_prev_task_fair,
+
+       .load_balance           = load_balance_fair,
+
+       .set_curr_task          = set_curr_task_fair,
+       .task_tick              = task_tick_fair,
+       .task_new               = task_new_fair,
+};
+
+#ifdef CONFIG_SCHED_DEBUG
+void print_cfs_stats(struct seq_file *m, int cpu, u64 now)
+{
+       struct rq *rq = cpu_rq(cpu);
+       struct cfs_rq *cfs_rq;
+
+       for_each_leaf_cfs_rq(rq, cfs_rq)
+               print_cfs_rq(m, cpu, cfs_rq, now);
+}
+#endif
diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c
new file mode 100644 (file)
index 0000000..41841e7
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * idle-task scheduling class.
+ *
+ * (NOTE: these are not related to SCHED_IDLE tasks which are
+ *  handled in sched_fair.c)
+ */
+
+/*
+ * Idle tasks are unconditionally rescheduled:
+ */
+static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p)
+{
+       resched_task(rq->idle);
+}
+
+static struct task_struct *pick_next_task_idle(struct rq *rq, u64 now)
+{
+       schedstat_inc(rq, sched_goidle);
+
+       return rq->idle;
+}
+
+/*
+ * It is not legal to sleep in the idle task - print a warning
+ * message if some code attempts to do it:
+ */
+static void
+dequeue_task_idle(struct rq *rq, struct task_struct *p, int sleep, u64 now)
+{
+       spin_unlock_irq(&rq->lock);
+       printk(KERN_ERR "bad: scheduling from the idle thread!\n");
+       dump_stack();
+       spin_lock_irq(&rq->lock);
+}
+
+static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, u64 now)
+{
+}
+
+static int
+load_balance_idle(struct rq *this_rq, int this_cpu, struct rq *busiest,
+                       unsigned long max_nr_move, unsigned long max_load_move,
+                       struct sched_domain *sd, enum cpu_idle_type idle,
+                       int *all_pinned, unsigned long *total_load_moved)
+{
+       return 0;
+}
+
+static void task_tick_idle(struct rq *rq, struct task_struct *curr)
+{
+}
+
+/*
+ * Simple, special scheduling class for the per-CPU idle tasks:
+ */
+static struct sched_class idle_sched_class __read_mostly = {
+       /* no enqueue/yield_task for idle tasks */
+
+       /* dequeue is not valid, we print a debug message there: */
+       .dequeue_task           = dequeue_task_idle,
+
+       .check_preempt_curr     = check_preempt_curr_idle,
+
+       .pick_next_task         = pick_next_task_idle,
+       .put_prev_task          = put_prev_task_idle,
+
+       .load_balance           = load_balance_idle,
+
+       .task_tick              = task_tick_idle,
+       /* no .task_new for idle tasks */
+};
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
new file mode 100644 (file)
index 0000000..1192a27
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Real-Time Scheduling Class (mapped to the SCHED_FIFO and SCHED_RR
+ * policies)
+ */
+
+/*
+ * Update the current task's runtime statistics. Skip current tasks that
+ * are not in our scheduling class.
+ */
+static inline void update_curr_rt(struct rq *rq, u64 now)
+{
+       struct task_struct *curr = rq->curr;
+       u64 delta_exec;
+
+       if (!task_has_rt_policy(curr))
+               return;
+
+       delta_exec = now - curr->se.exec_start;
+       if (unlikely((s64)delta_exec < 0))
+               delta_exec = 0;
+       if (unlikely(delta_exec > curr->se.exec_max))
+               curr->se.exec_max = delta_exec;
+
+       curr->se.sum_exec_runtime += delta_exec;
+       curr->se.exec_start = now;
+}
+
+static void
+enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup, u64 now)
+{
+       struct rt_prio_array *array = &rq->rt.active;
+
+       list_add_tail(&p->run_list, array->queue + p->prio);
+       __set_bit(p->prio, array->bitmap);
+}
+
+/*
+ * Adding/removing a task to/from a priority array:
+ */
+static void
+dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep, u64 now)
+{
+       struct rt_prio_array *array = &rq->rt.active;
+
+       update_curr_rt(rq, now);
+
+       list_del(&p->run_list);
+       if (list_empty(array->queue + p->prio))
+               __clear_bit(p->prio, array->bitmap);
+}
+
+/*
+ * Put task to the end of the run list without the overhead of dequeue
+ * followed by enqueue.
+ */
+static void requeue_task_rt(struct rq *rq, struct task_struct *p)
+{
+       struct rt_prio_array *array = &rq->rt.active;
+
+       list_move_tail(&p->run_list, array->queue + p->prio);
+}
+
+static void
+yield_task_rt(struct rq *rq, struct task_struct *p)
+{
+       requeue_task_rt(rq, p);
+}
+
+/*
+ * Preempt the current task with a newly woken task if needed:
+ */
+static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p)
+{
+       if (p->prio < rq->curr->prio)
+               resched_task(rq->curr);
+}
+
+static struct task_struct *pick_next_task_rt(struct rq *rq, u64 now)
+{
+       struct rt_prio_array *array = &rq->rt.active;
+       struct task_struct *next;
+       struct list_head *queue;
+       int idx;
+
+       idx = sched_find_first_bit(array->bitmap);
+       if (idx >= MAX_RT_PRIO)
+               return NULL;
+
+       queue = array->queue + idx;
+       next = list_entry(queue->next, struct task_struct, run_list);
+
+       next->se.exec_start = now;
+
+       return next;
+}
+
+static void put_prev_task_rt(struct rq *rq, struct task_struct *p, u64 now)
+{
+       update_curr_rt(rq, now);
+       p->se.exec_start = 0;
+}
+
+/*
+ * Load-balancing iterator. Note: while the runqueue stays locked
+ * during the whole iteration, the current task might be
+ * dequeued so the iterator has to be dequeue-safe. Here we
+ * achieve that by always pre-iterating before returning
+ * the current task:
+ */
+static struct task_struct *load_balance_start_rt(void *arg)
+{
+       struct rq *rq = arg;
+       struct rt_prio_array *array = &rq->rt.active;
+       struct list_head *head, *curr;
+       struct task_struct *p;
+       int idx;
+
+       idx = sched_find_first_bit(array->bitmap);
+       if (idx >= MAX_RT_PRIO)
+               return NULL;
+
+       head = array->queue + idx;
+       curr = head->prev;
+
+       p = list_entry(curr, struct task_struct, run_list);
+
+       curr = curr->prev;
+
+       rq->rt.rt_load_balance_idx = idx;
+       rq->rt.rt_load_balance_head = head;
+       rq->rt.rt_load_balance_curr = curr;
+
+       return p;
+}
+
+static struct task_struct *load_balance_next_rt(void *arg)
+{
+       struct rq *rq = arg;
+       struct rt_prio_array *array = &rq->rt.active;
+       struct list_head *head, *curr;
+       struct task_struct *p;
+       int idx;
+
+       idx = rq->rt.rt_load_balance_idx;
+       head = rq->rt.rt_load_balance_head;
+       curr = rq->rt.rt_load_balance_curr;
+
+       /*
+        * If we arrived back to the head again then
+        * iterate to the next queue (if any):
+        */
+       if (unlikely(head == curr)) {
+               int next_idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1);
+
+               if (next_idx >= MAX_RT_PRIO)
+                       return NULL;
+
+               idx = next_idx;
+               head = array->queue + idx;
+               curr = head->prev;
+
+               rq->rt.rt_load_balance_idx = idx;
+               rq->rt.rt_load_balance_head = head;
+       }
+
+       p = list_entry(curr, struct task_struct, run_list);
+
+       curr = curr->prev;
+
+       rq->rt.rt_load_balance_curr = curr;
+
+       return p;
+}
+
+static int
+load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest,
+                       unsigned long max_nr_move, unsigned long max_load_move,
+                       struct sched_domain *sd, enum cpu_idle_type idle,
+                       int *all_pinned, unsigned long *load_moved)
+{
+       int this_best_prio, best_prio, best_prio_seen = 0;
+       int nr_moved;
+       struct rq_iterator rt_rq_iterator;
+
+       best_prio = sched_find_first_bit(busiest->rt.active.bitmap);
+       this_best_prio = sched_find_first_bit(this_rq->rt.active.bitmap);
+
+       /*
+        * Enable handling of the case where there is more than one task
+        * with the best priority.   If the current running task is one
+        * of those with prio==best_prio we know it won't be moved
+        * and therefore it's safe to override the skip (based on load)
+        * of any task we find with that prio.
+        */
+       if (busiest->curr->prio == best_prio)
+               best_prio_seen = 1;
+
+       rt_rq_iterator.start = load_balance_start_rt;
+       rt_rq_iterator.next = load_balance_next_rt;
+       /* pass 'busiest' rq argument into
+        * load_balance_[start|next]_rt iterators
+        */
+       rt_rq_iterator.arg = busiest;
+
+       nr_moved = balance_tasks(this_rq, this_cpu, busiest, max_nr_move,
+                       max_load_move, sd, idle, all_pinned, load_moved,
+                       this_best_prio, best_prio, best_prio_seen,
+                       &rt_rq_iterator);
+
+       return nr_moved;
+}
+
+static void task_tick_rt(struct rq *rq, struct task_struct *p)
+{
+       /*
+        * RR tasks need a special form of timeslice management.
+        * FIFO tasks have no timeslices.
+        */
+       if (p->policy != SCHED_RR)
+               return;
+
+       if (--p->time_slice)
+               return;
+
+       p->time_slice = static_prio_timeslice(p->static_prio);
+       set_tsk_need_resched(p);
+
+       /* put it at the end of the queue: */
+       requeue_task_rt(rq, p);
+}
+
+/*
+ * No parent/child timeslice management necessary for RT tasks,
+ * just activate them:
+ */
+static void task_new_rt(struct rq *rq, struct task_struct *p)
+{
+       activate_task(rq, p, 1);
+}
+
+static struct sched_class rt_sched_class __read_mostly = {
+       .enqueue_task           = enqueue_task_rt,
+       .dequeue_task           = dequeue_task_rt,
+       .yield_task             = yield_task_rt,
+
+       .check_preempt_curr     = check_preempt_curr_rt,
+
+       .pick_next_task         = pick_next_task_rt,
+       .put_prev_task          = put_prev_task_rt,
+
+       .load_balance           = load_balance_rt,
+
+       .task_tick              = task_tick_rt,
+       .task_new               = task_new_rt,
+};
diff --git a/kernel/sched_stats.h b/kernel/sched_stats.h
new file mode 100644 (file)
index 0000000..c63c38f
--- /dev/null
@@ -0,0 +1,235 @@
+
+#ifdef CONFIG_SCHEDSTATS
+/*
+ * bump this up when changing the output format or the meaning of an existing
+ * format, so that tools can adapt (or abort)
+ */
+#define SCHEDSTAT_VERSION 14
+
+static int show_schedstat(struct seq_file *seq, void *v)
+{
+       int cpu;
+
+       seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
+       seq_printf(seq, "timestamp %lu\n", jiffies);
+       for_each_online_cpu(cpu) {
+               struct rq *rq = cpu_rq(cpu);
+#ifdef CONFIG_SMP
+               struct sched_domain *sd;
+               int dcnt = 0;
+#endif
+
+               /* runqueue-specific stats */
+               seq_printf(seq,
+                   "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %llu %llu %lu",
+                   cpu, rq->yld_both_empty,
+                   rq->yld_act_empty, rq->yld_exp_empty, rq->yld_cnt,
+                   rq->sched_switch, rq->sched_cnt, rq->sched_goidle,
+                   rq->ttwu_cnt, rq->ttwu_local,
+                   rq->rq_sched_info.cpu_time,
+                   rq->rq_sched_info.run_delay, rq->rq_sched_info.pcnt);
+
+               seq_printf(seq, "\n");
+
+#ifdef CONFIG_SMP
+               /* domain-specific stats */
+               preempt_disable();
+               for_each_domain(cpu, sd) {
+                       enum cpu_idle_type itype;
+                       char mask_str[NR_CPUS];
+
+                       cpumask_scnprintf(mask_str, NR_CPUS, sd->span);
+                       seq_printf(seq, "domain%d %s", dcnt++, mask_str);
+                       for (itype = CPU_IDLE; itype < CPU_MAX_IDLE_TYPES;
+                                       itype++) {
+                               seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu "
+                                               "%lu",
+                                   sd->lb_cnt[itype],
+                                   sd->lb_balanced[itype],
+                                   sd->lb_failed[itype],
+                                   sd->lb_imbalance[itype],
+                                   sd->lb_gained[itype],
+                                   sd->lb_hot_gained[itype],
+                                   sd->lb_nobusyq[itype],
+                                   sd->lb_nobusyg[itype]);
+                       }
+                       seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu"
+                           " %lu %lu %lu\n",
+                           sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
+                           sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
+                           sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
+                           sd->ttwu_wake_remote, sd->ttwu_move_affine,
+                           sd->ttwu_move_balance);
+               }
+               preempt_enable();
+#endif
+       }
+       return 0;
+}
+
+static int schedstat_open(struct inode *inode, struct file *file)
+{
+       unsigned int size = PAGE_SIZE * (1 + num_online_cpus() / 32);
+       char *buf = kmalloc(size, GFP_KERNEL);
+       struct seq_file *m;
+       int res;
+
+       if (!buf)
+               return -ENOMEM;
+       res = single_open(file, show_schedstat, NULL);
+       if (!res) {
+               m = file->private_data;
+               m->buf = buf;
+               m->size = size;
+       } else
+               kfree(buf);
+       return res;
+}
+
+const struct file_operations proc_schedstat_operations = {
+       .open    = schedstat_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+/*
+ * Expects runqueue lock to be held for atomicity of update
+ */
+static inline void
+rq_sched_info_arrive(struct rq *rq, unsigned long long delta)
+{
+       if (rq) {
+               rq->rq_sched_info.run_delay += delta;
+               rq->rq_sched_info.pcnt++;
+       }
+}
+
+/*
+ * Expects runqueue lock to be held for atomicity of update
+ */
+static inline void
+rq_sched_info_depart(struct rq *rq, unsigned long long delta)
+{
+       if (rq)
+               rq->rq_sched_info.cpu_time += delta;
+}
+# define schedstat_inc(rq, field)      do { (rq)->field++; } while (0)
+# define schedstat_add(rq, field, amt) do { (rq)->field += (amt); } while (0)
+#else /* !CONFIG_SCHEDSTATS */
+static inline void
+rq_sched_info_arrive(struct rq *rq, unsigned long long delta)
+{}
+static inline void
+rq_sched_info_depart(struct rq *rq, unsigned long long delta)
+{}
+# define schedstat_inc(rq, field)      do { } while (0)
+# define schedstat_add(rq, field, amt) do { } while (0)
+#endif
+
+#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
+/*
+ * Called when a process is dequeued from the active array and given
+ * the cpu.  We should note that with the exception of interactive
+ * tasks, the expired queue will become the active queue after the active
+ * queue is empty, without explicitly dequeuing and requeuing tasks in the
+ * expired queue.  (Interactive tasks may be requeued directly to the
+ * active queue, thus delaying tasks in the expired queue from running;
+ * see scheduler_tick()).
+ *
+ * This function is only called from sched_info_arrive(), rather than
+ * dequeue_task(). Even though a task may be queued and dequeued multiple
+ * times as it is shuffled about, we're really interested in knowing how
+ * long it was from the *first* time it was queued to the time that it
+ * finally hit a cpu.
+ */
+static inline void sched_info_dequeued(struct task_struct *t)
+{
+       t->sched_info.last_queued = 0;
+}
+
+/*
+ * Called when a task finally hits the cpu.  We can now calculate how
+ * long it was waiting to run.  We also note when it began so that we
+ * can keep stats on how long its timeslice is.
+ */
+static void sched_info_arrive(struct task_struct *t)
+{
+       unsigned long long now = sched_clock(), delta = 0;
+
+       if (t->sched_info.last_queued)
+               delta = now - t->sched_info.last_queued;
+       sched_info_dequeued(t);
+       t->sched_info.run_delay += delta;
+       t->sched_info.last_arrival = now;
+       t->sched_info.pcnt++;
+
+       rq_sched_info_arrive(task_rq(t), delta);
+}
+
+/*
+ * Called when a process is queued into either the active or expired
+ * array.  The time is noted and later used to determine how long we
+ * had to wait for us to reach the cpu.  Since the expired queue will
+ * become the active queue after active queue is empty, without dequeuing
+ * and requeuing any tasks, we are interested in queuing to either. It
+ * is unusual but not impossible for tasks to be dequeued and immediately
+ * requeued in the same or another array: this can happen in sched_yield(),
+ * set_user_nice(), and even load_balance() as it moves tasks from runqueue
+ * to runqueue.
+ *
+ * This function is only called from enqueue_task(), but also only updates
+ * the timestamp if it is already not set.  It's assumed that
+ * sched_info_dequeued() will clear that stamp when appropriate.
+ */
+static inline void sched_info_queued(struct task_struct *t)
+{
+       if (unlikely(sched_info_on()))
+               if (!t->sched_info.last_queued)
+                       t->sched_info.last_queued = sched_clock();
+}
+
+/*
+ * Called when a process ceases being the active-running process, either
+ * voluntarily or involuntarily.  Now we can calculate how long we ran.
+ */
+static inline void sched_info_depart(struct task_struct *t)
+{
+       unsigned long long delta = sched_clock() - t->sched_info.last_arrival;
+
+       t->sched_info.cpu_time += delta;
+       rq_sched_info_depart(task_rq(t), delta);
+}
+
+/*
+ * Called when tasks are switched involuntarily due, typically, to expiring
+ * their time slice.  (This may also be called when switching to or from
+ * the idle task.)  We are only called when prev != next.
+ */
+static inline void
+__sched_info_switch(struct task_struct *prev, struct task_struct *next)
+{
+       struct rq *rq = task_rq(prev);
+
+       /*
+        * prev now departs the cpu.  It's not interesting to record
+        * stats about how efficient we were at scheduling the idle
+        * process, however.
+        */
+       if (prev != rq->idle)
+               sched_info_depart(prev);
+
+       if (next != rq->idle)
+               sched_info_arrive(next);
+}
+static inline void
+sched_info_switch(struct task_struct *prev, struct task_struct *next)
+{
+       if (unlikely(sched_info_on()))
+               __sched_info_switch(prev, next);
+}
+#else
+#define sched_info_queued(t)           do { } while (0)
+#define sched_info_switch(t, next)     do { } while (0)
+#endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */
+
index 0b9886a00e74ba33ed59cafb8b02bc9d01570575..73217a9e2875b27909cb4c9db09a6ec2d4284a7c 100644 (file)
@@ -488,7 +488,6 @@ void __init softirq_init(void)
 
 static int ksoftirqd(void * __bind_cpu)
 {
-       set_user_nice(current, 19);
        current->flags |= PF_NOFREEZE;
 
        set_current_state(TASK_INTERRUPTIBLE);
index 30ee462ee79f8646eace494e5244ddaace7f5d95..51f5dac42a00c9f56943a44b7d1865f604d84bde 100644 (file)
@@ -206,7 +206,87 @@ static ctl_table root_table[] = {
        { .ctl_name = 0 }
 };
 
+#ifdef CONFIG_SCHED_DEBUG
+static unsigned long min_sched_granularity_ns = 100000;                /* 100 usecs */
+static unsigned long max_sched_granularity_ns = 1000000000;    /* 1 second */
+static unsigned long min_wakeup_granularity_ns;                        /* 0 usecs */
+static unsigned long max_wakeup_granularity_ns = 1000000000;   /* 1 second */
+#endif
+
 static ctl_table kern_table[] = {
+#ifdef CONFIG_SCHED_DEBUG
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_granularity_ns",
+               .data           = &sysctl_sched_granularity,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_sched_granularity_ns,
+               .extra2         = &max_sched_granularity_ns,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_wakeup_granularity_ns",
+               .data           = &sysctl_sched_wakeup_granularity,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_wakeup_granularity_ns,
+               .extra2         = &max_wakeup_granularity_ns,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_batch_wakeup_granularity_ns",
+               .data           = &sysctl_sched_batch_wakeup_granularity,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_wakeup_granularity_ns,
+               .extra2         = &max_wakeup_granularity_ns,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_stat_granularity_ns",
+               .data           = &sysctl_sched_stat_granularity,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_wakeup_granularity_ns,
+               .extra2         = &max_wakeup_granularity_ns,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_runtime_limit_ns",
+               .data           = &sysctl_sched_runtime_limit,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_sched_granularity_ns,
+               .extra2         = &max_sched_granularity_ns,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_child_runs_first",
+               .data           = &sysctl_sched_child_runs_first,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_features",
+               .data           = &sysctl_sched_features,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
        {
                .ctl_name       = KERN_PANIC,
                .procname       = "panic",
index da95e10cfd7094e8996ab08bb38c1f1bd5d4d6f9..fab32a2863710a328b5f41dc7498515fb7d55b5e 100644 (file)
@@ -105,6 +105,15 @@ config DETECT_SOFTLOCKUP
           can be detected via the NMI-watchdog, on platforms that
           support it.)
 
+config SCHED_DEBUG
+       bool "Collect scheduler debugging info"
+       depends on DEBUG_KERNEL && PROC_FS
+       default y
+       help
+         If you say Y here, the /proc/sched_debug file will be provided
+         that can help debug the scheduler. The runtime overhead of this
+         option is minimal.
+
 config SCHEDSTATS
        bool "Collect scheduler statistics"
        depends on DEBUG_KERNEL && PROC_FS
index d1d9814f99ddd51f982799ca70fa86762d7b48c0..c6ebd9f912abbfb7298c99fcd7432a3636857fb1 100644 (file)
@@ -1245,26 +1245,6 @@ int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long o
        return written;
 }
 
-ssize_t generic_file_sendfile(struct file *in_file, loff_t *ppos,
-                        size_t count, read_actor_t actor, void *target)
-{
-       read_descriptor_t desc;
-
-       if (!count)
-               return 0;
-
-       desc.written = 0;
-       desc.count = count;
-       desc.arg.data = target;
-       desc.error = 0;
-
-       do_generic_file_read(in_file, ppos, &desc, actor);
-       if (desc.written)
-               return desc.written;
-       return desc.error;
-}
-EXPORT_SYMBOL(generic_file_sendfile);
-
 static ssize_t
 do_readahead(struct address_space *mapping, struct file *filp,
             unsigned long index, unsigned long nr)
index fa360e566d88815caafbeaf57533085f334612ab..65ffc321f0c0f223e4c6115e91c53d12d8319399 100644 (file)
@@ -159,28 +159,6 @@ xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
 }
 EXPORT_SYMBOL_GPL(xip_file_read);
 
-ssize_t
-xip_file_sendfile(struct file *in_file, loff_t *ppos,
-            size_t count, read_actor_t actor, void *target)
-{
-       read_descriptor_t desc;
-
-       if (!count)
-               return 0;
-
-       desc.written = 0;
-       desc.count = count;
-       desc.arg.data = target;
-       desc.error = 0;
-
-       do_xip_mapping_read(in_file->f_mapping, &in_file->f_ra, in_file,
-                           ppos, &desc, actor);
-       if (desc.written)
-               return desc.written;
-       return desc.error;
-}
-EXPORT_SYMBOL_GPL(xip_file_sendfile);
-
 /*
  * __xip_unmap is invoked from xip_unmap and
  * xip_write
index b6aae2b33393d96d694145326c6591acf6f83b4b..0493e4d0bcaab2d5b0281446171b4de57598b8ee 100644 (file)
@@ -1100,9 +1100,9 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
         * Normally, filepage is NULL on entry, and either found
         * uptodate immediately, or allocated and zeroed, or read
         * in under swappage, which is then assigned to filepage.
-        * But shmem_prepare_write passes in a locked filepage,
-        * which may be found not uptodate by other callers too,
-        * and may need to be copied from the swappage read in.
+        * But shmem_readpage and shmem_prepare_write pass in a locked
+        * filepage, which may be found not uptodate by other callers
+        * too, and may need to be copied from the swappage read in.
         */
 repeat:
        if (!filepage)
@@ -1485,9 +1485,18 @@ static const struct inode_operations shmem_symlink_inode_operations;
 static const struct inode_operations shmem_symlink_inline_operations;
 
 /*
- * Normally tmpfs makes no use of shmem_prepare_write, but it
- * lets a tmpfs file be used read-write below the loop driver.
+ * Normally tmpfs avoids the use of shmem_readpage and shmem_prepare_write;
+ * but providing them allows a tmpfs file to be used for splice, sendfile, and
+ * below the loop driver, in the generic fashion that many filesystems support.
  */
+static int shmem_readpage(struct file *file, struct page *page)
+{
+       struct inode *inode = page->mapping->host;
+       int error = shmem_getpage(inode, page->index, &page, SGP_CACHE, NULL);
+       unlock_page(page);
+       return error;
+}
+
 static int
 shmem_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
@@ -1711,25 +1720,6 @@ static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count
        return desc.error;
 }
 
-static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
-                        size_t count, read_actor_t actor, void *target)
-{
-       read_descriptor_t desc;
-
-       if (!count)
-               return 0;
-
-       desc.written = 0;
-       desc.count = count;
-       desc.arg.data = target;
-       desc.error = 0;
-
-       do_shmem_file_read(in_file, ppos, &desc, actor);
-       if (desc.written)
-               return desc.written;
-       return desc.error;
-}
-
 static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
@@ -2386,6 +2376,7 @@ static const struct address_space_operations shmem_aops = {
        .writepage      = shmem_writepage,
        .set_page_dirty = __set_page_dirty_no_writeback,
 #ifdef CONFIG_TMPFS
+       .readpage       = shmem_readpage,
        .prepare_write  = shmem_prepare_write,
        .commit_write   = simple_commit_write,
 #endif
@@ -2399,7 +2390,8 @@ static const struct file_operations shmem_file_operations = {
        .read           = shmem_file_read,
        .write          = shmem_file_write,
        .fsync          = simple_sync_file,
-       .sendfile       = shmem_file_sendfile,
+       .splice_read    = generic_file_splice_read,
+       .splice_write   = generic_file_splice_write,
 #endif
 };
 
index c308756c2f9dae7edb6f65d90e98dfbe41fded7a..6398e6e674936af9be7124f897da0478a681e724 100644 (file)
@@ -456,18 +456,13 @@ void
 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
        struct ieee80211softmac_network *add_net)
 {
-       struct list_head *list_ptr;
-       struct ieee80211softmac_network *softmac_net = NULL;
+       struct ieee80211softmac_network *softmac_net;
 
-       list_for_each(list_ptr, &mac->network_list) {
-               softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+       list_for_each_entry(softmac_net, &mac->network_list, list) {
                if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
-                       break;
-               else
-                       softmac_net = NULL;
+                       return;
        }
-       if(softmac_net == NULL)
-               list_add(&(add_net->list), &mac->network_list);
+       list_add(&(add_net->list), &mac->network_list);
 }
 
 /* Add a network to the list, with locking */
@@ -506,16 +501,13 @@ struct ieee80211softmac_network *
 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
        u8 *bssid)
 {
-       struct list_head *list_ptr;
-       struct ieee80211softmac_network *softmac_net = NULL;
-       list_for_each(list_ptr, &mac->network_list) {
-               softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+       struct ieee80211softmac_network *softmac_net;
+
+       list_for_each_entry(softmac_net, &mac->network_list, list) {
                if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
-                       break;
-               else
-                       softmac_net = NULL;
+                       return softmac_net;
        }
-       return softmac_net;
+       return NULL;
 }
 
 /* Get a network from the list by BSSID with locking */
@@ -537,11 +529,9 @@ struct ieee80211softmac_network *
 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
        struct ieee80211softmac_essid *essid)
 {
-       struct list_head *list_ptr;
-       struct ieee80211softmac_network *softmac_net = NULL;
+       struct ieee80211softmac_network *softmac_net;
 
-       list_for_each(list_ptr, &mac->network_list) {
-               softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+       list_for_each_entry(softmac_net, &mac->network_list, list) {
                if (softmac_net->essid.len == essid->len &&
                        !memcmp(softmac_net->essid.data, essid->data, essid->len))
                        return softmac_net;
index 099a983797da329249942ccbbf279c92e8ac853b..c094583386fd2242cfc633e30235153e06d7cf35 100644 (file)
@@ -853,7 +853,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs
        u32 priv_len, maj_stat;
        int pad, saved_len, remaining_len, offset;
 
-       rqstp->rq_sendfile_ok = 0;
+       rqstp->rq_splice_ok = 0;
 
        priv_len = svc_getnl(&buf->head[0]);
        if (rqstp->rq_deferred) {
index e673ef9939043edc4a2d7aac1bf0c745ebd22917..55ea6df069deeb2042b8b1b8dc4c5294d5bfa649 100644 (file)
@@ -814,7 +814,7 @@ svc_process(struct svc_rqst *rqstp)
        rqstp->rq_res.tail[0].iov_base = NULL;
        rqstp->rq_res.tail[0].iov_len = 0;
        /* Will be turned off only in gss privacy case: */
-       rqstp->rq_sendfile_ok = 1;
+       rqstp->rq_splice_ok = 1;
        /* tcp needs a space for the record length... */
        if (rqstp->rq_prot == IPPROTO_TCP)
                svc_putnl(resv, 0);
index 5f38f670102c8940bedc6d90b56d5e8be32e754b..a1aa89f2faf3bc9e6f25ccb3784871d0631a49dd 100644 (file)
@@ -118,7 +118,7 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
        default: return -1;
        }
 
-       chip = dev->private;
+       chip = input_get_drvdata(dev);
        if (! chip || (beep = chip->beep) == NULL)
                return -1;
 
@@ -239,8 +239,8 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip)
        input_dev->evbit[0] = BIT(EV_SND);
        input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
        input_dev->event = snd_pmac_beep_event;
-       input_dev->private = chip;
-       input_dev->cdev.dev = &chip->pdev->dev;
+       input_dev->dev.parent = &chip->pdev->dev;
+       input_set_drvdata(input_dev, chip);
 
        beep->dev = input_dev;
        beep->buf = dmabuf;
@@ -251,8 +251,8 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip)
        err = snd_ctl_add(chip->card, beep_ctl);
        if (err < 0)
                goto fail1;
-       chip->beep = beep;
+
+       chip->beep = beep;
 
        err = input_register_device(beep->dev);
        if (err)