aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2002-01-23 11:27:29 +0000
committerdavem <davem>2002-01-23 11:27:29 +0000
commit5e65d7d736bb6906e4346a0613a426ccdc76ad71 (patch)
tree0be188246d60cef6f5b6efe9ad326bf85eb570d0
parente6c8f6673130f3191c1c16e533a2124bf4b7824d (diff)
downloadnetdev-vger-cvs-5e65d7d736bb6906e4346a0613a426ccdc76ad71.tar.gz
Merge mainline to 2.5.3-pre3
-rw-r--r--CREDITS30
-rw-r--r--Documentation/Changes7
-rw-r--r--Documentation/Configure.help13
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/kernel-api.tmpl4
-rw-r--r--Documentation/DocBook/kernel-hacking.tmpl3
-rw-r--r--Documentation/IRQ-affinity.txt2
-rw-r--r--Documentation/filesystems/devfs/ChangeLog8
-rw-r--r--Documentation/filesystems/devfs/README60
-rw-r--r--Documentation/ioctl-number.txt3
-rw-r--r--Documentation/kernel-parameters.txt7
-rw-r--r--Documentation/pci.txt4
-rw-r--r--MAINTAINERS21
-rw-r--r--Makefile2
-rw-r--r--arch/arm/kernel/process.c2
-rw-r--r--arch/cris/Makefile13
-rw-r--r--arch/cris/README.mm3
-rw-r--r--arch/cris/boot/compressed/README2
-rw-r--r--arch/cris/boot/compressed/misc.c2
-rw-r--r--arch/cris/boot/rescue/head.S12
-rw-r--r--arch/cris/boot/rescue/kimagerescue.S2
-rw-r--r--arch/cris/boot/rescue/testrescue.S2
-rw-r--r--arch/cris/config.in5
-rw-r--r--arch/cris/drivers/Config.in10
-rw-r--r--arch/cris/drivers/axisflashmap.c15
-rw-r--r--arch/cris/drivers/bluetooth/Makefile25
-rw-r--r--arch/cris/drivers/ds1302.c5
-rw-r--r--arch/cris/drivers/eeprom.c3
-rw-r--r--arch/cris/drivers/ethernet.c349
-rw-r--r--arch/cris/drivers/examples/kiobuftest.c3
-rw-r--r--arch/cris/drivers/gpio.c82
-rw-r--r--arch/cris/drivers/i2c.c5
-rw-r--r--arch/cris/drivers/i2c.h2
-rw-r--r--arch/cris/drivers/ide.c5
-rw-r--r--arch/cris/drivers/lpslave/bintocarr.pl2
-rw-r--r--arch/cris/drivers/lpslave/e100lpslave.S2
-rw-r--r--arch/cris/drivers/lpslave/e100lpslavenet.c5
-rw-r--r--arch/cris/drivers/parport.c2
-rw-r--r--arch/cris/drivers/serial.c993
-rw-r--r--arch/cris/drivers/serial.h111
-rw-r--r--arch/cris/drivers/sync_serial.c2
-rw-r--r--arch/cris/drivers/usb-host.c68
-rw-r--r--arch/cris/kernel/Makefile2
-rw-r--r--arch/cris/kernel/debugport.c26
-rw-r--r--arch/cris/kernel/entry.S40
-rw-r--r--arch/cris/kernel/head.S22
-rw-r--r--arch/cris/kernel/irq.c4
-rw-r--r--arch/cris/kernel/kgdb.c5
-rw-r--r--arch/cris/kernel/ksyms.c26
-rw-r--r--arch/cris/kernel/process.c27
-rw-r--r--arch/cris/kernel/ptrace.c23
-rw-r--r--arch/cris/kernel/setup.c77
-rw-r--r--arch/cris/kernel/shadows.c2
-rw-r--r--arch/cris/kernel/sys_cris.c2
-rw-r--r--arch/cris/kernel/time.c27
-rw-r--r--arch/cris/kernel/traps.c129
-rw-r--r--arch/cris/lib/checksum.S2
-rw-r--r--arch/cris/lib/checksumcopy.S2
-rw-r--r--arch/cris/lib/dmacopy.c2
-rw-r--r--arch/cris/lib/dram_init.S5
-rw-r--r--arch/cris/lib/hw_settings.S2
-rw-r--r--arch/cris/lib/old_checksum.c2
-rw-r--r--arch/cris/mm/extable.c3
-rw-r--r--arch/cris/mm/fault.c254
-rw-r--r--arch/cris/mm/init.c36
-rw-r--r--arch/i386/defconfig3
-rw-r--r--arch/i386/kernel/apm.c4
-rw-r--r--arch/i386/kernel/i8259.c4
-rw-r--r--arch/i386/kernel/process.c5
-rw-r--r--arch/i386/kernel/smp.c29
-rw-r--r--arch/i386/kernel/smpboot.c3
-rw-r--r--arch/i386/math-emu/fpu_entry.c2
-rw-r--r--arch/ia64/kernel/process.c4
-rw-r--r--arch/m68k/kernel/process.c2
-rw-r--r--arch/mips/kernel/process.c2
-rw-r--r--arch/mips/math-emu/cp1emu.c3
-rw-r--r--arch/mips64/kernel/process.c2
-rw-r--r--arch/mips64/math-emu/cp1emu.c3
-rw-r--r--arch/parisc/kernel/process.c4
-rw-r--r--arch/ppc/kernel/idle.c18
-rw-r--r--arch/s390/kernel/process.c2
-rw-r--r--arch/s390x/kernel/process.c2
-rw-r--r--arch/sh/kernel/process.c4
-rw-r--r--arch/sparc/kernel/process.c4
-rw-r--r--arch/sparc64/kernel/pci_psycho.c12
-rw-r--r--arch/sparc64/kernel/pci_sabre.c12
-rw-r--r--arch/sparc64/kernel/pci_schizo.c10
-rw-r--r--arch/sparc64/kernel/process.c6
-rw-r--r--arch/sparc64/kernel/sbus.c14
-rw-r--r--arch/sparc64/kernel/smp.c46
-rw-r--r--arch/sparc64/kernel/ttable.S9
-rw-r--r--arch/sparc64/mm/ultra.S10
-rw-r--r--drivers/block/cciss.c695
-rw-r--r--drivers/block/cciss.h3
-rw-r--r--drivers/block/cciss_cmd.h6
-rw-r--r--drivers/block/ll_rw_blk.c7
-rw-r--r--drivers/block/ps2esdi.c12
-rw-r--r--drivers/char/lp.c2
-rw-r--r--drivers/char/mem.c3
-rw-r--r--drivers/char/mwave/3780i.c6
-rw-r--r--drivers/char/ppdev.c8
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/tty_io.c3
-rw-r--r--drivers/hotplug/cpqphp_core.c6
-rw-r--r--drivers/i2c/i2c-algo-bit.c5
-rw-r--r--drivers/i2c/i2c-algo-ite.c2
-rw-r--r--drivers/ide/ide-disk.c67
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-tape.c404
-rw-r--r--drivers/ide/ide-taskfile.c97
-rw-r--r--drivers/ide/ide.c11
-rw-r--r--drivers/ieee1394/Config.in1
-rw-r--r--drivers/ieee1394/Makefile1
-rw-r--r--drivers/ieee1394/csr.c30
-rw-r--r--drivers/ieee1394/dv1394-private.h606
-rw-r--r--drivers/ieee1394/dv1394.c2722
-rw-r--r--drivers/ieee1394/dv1394.h277
-rw-r--r--drivers/ieee1394/highlevel.c95
-rw-r--r--drivers/ieee1394/highlevel.h1
-rw-r--r--drivers/ieee1394/hosts.c242
-rw-r--r--drivers/ieee1394/hosts.h115
-rw-r--r--drivers/ieee1394/ieee1394.h10
-rw-r--r--drivers/ieee1394/ieee1394_core.c274
-rw-r--r--drivers/ieee1394/ieee1394_core.h64
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c4
-rw-r--r--drivers/ieee1394/ieee1394_types.h11
-rw-r--r--drivers/ieee1394/nodemgr.c648
-rw-r--r--drivers/ieee1394/nodemgr.h57
-rw-r--r--drivers/ieee1394/ohci1394.c665
-rw-r--r--drivers/ieee1394/ohci1394.h62
-rw-r--r--drivers/ieee1394/pcilynx.c544
-rw-r--r--drivers/ieee1394/pcilynx.h4
-rw-r--r--drivers/ieee1394/raw1394.c24
-rw-r--r--drivers/ieee1394/sbp2.c394
-rw-r--r--drivers/ieee1394/sbp2.h46
-rw-r--r--drivers/ieee1394/video1394.c233
-rw-r--r--drivers/isdn/Config.in1
-rw-r--r--drivers/isdn/avmb1/b1pci.c235
-rw-r--r--drivers/isdn/avmb1/c4.c80
-rw-r--r--drivers/isdn/avmb1/t1pci.c124
-rw-r--r--drivers/isdn/hisax/Makefile3
-rw-r--r--drivers/isdn/hisax/avm_pci.c6
-rw-r--r--drivers/isdn/hisax/callc.c100
-rw-r--r--drivers/isdn/hisax/config.c18
-rw-r--r--drivers/isdn/hisax/elsa_ser.c6
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c8
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c6
-rw-r--r--drivers/isdn/hisax/hfc_pci.c12
-rw-r--r--drivers/isdn/hisax/hfc_sx.c12
-rw-r--r--drivers/isdn/hisax/hisax.h51
-rw-r--r--drivers/isdn/hisax/hisax_fcclassic.c384
-rw-r--r--drivers/isdn/hisax/hisax_fcclassic.h18
-rw-r--r--drivers/isdn/hisax/hisax_hscx.c421
-rw-r--r--drivers/isdn/hisax/hisax_hscx.h37
-rw-r--r--drivers/isdn/hisax/hscx.c6
-rw-r--r--drivers/isdn/hisax/icc.c6
-rw-r--r--drivers/isdn/hisax/isac.c6
-rw-r--r--drivers/isdn/hisax/isar.c6
-rw-r--r--drivers/isdn/hisax/isdnl1.c28
-rw-r--r--drivers/isdn/hisax/isdnl2.c86
-rw-r--r--drivers/isdn/hisax/isdnl2.h1
-rw-r--r--drivers/isdn/hisax/isdnl3.c26
-rw-r--r--drivers/isdn/hisax/jade.c6
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c38
-rw-r--r--drivers/isdn/hisax/l3dss1.c78
-rw-r--r--drivers/isdn/hisax/l3ni1.c84
-rw-r--r--drivers/isdn/hisax/netjet.c6
-rw-r--r--drivers/isdn/hisax/st5481.h2
-rw-r--r--drivers/isdn/hisax/st5481_d.c2
-rw-r--r--drivers/isdn/hisax/st5481_usb.c4
-rw-r--r--drivers/isdn/hisax/tei.c12
-rw-r--r--drivers/isdn/hisax/w6692.c12
-rw-r--r--drivers/isdn/isdn_common.c1330
-rw-r--r--drivers/isdn/isdn_common.h2
-rw-r--r--drivers/isdn/isdn_ppp.c140
-rw-r--r--drivers/isdn/isdn_ppp.h8
-rw-r--r--drivers/md/md.c3
-rw-r--r--drivers/media/radio/radio-sf16fmi.c6
-rw-r--r--drivers/media/video/c-qcam.c9
-rw-r--r--drivers/media/video/cpia.c9
-rw-r--r--drivers/media/video/cpia_pp.c2
-rw-r--r--drivers/media/video/cpia_usb.c4
-rw-r--r--drivers/media/video/saa5249.c6
-rw-r--r--drivers/mtd/chips/amd_flash.c4
-rw-r--r--drivers/mtd/devices/doc2000.c2
-rw-r--r--drivers/net/Config.in1
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/au1000_eth.c2
-rw-r--r--drivers/net/dl2k.c2
-rw-r--r--drivers/net/pcmcia/Config.in2
-rw-r--r--drivers/net/pcmcia/Makefile2
-rw-r--r--drivers/net/wireless/Config.in13
-rw-r--r--drivers/net/wireless/Makefile5
-rw-r--r--drivers/net/wireless/i82586.h (renamed from drivers/net/i82586.h)0
-rw-r--r--drivers/net/wireless/i82593.h (renamed from drivers/net/pcmcia/i82593.h)0
-rw-r--r--drivers/net/wireless/netwave_cs.c (renamed from drivers/net/pcmcia/netwave_cs.c)2
-rw-r--r--drivers/net/wireless/todo.txt11
-rw-r--r--drivers/net/wireless/wavelan.c (renamed from drivers/net/wavelan.c)0
-rw-r--r--drivers/net/wireless/wavelan.h (renamed from drivers/net/wavelan.h)0
-rw-r--r--drivers/net/wireless/wavelan.p.h (renamed from drivers/net/wavelan.p.h)0
-rw-r--r--drivers/net/wireless/wavelan_cs.c (renamed from drivers/net/pcmcia/wavelan_cs.c)742
-rw-r--r--drivers/net/wireless/wavelan_cs.h (renamed from drivers/net/pcmcia/wavelan.h)9
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h (renamed from drivers/net/pcmcia/wavelan_cs.h)113
-rw-r--r--drivers/parport/ChangeLog20
-rw-r--r--drivers/parport/ieee1284.c2
-rw-r--r--drivers/parport/ieee1284_ops.c43
-rw-r--r--drivers/parport/parport_pc.c32
-rw-r--r--drivers/scsi/advansys.c96
-rw-r--r--drivers/scsi/scsi_debug.c1172
-rw-r--r--drivers/scsi/scsi_debug.h27
-rw-r--r--drivers/scsi/sg.c412
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/sound/emu10k1/audio.c2
-rw-r--r--drivers/sound/emu10k1/midi.c2
-rw-r--r--drivers/sound/emu10k1/mixer.c2
-rw-r--r--drivers/sound/via82cxxx_audio.c4
-rw-r--r--drivers/usb/Makefile5
-rw-r--r--drivers/usb/audio.c8
-rw-r--r--drivers/usb/auerswald.c34
-rw-r--r--drivers/usb/devio.c4
-rw-r--r--drivers/usb/hcd.c51
-rw-r--r--drivers/usb/hcd/Config.in2
-rw-r--r--drivers/usb/hcd/Makefile2
-rw-r--r--drivers/usb/hcd/ehci-hcd.c11
-rw-r--r--drivers/usb/hcd/ehci-hub.c11
-rw-r--r--drivers/usb/hcd/ehci-q.c5
-rw-r--r--drivers/usb/hcd/ehci-sched.c4
-rw-r--r--drivers/usb/hcd/ohci-dbg.c236
-rw-r--r--drivers/usb/hcd/ohci-hcd.c973
-rw-r--r--drivers/usb/hcd/ohci-hub.c267
-rw-r--r--drivers/usb/hcd/ohci-mem.c251
-rw-r--r--drivers/usb/hcd/ohci-q.c1000
-rw-r--r--drivers/usb/hcd/ohci.h360
-rw-r--r--drivers/usb/hpusbscsi.c37
-rw-r--r--drivers/usb/hub.c4
-rw-r--r--drivers/usb/ibmcam.h2
-rw-r--r--drivers/usb/kaweth.c6
-rw-r--r--drivers/usb/microtek.c22
-rw-r--r--drivers/usb/ov511.c6
-rw-r--r--drivers/usb/ov511.h2
-rw-r--r--drivers/usb/pegasus.c2
-rw-r--r--drivers/usb/se401.c2
-rw-r--r--drivers/usb/se401.h4
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.h2
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/ir-usb.c322
-rw-r--r--drivers/usb/serial/keyspan.c64
-rw-r--r--drivers/usb/serial/keyspan.h127
-rw-r--r--drivers/usb/storage/protocol.c4
-rw-r--r--drivers/usb/storage/transport.c2
-rw-r--r--drivers/usb/storage/unusual_devs.h10
-rw-r--r--drivers/usb/storage/usb.c9
-rw-r--r--drivers/usb/stv680.c140
-rw-r--r--drivers/usb/stv680.h145
-rw-r--r--drivers/usb/uhci.c8
-rw-r--r--drivers/usb/usb-ohci.c34
-rw-r--r--drivers/usb/usb-ohci.h12
-rw-r--r--drivers/usb/usb-uhci.c102
-rw-r--r--drivers/usb/usb-uhci.h4
-rw-r--r--drivers/usb/usb.c31
-rw-r--r--drivers/usb/usbvideo.c4
-rw-r--r--drivers/usb/usbvideo.h2
-rw-r--r--drivers/usb/vicam.c30
-rw-r--r--drivers/usb/vicam.h2
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--fs/Makefile.lib2
-rw-r--r--fs/affs/amigaffs.c4
-rw-r--r--fs/affs/bitmap.c16
-rw-r--r--fs/affs/file.c142
-rw-r--r--fs/affs/inode.c61
-rw-r--r--fs/affs/super.c60
-rw-r--r--fs/binfmt_misc.c88
-rw-r--r--fs/block_dev.c14
-rw-r--r--fs/buffer.c129
-rw-r--r--fs/coda/inode.c77
-rw-r--r--fs/coda/psdev.c20
-rw-r--r--fs/devfs/base.c34
-rw-r--r--fs/devpts/inode.c10
-rw-r--r--fs/efs/super.c59
-rw-r--r--fs/ext2/balloc.c227
-rw-r--r--fs/ext2/bitmap.c4
-rw-r--r--fs/ext2/dir.c8
-rw-r--r--fs/ext2/ext2.h120
-rw-r--r--fs/ext2/file.c3
-rw-r--r--fs/ext2/fsync.c3
-rw-r--r--fs/ext2/ialloc.c34
-rw-r--r--fs/ext2/inode.c118
-rw-r--r--fs/ext2/ioctl.c10
-rw-r--r--fs/ext2/namei.c7
-rw-r--r--fs/ext2/super.c60
-rw-r--r--fs/ext2/symlink.c11
-rw-r--r--fs/ext3/ialloc.c41
-rw-r--r--fs/ext3/inode.c158
-rw-r--r--fs/ext3/ioctl.c7
-rw-r--r--fs/ext3/namei.c42
-rw-r--r--fs/ext3/super.c65
-rw-r--r--fs/ext3/symlink.c8
-rw-r--r--fs/fat/dir.c9
-rw-r--r--fs/fat/file.c7
-rw-r--r--fs/fat/inode.c13
-rw-r--r--fs/fat/misc.c48
-rw-r--r--fs/hpfs/anode.c7
-rw-r--r--fs/hpfs/buffer.c84
-rw-r--r--fs/hpfs/dir.c26
-rw-r--r--fs/hpfs/dnode.c46
-rw-r--r--fs/hpfs/ea.c2
-rw-r--r--fs/hpfs/file.c19
-rw-r--r--fs/hpfs/hpfs_fn.h6
-rw-r--r--fs/hpfs/inode.c85
-rw-r--r--fs/hpfs/name.c7
-rw-r--r--fs/hpfs/namei.c42
-rw-r--r--fs/hpfs/super.c63
-rw-r--r--fs/inode.c144
-rw-r--r--fs/intermezzo/journal_ext3.c2
-rw-r--r--fs/intermezzo/journal_obdfs.c2
-rw-r--r--fs/intermezzo/journal_reiserfs.c2
-rw-r--r--fs/intermezzo/kml_reint.c1
-rw-r--r--fs/jbd/commit.c8
-rw-r--r--fs/jffs2/background.c3
-rw-r--r--fs/jffs2/erase.c3
-rw-r--r--fs/jffs2/nodemgmt.c3
-rw-r--r--fs/msdos/msdosfs_syms.c1
-rw-r--r--fs/msdos/namei.c12
-rw-r--r--fs/namei.c2
-rw-r--r--fs/nfs/inode.c203
-rw-r--r--fs/nfs/read.c27
-rw-r--r--fs/nfs/write.c82
-rw-r--r--fs/pipe.c12
-rw-r--r--fs/qnx4/bitmap.c14
-rw-r--r--fs/qnx4/fsync.c2
-rw-r--r--fs/qnx4/inode.c90
-rw-r--r--fs/reiserfs/inode.c7
-rw-r--r--fs/reiserfs/journal.c4
-rw-r--r--fs/ufs/balloc.c8
-rw-r--r--fs/ufs/ialloc.c13
-rw-r--r--fs/ufs/inode.c53
-rw-r--r--fs/ufs/namei.c2
-rw-r--r--fs/ufs/super.c58
-rw-r--r--fs/ufs/symlink.c9
-rw-r--r--fs/ufs/truncate.c19
-rw-r--r--fs/ufs/util.c1
-rw-r--r--fs/umsdos/dir.c12
-rw-r--r--fs/umsdos/inode.c40
-rw-r--r--fs/umsdos/namei.c48
-rw-r--r--fs/umsdos/rdir.c2
-rw-r--r--fs/vfat/namei.c9
-rw-r--r--include/asm-arm/arch-arc/system.h2
-rw-r--r--include/asm-arm/arch-cl7500/system.h2
-rw-r--r--include/asm-arm/arch-ebsa110/system.h6
-rw-r--r--include/asm-arm/arch-ebsa285/system.h4
-rw-r--r--include/asm-arm/arch-nexuspci/system.h2
-rw-r--r--include/asm-arm/arch-rpc/system.h4
-rw-r--r--include/asm-arm/arch-sa1100/system.h2
-rw-r--r--include/asm-arm/arch-tbox/system.h4
-rw-r--r--include/asm-cris/bitops.h90
-rw-r--r--include/asm-cris/elf.h52
-rw-r--r--include/asm-cris/ethernet.h18
-rw-r--r--include/asm-cris/irq.h38
-rw-r--r--include/asm-cris/page.h10
-rw-r--r--include/asm-cris/pgalloc.h8
-rw-r--r--include/asm-cris/pgtable.h10
-rw-r--r--include/asm-cris/processor.h2
-rw-r--r--include/asm-cris/scatterlist.h14
-rw-r--r--include/asm-cris/unistd.h1
-rw-r--r--include/asm-cris/user.h45
-rw-r--r--include/asm-i386/hw_irq.h5
-rw-r--r--include/asm-i386/smplock.h4
-rw-r--r--include/asm-sparc64/irq.h7
-rw-r--r--include/asm-sparc64/pil.h21
-rw-r--r--include/linux/affs_fs.h2
-rw-r--r--include/linux/affs_fs_i.h10
-rw-r--r--include/linux/amigaffs.h12
-rw-r--r--include/linux/blk.h4
-rw-r--r--include/linux/cciss_ioctl.h5
-rw-r--r--include/linux/coda.h1
-rw-r--r--include/linux/coda_fs_i.h1
-rw-r--r--include/linux/coda_linux.h5
-rw-r--r--include/linux/dnotify.h2
-rw-r--r--include/linux/efs_fs.h10
-rw-r--r--include/linux/efs_fs_i.h68
-rw-r--r--include/linux/ext2_fs.h97
-rw-r--r--include/linux/ext2_fs_i.h41
-rw-r--r--include/linux/ext3_fs.h9
-rw-r--r--include/linux/ext3_fs_i.h1
-rw-r--r--include/linux/ext3_jbd.h2
-rw-r--r--include/linux/file.h5
-rw-r--r--include/linux/fs.h74
-rw-r--r--include/linux/hpfs_fs_i.h19
-rw-r--r--include/linux/ide.h21
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/isdn.h2
-rw-r--r--include/linux/mtd/cfi.h2
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/nfs_fs.h160
-rw-r--r--include/linux/nfs_fs_i.h81
-rw-r--r--include/linux/qnx4_fs.h16
-rw-r--r--include/linux/qnx4_fs_i.h39
-rw-r--r--include/linux/reiserfs_fs_sb.h2
-rw-r--r--include/linux/sched.h67
-rw-r--r--include/linux/shmem_fs.h7
-rw-r--r--include/linux/ufs_fs.h223
-rw-r--r--include/linux/ufs_fs_i.h1
-rw-r--r--include/linux/ufs_fs_sb.h221
-rw-r--r--include/linux/umsdos_fs.p5
-rw-r--r--include/linux/usb.h9
-rw-r--r--include/linux/usbdev_fs_i.h11
-rw-r--r--include/linux/usbdev_fs_sb.h13
-rw-r--r--include/linux/wireless.h117
-rw-r--r--include/net/iw_handler.h374
-rw-r--r--include/scsi/sg.h108
-rw-r--r--init/main.c22
-rw-r--r--kernel/fork.c10
-rw-r--r--kernel/ksyms.c8
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/sched.c428
-rw-r--r--kernel/softirq.c3
-rw-r--r--kernel/timer.c3
-rw-r--r--mm/filemap.c4
-rw-r--r--mm/highmem.c6
-rw-r--r--mm/oom_kill.c23
-rw-r--r--mm/shmem.c86
-rw-r--r--mm/swapfile.c4
-rw-r--r--mm/vmscan.c7
-rw-r--r--net/core/Makefile3
-rw-r--r--net/core/dev.c137
-rw-r--r--net/core/wireless.c733
-rw-r--r--net/khttpd/main.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/socket.c15
-rw-r--r--net/sunrpc/sched.c2
431 files changed, 20557 insertions, 8007 deletions
diff --git a/CREDITS b/CREDITS
index 5bdaddc54..b36c8b68f 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1281,6 +1281,13 @@ W: http://www.carumba.com/
D: bug toaster (A1 sauce makes all the difference)
D: Random linux hacker
+N: Tim Hockin
+E: thockin@hockin.org
+W: http://www.hockin.org/~thockin
+D: Natsemi ethernet
+D: Cobalt Networks (x86) support
+D: This-and-That
+
N: Dirk Hohndel
E: hohndel@suse.de
D: The XFree86[tm] Project
@@ -1451,11 +1458,10 @@ S: USA
N: Dave Jones
E: davej@suse.de
-W: http://www.suse.de/~davej
-D: Moved PCI bridge tuning to userspace (Powertweak).
-D: Various x86 (& clones) setup code hacking.
-D: AFFS fixes for 2.3.x
-D: Various Janitorial hacks. (kernel-janitor.sourceforge.net)
+W: http://www.codemonkey.org.uk
+D: x86 errata/setup maintenance.
+D: Backport/Forwardport merge monkey.
+D: Various Janitor work.
S: c/o SuSE Linux UK Ltd
S: The Kinetic Centre
S: Theobald Street
@@ -1660,6 +1666,13 @@ S: ul. Matemblewska 1B/10
S: 80-283 Gdansk
S: Poland
+N: Jakob Kemi
+E: jakob.kemi@telia.com
+D: V4L W9966 Webcam driver
+S: Forsbyvägen 33
+S: 74143 Knivsta
+S: Sweden
+
N: Gero Kuhlmann
E: gero@gkminix.han.de
D: mounting root via NFS
@@ -1832,6 +1845,11 @@ S: Puistokaari 1 E 18
S: 00200 Helsinki
S: Finland
+N: Daniel J. Maas
+E: dmaas@dcine.com
+W: http://www.maasdigital.com
+D: dv1394
+
N: Hamish Macdonald
E: hamishm@lucent.com
D: Linux/68k port
@@ -2526,7 +2544,7 @@ S: Wanniassa ACT 2903
S: Australia
N: Gerard Roudier
-E: groudier@iplus.fr
+E: groudier@free.fr
D: Contributed to asynchronous read-ahead improvement
S: 21 Rue Carnot
S: 95170 Deuil La Barre
diff --git a/Documentation/Changes b/Documentation/Changes
index 8551fc7c8..955627be1 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -50,10 +50,10 @@ with pcmcia-cs.
o Gnu C 2.95.3 # gcc --version
o Gnu make 3.77 # make --version
-o binutils 2.9.5.0.24 # ld -v
+o binutils 2.9.5.0.25 # ld -v
o util-linux 2.10o # fdformat --version
o modutils 2.4.2 # insmod -V
-o e2fsprogs 1.19 # tune2fs
+o e2fsprogs 1.25 # tune2fs
o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs
o pcmcia-cs 3.1.21 # cardmgr -V
o PPP 2.4.0 # pppd --version
@@ -304,8 +304,7 @@ o <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/>
E2fsprogs
---------
-o <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19.tar.gz>
-o <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19-0.src.rpm>
+o <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.25.tar.gz>
Reiserfsprogs
-------------
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 77b10d17e..9c3c11539 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -8144,6 +8144,19 @@ CONFIG_IEEE1394_VIDEO1394
this option only if you have an IEEE 1394 video device connected to
an OHCI-1394 card.
+OHCI-DV I/O support
+CONFIG_IEEE1394_DV1394
+ This driver allows you to transmit and receive DV (digital video)
+ streams on an OHCI-1394 card using a simple frame-oriented
+ interface.
+
+ The user-space API for dv1394 is documented in dv1394.h.
+
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read <file:Documentation/modules.txt>. The module
+ will be called dv1394.o.
+
SBP-2 support (Harddisks etc.)
CONFIG_IEEE1394_SBP2
This option enables you to use SBP-2 devices connected to your IEEE
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 693fa2125..fbd727042 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -93,6 +93,8 @@ APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
$(TOPDIR)/drivers/net/8390.c \
$(TOPDIR)/drivers/char/serial.c \
$(TOPDIR)/drivers/pci/pci.c \
+ $(TOPDIR)/drivers/hotplug/pci_hotplug_core.c \
+ $(TOPDIR)/drivers/hotplug/pci_hotplug_util.c \
$(TOPDIR)/drivers/block/ll_rw_blk.c \
$(TOPDIR)/drivers/sound/sound_core.c \
$(TOPDIR)/drivers/sound/sound_firmware.c \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 448f3234d..69bf70946 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -162,6 +162,10 @@
<sect1><title>PCI Support Library</title>
!Edrivers/pci/pci.c
</sect1>
+ <sect1><title>PCI Hotplug Support Library</title>
+!Edrivers/hotplug/pci_hotplug_core.c
+!Edrivers/hotplug/pci_hotplug_util.c
+ </sect1>
<sect1><title>MCA Architecture</title>
<sect2><title>MCA Device Functions</title>
!Earch/i386/kernel/mca.c
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index b25aa1bf5..bf5a8f6f8 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -371,8 +371,7 @@ if (signal_pending())
</para>
<programlisting>
-if (current-&gt;need_resched)
- schedule(); /* Will sleep */
+cond_resched(); /* Will sleep */
</programlisting>
<para>
diff --git a/Documentation/IRQ-affinity.txt b/Documentation/IRQ-affinity.txt
index 7c582f494..938d7dd05 100644
--- a/Documentation/IRQ-affinity.txt
+++ b/Documentation/IRQ-affinity.txt
@@ -8,7 +8,7 @@ to turn off all CPUs, and if an IRQ controller does not support IRQ
affinity then the value will not change from the default 0xffffffff.
Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting
-the IRQ to CPU4-8 (this is an 8-CPU SMP box):
+the IRQ to CPU4-7 (this is an 8-CPU SMP box):
[root@moon 44]# cat smp_affinity
ffffffff
diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog
index de386c4ea..8a65ff609 100644
--- a/Documentation/filesystems/devfs/ChangeLog
+++ b/Documentation/filesystems/devfs/ChangeLog
@@ -1869,3 +1869,11 @@ Changes for patch v206
- Added support for multiple Compaq cpqarray controllers
- Fixed (rare, old) race in <devfs_lookup>
+===============================================================================
+Changes for patch v207
+
+- Fixed deadlock bug in <devfs_d_revalidate_wait>
+
+- Tag VFS deletable in <devfs_mk_symlink> if handle ignored
+
+- Updated README from master HTML file
diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README
index a34fcd321..9f0e99e96 100644
--- a/Documentation/filesystems/devfs/README
+++ b/Documentation/filesystems/devfs/README
@@ -3,7 +3,16 @@ Devfs (Device File System) FAQ
Linux Devfs (Device File System) FAQ
Richard Gooch
-21-DEC-2001
+20-JAN-2002
+
+
+Document languages:
+
+
+
+
+
+
-----------------------------------------------------------------------------
@@ -69,6 +78,7 @@ Alternatives to devfs
What I don't like about devfs
How to report bugs
Strange kernel messages
+Compilation problems with devfsd
Other resources
@@ -837,8 +847,8 @@ device nodes. You can do this in your boot scripts. All your drivers
will now work as before.
Hopefully for most people devfs will have enough support so that they
-can mount devfs directly over /dev without loosing most functionality
-(i.e. loosing access to various devices). As of 22-JAN-1998 (devfs
+can mount devfs directly over /dev without losing most functionality
+(i.e. losing access to various devices). As of 22-JAN-1998 (devfs
patch version 10) I am now running this way. All the devices I have
are available in devfs, so I don't lose anything.
@@ -1477,6 +1487,7 @@ Alternatives to devfs
What I don't like about devfs
How to report bugs
Strange kernel messages
+Compilation problems with devfsd
@@ -1677,7 +1688,7 @@ unallocated major numbers. USB will also need to push beyond the 8 bit
minor limitation
-simplying increasing the device number size is insufficient. Apart
+simply increasing the device number size is insufficient. Apart
from causing a lot of pain, it doesn't solve the management issues
of a /dev with thousands or more device nodes
@@ -1828,6 +1839,29 @@ The solution is the same as above.
+
+Compilation problems with devfsd
+
+Usually, you can compile devfsd just by typing in
+make in the source directory, followed by a make
+install (as root). Sometimes, you may have problems, particularly
+on broken configurations.
+
+
+
+error messages relating to DEVFSD_NOTIFY_DELETE
+
+This happened because you have an ancient set of kernel headers
+installed in /usr/include/linux or /usr/src/linux.
+Install kernel 2.4.10 or later. You may need to pass the
+KERNEL_DIR variable to make (if you did not install
+the new kernel sources as /usr/src/linux), or you may copy
+the devfs_fs.h file in the kernel source tree into
+/usr/include/linux.
+
+
+
+
-----------------------------------------------------------------------------
@@ -1882,9 +1916,25 @@ This document has been translated into other languages.
+The document master (in English) by rgooch@atnf.csiro.au is
+available at
+
+http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
+
+
+
A Korean translation by viatoris@nownuri.net is available at
-http://home.nownuri.net/~viatoris/devfs/devfs.html
+http://home.nownuri.net/~viatoris/devfs/devfs.html
+
+A newer version is under construcation at
+http://viatoris.new21.org/devfs/devfs.html
+
+
+-----------------------------------------------------------------------------
+Most flags courtesy of ITA's
+Flags of All Countries
+used with permission.
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 4b520113f..711483a87 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -101,7 +101,8 @@ Code Seq# Include File Comments
'S' 82-FF scsi/scsi.h conflict!
'T' all linux/soundcard.h conflict!
'T' all asm-i386/ioctls.h conflict!
-'U' all linux/drivers/usb/usb.h
+'U' 00-EF linux/drivers/usb/usb.h
+'U' F0-FF drivers/usb/auerswald.c
'V' all linux/vt.h
'W' 00-1F linux/watchdog.h conflict!
'W' 00-1F linux/wanrouter.h conflict!
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 97e4026cf..e02079a8d 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -125,6 +125,13 @@ running once the system is up.
BusLogic= [HW,SCSI]
+ cachesize= [BUGS=ix86] Override level 2 CPU cache size detection.
+ Sometimes CPU hardware bugs make them report the cache
+ size incorrectly. The kernel will attempt work arounds
+ to fix known problems, but for some CPUs it is not
+ possible to determine what the correct size should be.
+ This option provides an override for these situations.
+
cdu31a= [HW,CD]
chandev= [HW,NET]
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index dadb9a9dc..5ac05854a 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -104,6 +104,10 @@ Tips:
If you are sure the driver is not a hotplug driver then use only
__init/exit __initdata/exitdata.
+ Pointers to functions marked as __devexit must be created using
+ __devexit_p(function_name). That will generate the function
+ name or NULL if the __devexit function will be discarded.
+
2. How to find PCI devices manually (the old style)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/MAINTAINERS b/MAINTAINERS
index 2ebeced0b..1c4472ec5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -412,6 +412,12 @@ W: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
L: linux-decnet-user@lists.sourceforge.net
S: Maintained
+DELL LAPTOP SMM DRIVER
+P: Massimo Dal Zotto
+M: dz@debian.org
+W: http://www.debian.org/~dz/i8k/
+S: Maintained
+
DEVICE NUMBER REGISTRY
P: H. Peter Anvin
M: hpa@zytor.com
@@ -926,6 +932,12 @@ L: linux-LVM@sistina.com
W: http://www.sistina.com/lvm
S: Maintained
+LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers
+P: Gerard Roudier
+M: groudier@free.fr
+L: linux-scsi@vger.kernel.org
+S: Maintained
+
M68K
P: Jes Sorensen
M: jes@trained-monkey.org
@@ -1010,6 +1022,11 @@ P: Andrew Veliath
M: andrewtv@usa.net
S: Maintained
+NATSEMI ETHERNET DRIVER (DP8381x)
+P: Tim Hockin
+M: thockin@hockin.org
+S: Maintained
+
NCP FILESYSTEM
P: Petr Vandrovec
M: vandrove@vc.cvut.cz
@@ -1133,8 +1150,8 @@ L: linux-scsi@vger.rutgers.edu
S: Maintained
OPL3-SA2, SA3, and SAx DRIVER
-P: Scott Murray
-M: scott@spiteful.org
+P: Zwane Mwaikambo
+M: zwane@commfireservices.com
L: linux-sound@vger.kernel.org
S: Maintained
diff --git a/Makefile b/Makefile
index dc774375b..e4a9258e6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 3
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre3
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 741984e0c..61b592b97 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -91,7 +91,7 @@ void cpu_idle(void)
if (!idle)
idle = arch_idle;
leds_event(led_idle_start);
- while (!current->need_resched)
+ while (!need_resched())
idle();
leds_event(led_idle_end);
schedule();
diff --git a/arch/cris/Makefile b/arch/cris/Makefile
index 61db7aea6..4a9dadc1a 100644
--- a/arch/cris/Makefile
+++ b/arch/cris/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.22 2001/10/01 14:42:38 bjornw Exp $
+# $Id: Makefile,v 1.3 2002/01/21 15:21:23 bjornw Exp $
# cris/Makefile
#
# This file is included by the global makefile so that you can add your own
@@ -29,18 +29,17 @@ LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \
-e s/@CONFIG_ETRAX_DRAM_SIZE_M@/$(CONFIG_ETRAX_DRAM_SIZE)/ \
< $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \
else true; \
- fi && $(CROSS_COMPILE)gcc -mlinux -nostdlib
+ fi && $(CROSS_COMPILE)ld -mcrislinux
-LINKFLAGS = -mlinux -T $(LD_SCRIPT).tmp
+LINKFLAGS = -T $(LD_SCRIPT).tmp
# objcopy is used to make binary images from the resulting linked file
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-# normally, gcc on a linux box adds __linux__ but we do it "manually"
-# -mlinux enables -march=v10, -fno-underscores among others
+# -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others
-CFLAGS := $(CFLAGS) -mlinux -fno-strict-aliasing -pipe -D__linux__
+CFLAGS := $(CFLAGS) -mlinux -pipe
ifdef CONFIG_ETRAX_KGDB
CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g
@@ -57,7 +56,7 @@ ifdef CONFIG_ETRAX_AXISFLASHMAP
# each others config options
SUBDIRS += arch/cris/boot/rescue
endif
-CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o
+CORE_FILES := arch/cris/kernel/kernel.o arch/cris/mm/mm.o $(CORE_FILES)
DRIVERS += arch/cris/drivers/drivers.o
LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
diff --git a/arch/cris/README.mm b/arch/cris/README.mm
index 6de4e7077..195ca898b 100644
--- a/arch/cris/README.mm
+++ b/arch/cris/README.mm
@@ -3,6 +3,9 @@ Memory management for CRIS/MMU
HISTORY:
$Log: README.mm,v $
+Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+Import of Linux 2.5.1
+
Revision 1.1 2000/07/10 16:25:21 bjornw
Initial revision
diff --git a/arch/cris/boot/compressed/README b/arch/cris/boot/compressed/README
index 83e1f1e51..349eb2ab4 100644
--- a/arch/cris/boot/compressed/README
+++ b/arch/cris/boot/compressed/README
@@ -1,6 +1,6 @@
Creation of the self-extracting compressed kernel image (vmlinuz)
-----------------------------------------------------------------
-$Id: README,v 1.1 2000/11/22 17:20:46 bjornw Exp $
+$Id: README,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
This can be slightly confusing because it's a process with many steps.
diff --git a/arch/cris/boot/compressed/misc.c b/arch/cris/boot/compressed/misc.c
index 31a0331d7..cf7a174ff 100644
--- a/arch/cris/boot/compressed/misc.c
+++ b/arch/cris/boot/compressed/misc.c
@@ -1,7 +1,7 @@
/*
* misc.c
*
- * $Id: misc.c,v 1.6 2001/04/09 10:00:21 starvik Exp $
+ * $Id: misc.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* This is a collection of several routines from gzip-1.0.3
* adapted for Linux.
diff --git a/arch/cris/boot/rescue/head.S b/arch/cris/boot/rescue/head.S
index 7904252a3..40f9af6b6 100644
--- a/arch/cris/boot/rescue/head.S
+++ b/arch/cris/boot/rescue/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.8 2001/10/03 17:15:15 bjornw Exp $
+/* $Id: head.S,v 1.2 2001/12/18 13:35:12 bjornw Exp $
*
* Rescue code, made to reside at the beginning of the
* flash-memory. when it starts, it checks a partition
@@ -114,7 +114,7 @@
#define NOP_DI 0xf025050f
#define RAM_INIT_MAGIC 0x56902387
-
+
.text
;; This is the entry point of the rescue code
@@ -144,7 +144,13 @@ jtcd: move.d [jumptarget], $r0
jumptarget:
.dword 0xffffffff ; can be overwritten later to insert new code
-no_newjump:
+no_newjump:
+#ifdef CONFIG_ETRAX_ETHERNET
+ ;; Start MII clock to make sure it is running when tranceiver is reset
+ move.d 0x3, $r0 ; enable = on, phy = mii_clk
+ move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+
;; We need to setup the bus registers before we start using the DRAM
#include "../../lib/dram_init.S"
diff --git a/arch/cris/boot/rescue/kimagerescue.S b/arch/cris/boot/rescue/kimagerescue.S
index 500ed5ede..270774108 100644
--- a/arch/cris/boot/rescue/kimagerescue.S
+++ b/arch/cris/boot/rescue/kimagerescue.S
@@ -1,4 +1,4 @@
-/* $Id: kimagerescue.S,v 1.5 2001/10/03 17:15:15 bjornw Exp $
+/* $Id: kimagerescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* Rescue code to be prepended on a kimage and copied to the
* rescue serial port.
diff --git a/arch/cris/boot/rescue/testrescue.S b/arch/cris/boot/rescue/testrescue.S
index 2e0f0ce00..f39c69e26 100644
--- a/arch/cris/boot/rescue/testrescue.S
+++ b/arch/cris/boot/rescue/testrescue.S
@@ -1,4 +1,4 @@
-/* $Id: testrescue.S,v 1.3 2001/10/03 17:15:15 bjornw Exp $
+/* $Id: testrescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* Simple testcode to download by the rescue block.
* Just lits some LEDs to show it was downloaded correctly.
diff --git a/arch/cris/config.in b/arch/cris/config.in
index 660133597..6a38f9bc8 100644
--- a/arch/cris/config.in
+++ b/arch/cris/config.in
@@ -35,6 +35,9 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB
bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG
+if [ "$CONFIG_ETRAX_WATCHDOG" = "y" ]; then
+ bool 'Disable watchdog during Oops printouts' CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+fi
endmenu
@@ -250,6 +253,6 @@ bool 'Kernel profiling support' CONFIG_PROFILE
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
-endmenu
source lib/Config.in
+endmenu
diff --git a/arch/cris/drivers/Config.in b/arch/cris/drivers/Config.in
index 7d934a600..a73786250 100644
--- a/arch/cris/drivers/Config.in
+++ b/arch/cris/drivers/Config.in
@@ -175,11 +175,11 @@ if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then
hex ' PB user changeable bits mask' CONFIG_ETRAX_PB_CHANGEABLE_BITS FF
fi
-bool 'ARTPEC-1 support' CONFIG_JULIETTE
-
-if [ "$CONFIG_JULIETTE" = "y" ]; then
- source arch/cris/drivers/juliette/Config.in
-fi
+#bool 'ARTPEC-1 support' CONFIG_JULIETTE
+#
+#if [ "$CONFIG_JULIETTE" = "y" ]; then
+# source arch/cris/drivers/juliette/Config.in
+#fi
bool 'USB host' CONFIG_ETRAX_USB_HOST
if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then
diff --git a/arch/cris/drivers/axisflashmap.c b/arch/cris/drivers/axisflashmap.c
index 784c444bb..9f4a0558a 100644
--- a/arch/cris/drivers/axisflashmap.c
+++ b/arch/cris/drivers/axisflashmap.c
@@ -11,6 +11,17 @@
* partition split defined below.
*
* $Log: axisflashmap.c,v $
+ * Revision 1.2 2001/12/18 13:35:15 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.17 2001/11/12 19:42:38 pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.16 2001/11/08 11:18:58 jonashg
+ * Always read from uncached address to avoid problems with flushing
+ * cachelines after write and MTD-erase. No performance loss have been
+ * seen yet.
+ *
* Revision 1.15 2001/10/19 12:41:04 jonashg
* Name of probe has changed in MTD.
*
@@ -121,7 +132,7 @@ static __u32 flash_read32(struct map_info *map, unsigned long ofs)
static void flash_copy_from(struct map_info *map, void *to,
unsigned long from, ssize_t len)
{
- memcpy(to, (void *)(FLASH_CACHED_ADDR + from), len);
+ memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len);
}
static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
@@ -237,7 +248,7 @@ init_axis_flash(void)
int use_default_ptable = 1; /* Until proven otherwise */
const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n";
- printk(KERN_NOTICE "Axis flash mapping: %x at %x\n",
+ printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
WINDOW_SIZE, FLASH_CACHED_ADDR);
#ifdef CONFIG_MTD_CFI
diff --git a/arch/cris/drivers/bluetooth/Makefile b/arch/cris/drivers/bluetooth/Makefile
new file mode 100644
index 000000000..b3cbffc6c
--- /dev/null
+++ b/arch/cris/drivers/bluetooth/Makefile
@@ -0,0 +1,25 @@
+include $(APPS)/Rules.elinux
+
+all:
+
+install: src/bluetooth.c include/btcommon.h
+ ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth
+ if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \
+ echo '' >> ../Config.in; \
+ echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \
+ echo ' source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \
+ echo 'fi' >> ../Config.in; \
+ fi
+ if ! grep bluetooth/src/bt.o ../Makefile; then \
+ perl -pi -e "s:include:obj-\\\$$(CONFIG_BLUETOOTH) += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH) += bluetooth/src\n\ninclude:" ../Makefile; \
+ fi
+
+clean:
+
+src/bluetooth.c:
+ @echo "You must install the OpenBT src directory before install can be done here!"
+ @exit 1
+
+include/btcommon.h:
+ @echo "You must install the OpenBT include directory before install can be done here!"
+ @exit 1
diff --git a/arch/cris/drivers/ds1302.c b/arch/cris/drivers/ds1302.c
index 177d9b119..a0b55436a 100644
--- a/arch/cris/drivers/ds1302.c
+++ b/arch/cris/drivers/ds1302.c
@@ -7,6 +7,9 @@
*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
*!
*! $Log: ds1302.c,v $
+*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+*! Import of Linux 2.5.1
+*!
*! Revision 1.11 2001/06/14 12:35:52 jonashg
*! The ATA hack is back. It is unfortunately the only way to set g27 to output.
*!
@@ -82,7 +85,7 @@
*!
*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
*!
-*! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $
+*! $Id: ds1302.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*!
*!***************************************************************************/
diff --git a/arch/cris/drivers/eeprom.c b/arch/cris/drivers/eeprom.c
index ad3df73a2..cb39cf103 100644
--- a/arch/cris/drivers/eeprom.c
+++ b/arch/cris/drivers/eeprom.c
@@ -20,6 +20,9 @@
*! in the spin-lock.
*!
*! $Log: eeprom.c,v $
+*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+*! Import of Linux 2.5.1
+*!
*! Revision 1.8 2001/06/15 13:24:29 jonashg
*! * Added verification of pointers from userspace in read and write.
*! * Made busy counter volatile.
diff --git a/arch/cris/drivers/ethernet.c b/arch/cris/drivers/ethernet.c
index 707c295f3..47fe0a6e7 100644
--- a/arch/cris/drivers/ethernet.c
+++ b/arch/cris/drivers/ethernet.c
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.18 2001/10/03 14:40:43 jonashg Exp $
+/* $Id: ethernet.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $
*
* e100net.c: A network driver for the ETRAX 100LX network controller.
*
@@ -7,6 +7,24 @@
* The outline of this driver comes from skeleton.c.
*
* $Log: ethernet.c,v $
+ * Revision 1.2 2001/12/18 13:35:15 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.21 2001/11/23 11:54:49 starvik
+ * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list
+ * Removed compiler warnings
+ *
+ * Revision 1.20 2001/11/12 19:26:00 pkj
+ * * Corrected e100_negotiate() to not assign half to current_duplex when
+ * it was supposed to compare them...
+ * * Cleaned up failure handling in e100_open().
+ * * Fixed compiler warnings.
+ *
+ * Revision 1.19 2001/11/09 07:43:09 starvik
+ * Added full duplex support
+ * Added ioctl to set speed and duplex
+ * Clear LED timer only runs when LED is lit
+ *
* Revision 1.18 2001/10/03 14:40:43 jonashg
* Update rx_bytes counter.
*
@@ -104,6 +122,7 @@
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/bitops.h>
+#include <asm/ethernet.h>
//#define ETHDEBUG
#define D(x)
@@ -120,7 +139,7 @@ static const char* cardname = "ETRAX 100LX built-in ethernet controller";
static struct sockaddr default_mac = {
0,
- { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
+ { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
};
/* Information that need to be kept for each board. */
@@ -136,6 +155,14 @@ struct net_local {
};
+/* Duplex settings */
+enum duplex
+{
+ half,
+ full,
+ autoneg
+};
+
/* Dma descriptors etc. */
#define RX_BUF_SIZE 32768
@@ -148,9 +175,18 @@ struct net_local {
/*
** MDIO constants.
*/
-#define MDIO_BASE_STATUS_REG 0x1
-#define MDIO_BASE_CONTROL_REG 0x0
-#define MDIO_LINK_UP_MASK 0x4
+#define MDIO_BASE_STATUS_REG 0x1
+#define MDIO_BASE_CONTROL_REG 0x0
+#define MDIO_BC_NEGOTIATE 0x0200
+#define MDIO_BC_FULL_DUPLEX_MASK 0x0100
+#define MDIO_BC_AUTO_NEG_MASK 0x1000
+#define MDIO_BC_SPEED_SELECT_MASK 0x2000
+#define MDIO_ADVERTISMENT_REG 0x4
+#define MDIO_ADVERT_100_FD 0x100
+#define MDIO_ADVERT_100_HD 0x080
+#define MDIO_ADVERT_10_FD 0x040
+#define MDIO_ADVERT_10_HD 0x020
+#define MDIO_LINK_UP_MASK 0x4
#define MDIO_START 0x1
#define MDIO_READ 0x2
#define MDIO_WRITE 0x1
@@ -158,6 +194,7 @@ struct net_local {
/* Broadcom specific */
#define MDIO_AUX_CTRL_STATUS_REG 0x18
+#define MDIO_FULL_DUPLEX_IND 0x1
#define MDIO_SPEED 0x2
#define MDIO_PHYS_ADDR 0x0
@@ -165,18 +202,25 @@ struct net_local {
#define NET_FLASH_TIME (HZ/50) /* 20 ms */
#define NET_FLASH_PAUSE (HZ/100) /* 10 ms */
#define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */
+#define NET_DUPLEX_CHECK_INTERVAL (2*HZ) /* 2 s */
#define NO_NETWORK_ACTIVITY 0
#define NETWORK_ACTIVITY 1
#define RX_DESC_BUF_SIZE 256
#define NBR_OF_RX_DESC (RX_BUF_SIZE / \
- RX_DESC_BUF_SIZE)
+ RX_DESC_BUF_SIZE)
#define GET_BIT(bit,val) (((val) >> (bit)) & 0x01)
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
+ IO_FIELD(##reg##, field, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
+ IO_STATE(##reg##, field, val)
+
static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to
- to be processed */
+ to be processed */
static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */
static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */
@@ -187,13 +231,21 @@ static etrax_dma_descr TxDesc __attribute__ ((aligned(4)));
static struct sk_buff *tx_skb;
+static unsigned int network_rec_config_shadow = 0;
+
/* Network speed indication. */
static struct timer_list speed_timer;
static struct timer_list clear_led_timer;
-static int current_speed;
+static int current_speed; /* Speed read from tranceiver */
+static int current_speed_selection; /* Speed selected by user */
static int led_next_time;
static int led_active;
+/* Duplex */
+static struct timer_list duplex_timer;
+static int full_duplex;
+static enum duplex current_duplex;
+
/* Index to functions, as function prototypes. */
static int etrax_ethernet_init(struct net_device *dev);
@@ -206,6 +258,8 @@ static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void e100_rx(struct net_device *dev);
static int e100_close(struct net_device *dev);
+static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static void e100_tx_timeout(struct net_device *dev);
static struct net_device_stats *e100_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void e100_hardware_send_packet(char *buf, int length);
@@ -213,6 +267,11 @@ static void update_rx_stats(struct net_device_stats *);
static void update_tx_stats(struct net_device_stats *);
static void e100_check_speed(unsigned long dummy);
+static void e100_set_speed(unsigned long speed);
+static void e100_check_duplex(unsigned long dummy);
+static void e100_set_duplex(enum duplex);
+static void e100_negotiate(void);
+
static unsigned short e100_get_mdio_reg(unsigned char reg_num);
static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
static void e100_send_mdio_bit(unsigned char bit);
@@ -278,6 +337,8 @@ etrax_ethernet_init(struct net_device *dev)
dev->get_stats = e100_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->set_mac_address = e100_set_mac_address;
+ dev->do_ioctl = e100_ioctl;
+ dev->tx_timeout = e100_tx_timeout;
/* set the default MAC address */
@@ -287,7 +348,7 @@ etrax_ethernet_init(struct net_device *dev)
/* Initialise receive descriptors */
- for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+ for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
RxDescList[i].ctrl = 0;
RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
@@ -313,12 +374,18 @@ etrax_ethernet_init(struct net_device *dev)
/* Initialize speed indicator stuff. */
current_speed = 10;
+ current_speed_selection = 0; /* Auto */
speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
speed_timer.function = e100_check_speed;
add_timer(&speed_timer);
+
clear_led_timer.function = e100_clear_network_leds;
- clear_led_timer.expires = jiffies + HZ/10;
- add_timer(&clear_led_timer);
+
+ full_duplex = 0;
+ current_duplex = autoneg;
+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+ duplex_timer.function = e100_check_duplex;
+ add_timer(&duplex_timer);
return 0;
}
@@ -335,7 +402,7 @@ e100_set_mac_address(struct net_device *dev, void *p)
/* remember it */
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/* Write it to the hardware.
* Note the way the address is wrapped:
@@ -409,21 +476,21 @@ e100_open(struct net_device *dev)
if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
cardname, (void *)dev)) {
- goto grace_exit;
+ goto grace_exit0;
}
/* allocate the irq corresponding to the transmitting DMA */
if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
cardname, (void *)dev)) {
- goto grace_exit;
+ goto grace_exit1;
}
/* allocate the irq corresponding to the network errors etc */
if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0,
cardname, (void *)dev)) {
- goto grace_exit;
+ goto grace_exit2;
}
/*
@@ -431,18 +498,12 @@ e100_open(struct net_device *dev)
* and clean up on failure.
*/
- if(request_dma(NETWORK_TX_DMA_NBR, cardname)) {
- goto grace_exit;
+ if (request_dma(NETWORK_TX_DMA_NBR, cardname)) {
+ goto grace_exit3;
}
- if(request_dma(NETWORK_RX_DMA_NBR, cardname)) {
- grace_exit:
- /* this will cause some 'trying to free free irq' but what the heck... */
- free_dma(NETWORK_TX_DMA_NBR);
- free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
- free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
- free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
- return -EAGAIN;
+ if (request_dma(NETWORK_RX_DMA_NBR, cardname)) {
+ goto grace_exit4;
}
/* give the HW an idea of what MAC address we want */
@@ -459,9 +520,10 @@ e100_open(struct net_device *dev)
*R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
#else
- *R_NETWORK_REC_CONFIG =
- IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) |
- IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable);
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
#endif
*R_NETWORK_GEN_CONFIG =
@@ -507,6 +569,17 @@ e100_open(struct net_device *dev)
netif_start_queue(dev);
return 0;
+
+grace_exit4:
+ free_dma(NETWORK_TX_DMA_NBR);
+grace_exit3:
+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+grace_exit2:
+ free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+grace_exit1:
+ free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+grace_exit0:
+ return -EAGAIN;
}
@@ -532,10 +605,119 @@ e100_check_speed(unsigned long dummy)
add_timer(&speed_timer);
}
+static void
+e100_negotiate(void)
+{
+ unsigned short cmd;
+ unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
+ int bitCounter;
+
+ /* Discard old speed and duplex settings */
+ data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD |
+ MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD);
+
+ switch (current_speed_selection) {
+ case 10 :
+ if (current_duplex == full)
+ data |= MDIO_ADVERT_10_FD;
+ else if (current_duplex == half)
+ data |= MDIO_ADVERT_10_HD;
+ else
+ data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD;
+ break;
+
+ case 100 :
+ if (current_duplex == full)
+ data |= MDIO_ADVERT_100_FD;
+ else if (current_duplex == half)
+ data |= MDIO_ADVERT_100_HD;
+ else
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD;
+ break;
+
+ case 0 : /* Auto */
+ if (current_duplex == full)
+ data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD;
+ else if (current_duplex == half)
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD;
+ else
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
+ break;
+
+ default : /* assume autoneg speed and duplex */
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD |
+ MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
+ }
+
+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+ (MDIO_ADVERTISMENT_REG<< 2);
+
+ e100_send_mdio_cmd(cmd, 1);
+
+ /* Data... */
+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+ e100_send_mdio_bit(GET_BIT(bitCounter, data));
+ }
+
+ /* Renegotiate with link partner */
+ data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
+ data |= MDIO_BC_NEGOTIATE;
+
+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+ (MDIO_BASE_CONTROL_REG<< 2);
+
+ e100_send_mdio_cmd(cmd, 1);
+
+ /* Data... */
+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+ e100_send_mdio_bit(GET_BIT(bitCounter, data));
+ }
+}
+
+static void
+e100_set_speed(unsigned long speed)
+{
+ current_speed_selection = speed;
+ e100_negotiate();
+}
+
+static void
+e100_check_duplex(unsigned long dummy)
+{
+ unsigned long data;
+
+ data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG);
+
+ if (data & MDIO_FULL_DUPLEX_IND) {
+ if (!full_duplex) { /* Duplex changed to full? */
+ full_duplex = 1;
+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+ }
+ } else { /* half */
+ if (full_duplex) { /* Duplex changed to half? */
+ full_duplex = 0;
+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+ }
+ }
+
+ /* Reinitialize the timer. */
+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+ add_timer(&duplex_timer);
+}
+
+static void
+e100_set_duplex(enum duplex new_duplex)
+{
+ current_duplex = new_duplex;
+ e100_negotiate();
+}
+
+
static unsigned short
e100_get_mdio_reg(unsigned char reg_num)
{
- unsigned long flags;
unsigned short cmd; /* Data to be sent on MDIO port */
unsigned short data; /* Data read from MDIO */
int bitCounter;
@@ -549,7 +731,7 @@ e100_get_mdio_reg(unsigned char reg_num)
data = 0;
/* Data... */
- for(bitCounter=15; bitCounter>=0 ; bitCounter--) {
+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
data |= (e100_receive_mdio_bit() << bitCounter);
}
@@ -563,14 +745,14 @@ e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
unsigned char data = 0x2;
/* Preamble */
- for(bitCounter = 31; bitCounter>= 0; bitCounter--)
+ for (bitCounter = 31; bitCounter>= 0; bitCounter--)
e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));
- for(bitCounter = 15; bitCounter >= 2; bitCounter--)
+ for (bitCounter = 15; bitCounter >= 2; bitCounter--)
e100_send_mdio_bit(GET_BIT(bitCounter, cmd));
/* Turnaround */
- for(bitCounter = 1; bitCounter >= 0 ; bitCounter--)
+ for (bitCounter = 1; bitCounter >= 0 ; bitCounter--)
if (write_cmd)
e100_send_mdio_bit(GET_BIT(bitCounter, data));
else
@@ -606,7 +788,6 @@ e100_receive_mdio_bit()
static void
e100_reset_tranceiver(void)
{
- unsigned long flags;
unsigned short cmd;
unsigned short data;
int bitCounter;
@@ -619,7 +800,7 @@ e100_reset_tranceiver(void)
data |= 0x8000;
- for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
+ for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
e100_send_mdio_bit(GET_BIT(bitCounter, data));
}
}
@@ -706,15 +887,14 @@ e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct net_device *dev = (struct net_device *)dev_id;
unsigned long irqbits = *R_IRQ_MASK2_RD;
- if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
-
+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
/* acknowledge the eop interrupt */
*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
/* check if one or more complete packets were indeed received */
- while(*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) {
+ while (*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) {
/* Take out the buffer and give it to the OS, then
* allocate a new buffer to put a packet in.
*/
@@ -747,8 +927,7 @@ e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct net_local *np = (struct net_local *)dev->priv;
/* check for a dma0_eop interrupt */
- if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-
+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
/* This protects us from concurrent execution of
* our dev->hard_start_xmit function above.
*/
@@ -759,7 +938,7 @@ e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
- if(*R_DMA_CH0_FIRST == 0 && tx_skb) {
+ if (*R_DMA_CH0_FIRST == 0 && tx_skb) {
np->stats.tx_bytes += tx_skb->len;
np->stats.tx_packets++;
/* dma is ready with the transmission of the data in tx_skb, so now
@@ -784,19 +963,19 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
unsigned long irqbits = *R_IRQ_MASK0_RD;
/* check for underrun irq */
- if(irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) {
+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) {
*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
np->stats.tx_errors++;
D(printk("ethernet receiver underrun!\n"));
}
/* check for overrun irq */
- if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {
+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {
update_rx_stats(&np->stats); /* this will ack the irq */
D(printk("ethernet receiver overrun!\n"));
}
/* check for excessive collision irq */
- if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) {
+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) {
*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
np->stats.tx_errors++;
D(printk("ethernet excessive collisions!\n"));
@@ -809,11 +988,13 @@ static void
e100_rx(struct net_device *dev)
{
struct sk_buff *skb;
- int length=0;
- int i;
+ int length = 0;
struct net_local *np = (struct net_local *)dev->priv;
struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc;
unsigned char *skb_data_ptr;
+#ifdef ETHDEBUG
+ int i;
+#endif
if (!led_active && jiffies > led_next_time) {
/* light the network leds depending on the current speed. */
@@ -822,6 +1003,7 @@ e100_rx(struct net_device *dev)
/* Set the earliest time we may clear the LED */
led_next_time = jiffies + NET_FLASH_TIME;
led_active = 1;
+ mod_timer(&clear_led_timer, jiffies + HZ/10);
}
/* If the packet is broken down in many small packages then merge
@@ -842,7 +1024,7 @@ e100_rx(struct net_device *dev)
printk("Got a packet of length %d:\n", length);
/* dump the first bytes in the packet */
skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf);
- for(i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
@@ -869,7 +1051,7 @@ e100_rx(struct net_device *dev)
/* this loop can be made using max two memcpy's if optimized */
- while(mySaveRxDesc != myNextRxDesc) {
+ while (mySaveRxDesc != myNextRxDesc) {
memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
mySaveRxDesc->sw_len);
skb_data_ptr += mySaveRxDesc->sw_len;
@@ -946,6 +1128,37 @@ e100_close(struct net_device *dev)
return 0;
}
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ /* Maybe default should return -EINVAL instead? */
+ switch (cmd) {
+ case SET_ETH_SPEED_10: /* 10 Mbps */
+ e100_set_speed(10);
+ break;
+ case SET_ETH_SPEED_100: /* 100 Mbps */
+ e100_set_speed(100);
+ break;
+ case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */
+ e100_set_speed(0);
+ break;
+ case SET_ETH_DUPLEX_HALF: /* Hhalf duplex. */
+ e100_set_duplex(half);
+ break;
+ case SET_ETH_DUPLEX_FULL: /* Full duplex. */
+ e100_set_duplex(full);
+ break;
+ case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/
+ e100_set_duplex(autoneg);
+ break;
+ default: /* Auto neg */
+ e100_set_speed(0);
+ e100_set_duplex(autoneg);
+ break;
+ }
+ return 0;
+}
+
static void
update_rx_stats(struct net_device_stats *es)
{
@@ -996,26 +1209,31 @@ set_multicast_list(struct net_device *dev)
int num_addr = dev->mc_count;
unsigned long int lo_bits;
unsigned long int hi_bits;
- if (num_addr == -1)
+ if (dev->flags & IFF_PROMISC)
{
/* promiscuous mode */
lo_bits = 0xfffffffful;
hi_bits = 0xfffffffful;
- /* Enable individual receive */
- *R_NETWORK_REC_CONFIG =
- IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) |
- IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable) |
- IO_STATE(R_NETWORK_REC_CONFIG, individual, receive);
+ /* Enable individual receive */
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+ } else if (dev->flags & IFF_ALLMULTI) {
+ /* enable all multicasts */
+ lo_bits = 0xfffffffful;
+ hi_bits = 0xfffffffful;
+
+ /* Disable individual receive */
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
} else if (num_addr == 0) {
/* Normal, clear the mc list */
lo_bits = 0x00000000ul;
hi_bits = 0x00000000ul;
- /* Disable individual receive */
- *R_NETWORK_REC_CONFIG =
- IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) |
- IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable);
+ /* Disable individual receive */
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
} else {
/* MC mode, receive normal and MC packets */
char hash_ix;
@@ -1057,10 +1275,9 @@ set_multicast_list(struct net_device *dev)
}
dmi = dmi->next;
}
- /* Disable individual receive */
- *R_NETWORK_REC_CONFIG =
- IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) |
- IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable);
+ /* Disable individual receive */
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
}
*R_NETWORK_GA_0 = lo_bits;
*R_NETWORK_GA_1 = hi_bits;
@@ -1078,6 +1295,7 @@ e100_hardware_send_packet(char *buf, int length)
/* Set the earliest time we may clear the LED */
led_next_time = jiffies + NET_FLASH_TIME;
led_active = 1;
+ mod_timer(&clear_led_timer, jiffies + HZ/10);
}
/* configure the tx dma descriptor */
@@ -1095,16 +1313,13 @@ e100_hardware_send_packet(char *buf, int length)
static void
e100_clear_network_leds(unsigned long dummy)
{
- if (led_active && jiffies > led_next_time) {
+ if (led_active && jiffies > led_next_time) {
e100_set_network_leds(NO_NETWORK_ACTIVITY);
/* Set the earliest time we may set the LED */
led_next_time = jiffies + NET_FLASH_PAUSE;
led_active = 0;
}
-
- clear_led_timer.expires = jiffies + HZ/10;
- add_timer(&clear_led_timer);
}
static void
@@ -1143,7 +1358,7 @@ etrax_init_module(void)
d->init = etrax_ethernet_init;
- if(register_netdev(d) == 0)
+ if (register_netdev(d) == 0)
return 0;
else
return -ENODEV;
diff --git a/arch/cris/drivers/examples/kiobuftest.c b/arch/cris/drivers/examples/kiobuftest.c
index c621966a0..784418f9c 100644
--- a/arch/cris/drivers/examples/kiobuftest.c
+++ b/arch/cris/drivers/examples/kiobuftest.c
@@ -10,6 +10,9 @@
* Author: Bjorn Wesen
*
* $Log: kiobuftest.c,v $
+ * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+ * Import of Linux 2.5.1
+ *
* Revision 1.2 2001/02/27 13:52:50 bjornw
* malloc.h -> slab.h
*
diff --git a/arch/cris/drivers/gpio.c b/arch/cris/drivers/gpio.c
index a88b0f6e4..c454e5de5 100644
--- a/arch/cris/drivers/gpio.c
+++ b/arch/cris/drivers/gpio.c
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.11 2001/10/30 14:39:12 johana Exp $
+/* $Id: gpio.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $
*
* Etrax general port I/O device
*
@@ -9,6 +9,13 @@
* Johan Adolfsson (read/set directions, write)
*
* $Log: gpio.c,v $
+ * Revision 1.2 2001/12/18 13:35:15 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.12 2001/11/12 19:42:15 pkj
+ * * Corrected return values from gpio_leds_ioctl().
+ * * Fixed compiler warnings.
+ *
* Revision 1.11 2001/10/30 14:39:12 johana
* Added D() around gpio_write printk.
*
@@ -74,7 +81,9 @@
static char gpio_name[] = "etrax gpio";
+#if 0
static wait_queue_head_t *gpio_wq;
+#endif
static int gpio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
@@ -143,7 +152,7 @@ gpio_poll(struct file *filp,
{
/* TODO poll on alarms! */
#if 0
- if(!ANYTHING_WANTED) {
+ if (!ANYTHING_WANTED) {
D(printk("gpio_select sleeping task\n"));
select_wait(&gpio_wq, table);
return 0;
@@ -160,16 +169,14 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
unsigned char data, clk_mask, data_mask, write_msb;
unsigned long flags;
ssize_t retval = count;
- if (verify_area(VERIFY_READ, buf, count))
- {
+ if (verify_area(VERIFY_READ, buf, count)) {
return -EFAULT;
}
clk_mask = priv->clk_mask;
data_mask = priv->data_mask;
/* It must have been configured using the IO_CFG_WRITE_MODE */
/* Perhaps a better error code? */
- if (clk_mask == 0 || data_mask == 0)
- {
+ if (clk_mask == 0 || data_mask == 0) {
return -EPERM;
}
write_msb = priv->write_msb;
@@ -178,7 +185,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
int i;
data = *buf++;
if (priv->write_msb) {
- for (i = 7; i>=0;i--) {
+ for (i = 7; i >= 0;i--) {
save_flags(flags); cli();
*priv->port = *priv->shadow &= ~clk_mask;
if (data & 1<<i)
@@ -190,7 +197,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
restore_flags(flags);
}
} else {
- for (i = 0; i<=7;i++) {
+ for (i = 0; i <= 7;i++) {
save_flags(flags); cli();
*priv->port = *priv->shadow &= ~clk_mask;
if (data & 1<<i)
@@ -212,13 +219,13 @@ gpio_open(struct inode *inode, struct file *filp)
struct gpio_private *priv;
int p = MINOR(inode->i_rdev);
- if(p >= NUM_PORTS && p != LEDS)
+ if (p >= NUM_PORTS && p != LEDS)
return -EINVAL;
priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private),
GFP_KERNEL);
- if(!priv)
+ if (!priv)
return -ENOMEM;
priv->minor = p;
@@ -254,10 +261,10 @@ gpio_release(struct inode *inode, struct file *filp)
/* unlink from alarmlist and free the private structure */
- if(p == todel) {
+ if (p == todel) {
alarmlist = todel->next;
} else {
- while(p->next != todel)
+ while (p->next != todel)
p = p->next;
p->next = todel->next;
}
@@ -280,7 +287,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
{
unsigned long flags;
struct gpio_private *priv = (struct gpio_private *)file->private_data;
- if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+ if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
return -EINVAL;
}
@@ -353,7 +360,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
if (!((priv->clk_mask & priv->changeable_bits) &&
(priv->data_mask & priv->changeable_bits) &&
(priv->clk_mask & *priv->dir_shadow) &&
- (priv->data_mask & *priv->dir_shadow)) )
+ (priv->data_mask & *priv->dir_shadow)))
{
priv->clk_mask = 0;
priv->data_mask = 0;
@@ -361,7 +368,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
}
break;
default:
- if(priv->minor == LEDS)
+ if (priv->minor == LEDS)
return gpio_leds_ioctl(cmd, arg);
else
return -EINVAL;
@@ -375,6 +382,7 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
{
unsigned char green;
unsigned char red;
+
switch (_IOC_NR(cmd)) {
case IO_LEDACTIVE_SET:
green = ((unsigned char) arg) & 1;
@@ -382,14 +390,20 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
LED_ACTIVE_SET_G(green);
LED_ACTIVE_SET_R(red);
break;
- case IO_LED_SETBIT:
- LED_BIT_SET(arg);
- break;
- case IO_LED_CLRBIT:
- LED_BIT_CLR(arg);
+
+ case IO_LED_SETBIT:
+ LED_BIT_SET(arg);
+ break;
+
+ case IO_LED_CLRBIT:
+ LED_BIT_CLR(arg);
+ break;
+
default:
return -EINVAL;
}
+
+ return 0;
}
struct file_operations gpio_fops = {
@@ -406,30 +420,32 @@ struct file_operations gpio_fops = {
static __init int
gpio_init(void)
{
- int res,i;
+ extern void init_ioremap(void);
+ int res;
+#if defined (CONFIG_ETRAX_CSP0_LEDS)
+ int i;
+#endif
/* do the formalities */
res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
- if(res < 0) {
+ if (res < 0) {
printk(KERN_ERR "gpio: couldn't get a major number.\n");
return res;
}
/* Clear all leds */
-#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
-
- init_ioremap();
- LED_NETWORK_SET(0);
- LED_ACTIVE_SET(0);
- LED_DISK_READ(0);
- LED_DISK_WRITE(0);
+#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
+ init_ioremap();
+ LED_NETWORK_SET(0);
+ LED_ACTIVE_SET(0);
+ LED_DISK_READ(0);
+ LED_DISK_WRITE(0);
#if defined (CONFIG_ETRAX_CSP0_LEDS)
- for( i = 0; i < 32; i ++)
- {
- LED_BIT_SET(i);
- }
+ for (i = 0; i < 32; i++) {
+ LED_BIT_SET(i);
+ }
#endif
#endif
diff --git a/arch/cris/drivers/i2c.c b/arch/cris/drivers/i2c.c
index d3b32b626..a89023831 100644
--- a/arch/cris/drivers/i2c.c
+++ b/arch/cris/drivers/i2c.c
@@ -12,6 +12,9 @@
*! don't use PB_I2C if DS1302 uses same bits,
*! use PB.
*! $Log: i2c.c,v $
+*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+*! Import of Linux 2.5.1
+*!
*! Revision 1.7 2001/04/04 13:11:36 markusl
*! Updated according to review remarks
*!
@@ -43,7 +46,7 @@
*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
*!
*!***************************************************************************/
-/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */
+/* $Id: i2c.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */
/****************** INCLUDE FILES SECTION ***********************************/
#include <linux/module.h>
diff --git a/arch/cris/drivers/i2c.h b/arch/cris/drivers/i2c.h
index a820f9d9b..d789274ad 100644
--- a/arch/cris/drivers/i2c.h
+++ b/arch/cris/drivers/i2c.h
@@ -1,4 +1,4 @@
-/* $Id: i2c.h,v 1.3 2001/03/19 12:43:01 markusl Exp $ */
+/* $Id: i2c.h,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */
/* High level I2C actions */
int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
diff --git a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
index 45164a605..9cb576949 100644
--- a/arch/cris/drivers/ide.c
+++ b/arch/cris/drivers/ide.c
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.19 2001/05/09 12:53:16 johana Exp $
+/* $Id: ide.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* Etrax specific IDE functions, like init and PIO-mode setting etc.
* Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,9 @@
* Mikael Starvik (pio setup stuff)
*
* $Log: ide.c,v $
+ * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+ * Import of Linux 2.5.1
+ *
* Revision 1.19 2001/05/09 12:53:16 johana
* Added #include <asm/dma.h>
*
diff --git a/arch/cris/drivers/lpslave/bintocarr.pl b/arch/cris/drivers/lpslave/bintocarr.pl
index a400fa168..c03dd8b71 100644
--- a/arch/cris/drivers/lpslave/bintocarr.pl
+++ b/arch/cris/drivers/lpslave/bintocarr.pl
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
-# $Id: bintocarr.pl,v 1.4 2001/08/08 08:18:13 bjarne Exp $
+# $Id: bintocarr.pl,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
# Copy of mkjulbin.pl made by Olof
# convert a binary stdin to a C-file containing a char array of the input
# first argument is the symbol name
diff --git a/arch/cris/drivers/lpslave/e100lpslave.S b/arch/cris/drivers/lpslave/e100lpslave.S
index 6e2991deb..44efe0771 100644
--- a/arch/cris/drivers/lpslave/e100lpslave.S
+++ b/arch/cris/drivers/lpslave/e100lpslave.S
@@ -1,4 +1,4 @@
- ;; $Id: e100lpslave.S,v 1.3 2001/06/21 16:55:26 olof Exp $
+ ;; $Id: e100lpslave.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
;;
;; Etrax100 slave network<->parport forwarder
;;
diff --git a/arch/cris/drivers/lpslave/e100lpslavenet.c b/arch/cris/drivers/lpslave/e100lpslavenet.c
index f8ab69367..54aa0bace 100644
--- a/arch/cris/drivers/lpslave/e100lpslavenet.c
+++ b/arch/cris/drivers/lpslave/e100lpslavenet.c
@@ -1,4 +1,4 @@
-/* $Id: e100lpslavenet.c,v 1.4 2001/06/21 16:55:26 olof Exp $
+/* $Id: e100lpslavenet.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller.
*
@@ -7,6 +7,9 @@
* The outline of this driver comes from skeleton.c.
*
* $Log: e100lpslavenet.c,v $
+ * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+ * Import of Linux 2.5.1
+ *
* Revision 1.4 2001/06/21 16:55:26 olof
* Minimized par port setup time to gain bandwidth
*
diff --git a/arch/cris/drivers/parport.c b/arch/cris/drivers/parport.c
index 1d792968f..443e51a11 100644
--- a/arch/cris/drivers/parport.c
+++ b/arch/cris/drivers/parport.c
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.8 2001/09/26 11:51:52 bjornw Exp $
+/* $Id: parport.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* Elinux parallel port driver
* NOTE!
diff --git a/arch/cris/drivers/serial.c b/arch/cris/drivers/serial.c
index 6de63c4ac..412f7519c 100644
--- a/arch/cris/drivers/serial.c
+++ b/arch/cris/drivers/serial.c
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.23 2001/10/30 17:53:26 pkj Exp $
+/* $Id: serial.c,v 1.3 2001/12/19 10:32:35 johana Exp $
*
* Serial port driver for the ETRAX 100LX chip
*
@@ -7,6 +7,34 @@
* Many, many authors. Based once upon a time on serial.c for 16x50.
*
* $Log: serial.c,v $
+ * Revision 1.3 2001/12/19 10:32:35 johana
+ * Cleaned up write_rs485() - now it works correctly without padding extra
+ * char.
+ * Added sane default initialisation of rs485.
+ * Added #ifdef around dummy variables.
+ *
+ * Revision 1.27 2001/11/29 17:00:41 pkj
+ * 2kB seems to be too small a buffer when using 921600 bps,
+ * so increase it to 4kB (this was already done for the elinux
+ * version of the serial driver).
+ *
+ * Revision 1.26 2001/11/19 14:20:41 pkj
+ * Minor changes to comments and unused code.
+ *
+ * Revision 1.25 2001/11/12 20:03:43 pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.24 2001/11/12 15:10:05 pkj
+ * Total redesign of the receiving part of the serial driver.
+ * Uses eight chained descriptors to write to a 4kB buffer.
+ * This data is then serialised into a 2kB buffer. From there it
+ * is copied into the TTY's flip buffers when they become available.
+ * A lot of copying, and the sizes of the buffers might need to be
+ * tweaked, but all in all it should work better than the previous
+ * version, without the need to modify the TTY code in any way.
+ * Also note that erroneous bytes are now correctly marked in the
+ * flag buffers (instead of always marking the first byte).
+ *
* Revision 1.23 2001/10/30 17:53:26 pkj
* * Set info->uses_dma to 0 when a port is closed.
* * Mark the timer1 interrupt as a fast one (SA_INTERRUPT).
@@ -123,12 +151,12 @@
* Changed %ul to %lu in printf's
*
* Revision 1.47 2000/10/18 15:06:53 pkj
- * Compile correctly with CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST and
- * CONFIG_SERIAL_PROC_ENTRY together.
+ * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and
+ * CONFIG_ETRAX_SERIAL_PROC_ENTRY together.
* Some clean-up of the /proc/serial file.
*
* Revision 1.46 2000/10/16 12:59:40 johana
- * Added CONFIG_SERIAL_PROC_ENTRY for statistics and debug info.
+ * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info.
*
* Revision 1.45 2000/10/13 17:10:59 pkj
* Do not flush DMAs while flipping TTY buffers.
@@ -171,7 +199,7 @@
* Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
*
* Revision 1.36 2000/09/20 13:12:52 johana
- * Support for CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS:
+ * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS:
* Number of timer ticks between flush of receive fifo (1 tick = 10ms).
* Try 0-3 for low latency applications. Approx 5 for high load
* applications (e.g. PPP). Maybe this should be more adaptive some day...
@@ -255,7 +283,7 @@
*
*/
-static char *serial_version = "$Revision: 1.23 $";
+static char *serial_version = "$Revision: 1.3 $";
#include <linux/config.h>
#include <linux/version.h>
@@ -272,6 +300,7 @@ static char *serial_version = "$Revision: 1.23 $";
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#if (LINUX_VERSION_CODE >= 131343)
#include <linux/init.h>
#endif
@@ -302,6 +331,8 @@ static char *serial_version = "$Revision: 1.23 $";
#include "serial_compat.h"
#endif
+#define _INLINE_ inline
+
static DECLARE_TASK_QUEUE(tq_serial);
struct tty_driver serial_driver, callout_driver;
@@ -313,11 +344,6 @@ static int serial_refcount;
#define SERIAL_TYPE_CALLOUT 2
#endif
-#define DEBUG_LOG(line, string, value)
-
-/* Add an x here to log a lot of timer stuff */
-#define TIMERD(x)
-
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
@@ -337,6 +363,14 @@ static int serial_refcount;
#define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10)
+#define SERIAL_RECV_SIZE 4096
+#define SERIAL_DESCR_BUF_SIZE 512
+
+/* Add an x here to log a lot of timer stuff */
+#define TIMERD(x)
+
+#define DEBUG_LOG(line, string, value)
+
#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
/* Default number of timer ticks before flushing rx fifo
* When using "little data, low latency applications: use 0
@@ -345,8 +379,6 @@ static int serial_refcount;
#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
#endif
-#define _INLINE_ inline
-
static void change_speed(struct e100_serial *info);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
static int rs_write(struct tty_struct * tty, int from_user,
@@ -403,9 +435,9 @@ static int rs_write(struct tty_struct * tty, int from_user,
static struct e100_serial rs_table[] = {
{ DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */
R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD,
- R_DMA_CH6_STATUS, R_DMA_CH6_HWSW,
+ R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, R_DMA_CH6_DESCR,
R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD,
- R_DMA_CH7_STATUS, R_DMA_CH7_HWSW,
+ R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, R_DMA_CH7_DESCR,
STD_FLAGS, DEF_RX, DEF_TX, 2,
#ifdef CONFIG_ETRAX_SERIAL_PORT0
1
@@ -416,9 +448,9 @@ static struct e100_serial rs_table[] = {
#ifndef CONFIG_SVINTO_SIM
{ DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */
R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD,
- R_DMA_CH8_STATUS, R_DMA_CH8_HWSW,
+ R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, R_DMA_CH8_DESCR,
R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD,
- R_DMA_CH9_STATUS, R_DMA_CH9_HWSW,
+ R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, R_DMA_CH9_DESCR,
STD_FLAGS, DEF_RX, DEF_TX, 3 ,
#ifdef CONFIG_ETRAX_SERIAL_PORT1
1
@@ -429,9 +461,9 @@ static struct e100_serial rs_table[] = {
{ DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4, /* uses DMA 2 and 3 */
R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD,
- R_DMA_CH2_STATUS, R_DMA_CH2_HWSW,
+ R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, R_DMA_CH2_DESCR,
R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD,
- R_DMA_CH3_STATUS, R_DMA_CH3_HWSW,
+ R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, R_DMA_CH3_DESCR,
STD_FLAGS, DEF_RX, DEF_TX, 0,
#ifdef CONFIG_ETRAX_SERIAL_PORT2
1
@@ -442,9 +474,9 @@ static struct e100_serial rs_table[] = {
{ DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8, /* uses DMA 4 and 5 */
R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD,
- R_DMA_CH4_STATUS, R_DMA_CH4_HWSW,
+ R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, R_DMA_CH4_DESCR,
R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD,
- R_DMA_CH5_STATUS, R_DMA_CH5_HWSW,
+ R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, R_DMA_CH5_DESCR,
STD_FLAGS, DEF_RX, DEF_TX, 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT3
1
@@ -462,9 +494,9 @@ static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
-#ifdef CONFIG_SERIAL_PROC_ENTRY
+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
#define PROCSTAT(x) x
-struct ser_statistics_type{
+struct ser_statistics_type {
int overrun_cnt;
int early_errors_cnt;
int ser_ints_ok_cnt;
@@ -484,7 +516,7 @@ static struct ser_statistics_type ser_stat[NR_PORTS];
#define PROCSTAT(x)
-#endif /* CONFIG_SERIAL_PROC_ENTRY */
+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
/* RS-485 */
#if defined(CONFIG_ETRAX_RS485)
@@ -497,14 +529,20 @@ static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
/* For now we assume that all bits are on the same port for each serial port */
/* Dummy shadow variables */
+#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
static unsigned char dummy_ser0 = 0x00;
-static unsigned char dummy_ser1 = 0x00;
-static unsigned char dummy_ser2 = 0x00;
-static unsigned char dummy_ser3 = 0x00;
-
static unsigned char dummy_dir_ser0 = 0x00;
+#endif
+#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
+static unsigned char dummy_ser1 = 0x00;
static unsigned char dummy_dir_ser1 = 0x00;
+#endif
+#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
+static unsigned char dummy_ser2 = 0x00;
static unsigned char dummy_dir_ser2 = 0x00;
+#endif
+
+static unsigned char dummy_ser3 = 0x00;
static unsigned char dummy_dir_ser3 = 0x00;
/* Info needed for each ports extra control/status signals.
@@ -523,52 +561,56 @@ struct control_pins
static const struct control_pins e100_modem_pins[NR_PORTS] =
{
-/* Ser 0 */
- {
+ /* Ser 0 */
+ {
#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
- R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
- CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
- CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
- CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
- CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+ R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
+ CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
+ CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
+ CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
+ CONFIG_ETRAX_SER0_CD_ON_PB_BIT
#else
- &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
-#endif
- },
-/* Ser 1 */
- {
+ &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
+#endif
+ },
+
+ /* Ser 1 */
+ {
#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
- R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
- CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
- CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
- CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
- CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+ R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
+ CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
+ CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
+ CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
+ CONFIG_ETRAX_SER1_CD_ON_PB_BIT
#else
- &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
-#endif
- },
-/* Ser 2 */
- {
+ &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
+#endif
+ },
+
+ /* Ser 2 */
+ {
#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
- R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
- CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
- CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
- CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
- CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+ R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
+ CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
+ CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
+ CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
+ CONFIG_ETRAX_SER2_CD_ON_PA_BIT
#else
- &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
-#endif
- },
-/* Ser 3 */
- {
- &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
- }
+ &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
+#endif
+ },
+
+ /* Ser 3 */
+ {
+ &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+ }
};
#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
#endif
+
#define E100_RTS_MASK 0x20
#define E100_CTS_MASK 0x40
@@ -840,8 +882,8 @@ e100_disable_rx(struct e100_serial *info)
{
#ifndef CONFIG_SVINTO_SIM
/* disable the receiver */
- info->port[REG_REC_CTRL] = info->rx_ctrl &=
- ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable);
+ info->port[REG_REC_CTRL] =
+ (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
#endif
}
@@ -850,8 +892,8 @@ e100_enable_rx(struct e100_serial *info)
{
#ifndef CONFIG_SVINTO_SIM
/* enable the receiver */
- info->port[REG_REC_CTRL] = info->rx_ctrl |=
- IO_MASK(R_SERIAL0_REC_CTRL, rec_enable);
+ info->port[REG_REC_CTRL] =
+ (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
#endif
}
@@ -943,13 +985,8 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
static int
e100_write_rs485(struct tty_struct *tty,struct rs485_write *r)
{
- int stop_delay;
- int total, i;
- int max_j, delay_ms, bits;
- tcflag_t cflags;
- int size = (*r).outc_size;
+ int total;
struct e100_serial * info = (struct e100_serial *)tty->driver_data;
- struct wait_queue wait = { current, NULL };
/* If we are in RS-485 mode, we need to toggle RTS and disable
* the receiver before initiating a DMA transfer
@@ -975,44 +1012,20 @@ e100_write_rs485(struct tty_struct *tty,struct rs485_write *r)
* enable the receiver
*/
- /* wait on transmit shift register */
- /* All is sent, check if we should wait more before toggling rts */
-
- /* calc. number of bits / data byte */
- cflags = info->tty->termios->c_cflag;
-
- /* databits + startbit and 1 stopbit */
- if ((cflags & CSIZE) == CS7)
- bits = 9;
- else
- bits = 10;
-
- if (cflags & CSTOPB) /* 2 stopbits ? */
- bits++;
-
- if (cflags & PARENB) /* parity bit ? */
- bits++;
-
- /* calc timeout */
- delay_ms = ((bits * size * 1000) / info->baud) + 1;
- max_j = jiffies + (delay_ms * HZ)/1000 + 10;
-
- while (jiffies < max_j) {
- if (info->port[REG_STATUS] &
- IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) {
- for (i = 0; i < 100; i++)
- ;
- if (info->port[REG_STATUS] &
- IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) {
- /* ~25 for loops per usec */
- stop_delay = 1000000 / info->baud;
- if (cflags & CSTOPB)
- stop_delay *= 2;
- udelay(stop_delay);
- break;
- }
- }
+ /* Sleep until all sent */
+ tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+ /* Now sleep a little more so that shift register is empty */
+ schedule_usleep(info->char_time_usec * 2);
+#else
+ {
+ unsigned int val;
+ /* wait on transmit shift register */
+ do{
+ get_lsr_info(info, &val);
+ }while (!(val & TIOCSER_TEMT));
}
+#endif
e100_rts(info, info->rs485.rts_after_sent);
@@ -1118,7 +1131,7 @@ transmit_chars(struct e100_serial *info)
}
return;
#endif
- /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
+ /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
*info->oclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
@@ -1168,14 +1181,14 @@ transmit_chars(struct e100_serial *info)
#if defined(CONFIG_ETRAX_RS485)
/* Check if we should toggle RTS now */
- if (info->rs485.enabled)
- {
+ if (info->rs485.enabled) {
/* Make sure fifo is empty */
- int in_fifo = 0 ;
- do{
+ int in_fifo = 0;
+
+ do {
in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail,
- *info->ostatusadr);
- } while (in_fifo > 0) ;
+ *info->ostatusadr);
+ } while (in_fifo > 0);
/* Any way to really check transmitter empty? (TEMT) */
/* Control RTS to set to RX mode */
e100_rts(info, info->rs485.rts_after_sent);
@@ -1201,7 +1214,6 @@ transmit_chars(struct e100_serial *info)
*info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */
/* DMA is now running (hopefully) */
-
}
static void
@@ -1220,13 +1232,122 @@ start_transmit(struct e100_serial *info)
transmit_chars(info);
}
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static int serial_fast_timer_started = 0;
+static int serial_fast_timer_expired = 0;
+static void flush_timeout_function(unsigned long data);
+#define START_FLUSH_FAST_TIMER(info, string) {\
+ unsigned long timer_flags; \
+ save_flags(timer_flags); \
+ cli(); \
+ if (fast_timers[info->line].function == NULL) { \
+ serial_fast_timer_started++; \
+ TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+ TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
+ start_one_shot_timer(&fast_timers[info->line], \
+ flush_timeout_function, \
+ (unsigned long)info, \
+ info->char_time_usec*4, \
+ string); \
+ } \
+ else { \
+ TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+ } \
+ restore_flags(timer_flags); \
+}
+
+#else
+#define START_FLUSH_FAST_TIMER(info, string)
+#endif
+
+static int
+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
+{
+ if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE))
+ return 0;
+
+ info->recv.buf[info->recv.head] = data;
+ info->flag_buf[info->recv.head] = flag;
+ info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1);
+
+ info->icount.rx++;
+
+ return 1;
+}
+
+static _INLINE_ unsigned int
+copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf)
+{
+ unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE);
+ unsigned int length = 0;
+
+ while (length < recvl && count) {
+ if (length + count > recvl)
+ count = recvl - length;
+
+ memcpy(info->recv.buf + info->recv.head, buf + length, count);
+ memset(info->flag_buf + info->recv.head, '\0', count);
+ info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1);
+ length += count;
+
+ count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE);
+ }
+
+ if (length != recvl) {
+ printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length);
+ PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length);
+ }
+
+ return length;
+}
+
+static _INLINE_ unsigned int
+copy_all_descr_data(struct e100_serial *info)
+{
+ struct etrax_dma_descr *descr;
+ unsigned int recvl;
+ unsigned int ret = 0;
+
+ while (1)
+ {
+ descr = &info->rec_descr[info->cur_rec_descr];
+
+ if (descr == phys_to_virt(*info->idescradr))
+ break;
+
+ if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
+ info->cur_rec_descr = 0;
+
+ /* find out how many bytes were read */
+
+ /* if the eop bit was not set, all data has been received */
+ if (!(descr->status & d_eop)) {
+ recvl = descr->sw_len;
+ } else {
+ /* otherwise we find the amount of data received here */
+ recvl = descr->hw_len;
+ }
+
+ /* Reset the status information */
+ descr->status = 0;
+
+ DEBUG_LOG(info->line, "recvl %lu\n", recvl);
+
+ /* update stats */
+ info->icount.rx += recvl;
+
+ ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf));
+ }
+
+ return ret;
+}
+
static _INLINE_ void
receive_chars(struct e100_serial *info)
{
struct tty_struct *tty;
unsigned char rstat;
- unsigned int recvl;
- struct etrax_dma_descr *descr;
+ unsigned int old_head;
#ifdef CONFIG_SVINTO_SIM
/* No receive in the simulator. Will probably be when the rest of
@@ -1235,168 +1356,96 @@ receive_chars(struct e100_serial *info)
return;
#endif
- tty = info->tty;
-
- /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
-
- // ?
+ /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
*info->iclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
- if (!tty) /* something wrong... */
+ tty = info->tty;
+ if (!tty) /* Something wrong... */
return;
- descr = &info->rec_descr;
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+ e100_enable_serial_data_irq(info);
+#endif
- /* find out how many bytes were read */
+ if (info->errorcode == ERRCODE_INSERT_BREAK)
+ add_char_and_flag(info, '\0', TTY_BREAK);
- /* if the eop bit was not set, all data has been received */
- if (!(descr->status & d_eop)) {
- recvl = descr->sw_len;
- } else {
- /* otherwise we find the amount of data received here */
- recvl = descr->hw_len;
- }
+ old_head = info->recv.head;
+
+ if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK)
+ info->flag_buf[old_head] = TTY_BREAK;
- /* read the status register so we can detect errors,
- * but we can't really do anything about those errors
- * anyway, since we have the DMA in "force eop at error" mode
- * the fault characters are not in the buffer anyway.
- */
+ info->errorcode = 0;
+ /* Read the status register to detect errors */
rstat = info->port[REG_STATUS];
- if ((rstat & SER_ERROR_MASK) != 0) {
- unsigned char data;
- /* if we got an error, we must reset it by reading the
+ if (rstat & SER_ERROR_MASK) {
+ /* If we got an error, we must reset it by reading the
* data_in field
*/
- data = info->port[REG_DATA];
+ unsigned char data = info->port[REG_DATA];
+
PROCSTAT(ser_stat[info->line].errors_cnt++);
- DEBUG_LOG(info->line, " #dERR: s d 0x%04X\n",
+ DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
((rstat & SER_ERROR_MASK) << 8) | data);
- /* Only handle the saved error code, that indicates that we got
- * the last character of a break that looks like it's ok, but
- * is not
- */
- if (info->errorcode == 0) {
- *tty->flip.flag_buf_ptr = TTY_NORMAL;
- } else {
- unsigned char data;
- data = info->port[REG_DATA];
- if (info->errorcode & ERRCODE_INSERT) {
- unsigned char *currbuf;
- /* Get the current buffer */
- if (tty->flip.buf_num) {
- currbuf = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- } else {
- currbuf = tty->flip.char_buf;
- }
- /* We should insert a character in the buffer! */
- if (recvl == 0) {
- recvl = 1;
- DEBUG_LOG(info->line, "insert to %lu\n", recvl);
- } else {
- /* Move stuff around.. */
- DEBUG_LOG(info->line, "#insert to %lu!\n", recvl);
- if (recvl < TTY_FLIPBUF_SIZE) {
- int i;
- /* Move the data 1 step right */
- i = recvl;
- while (i) {
- currbuf[i] = currbuf[i-1];
- i--;
- }
- recvl++;
- } else {
- /* We can't move it all! Skip break! */
- /* TODO: Handle full buffer? */
- DEBUG_LOG(info->line, "#BRK skipped! %lu!\n", recvl);
- info->errorcode = 0;
- }
- }
- }
-
- PROCSTAT(ser_stat[info->line].errors_cnt++);
- DEBUG_LOG(info->line, " #bERR: s d 0x%04X\n",
- ((rstat & SER_ERROR_MASK) << 8) | data);
- *tty->flip.flag_buf_ptr = (info->errorcode & 0xFF);
- info->errorcode = 0;
-#if 0
- printk("SERERR: 0x%02X data: 0x%02X\n", rstat & SER_ERROR_MASK, data);
-#endif
- /* we only ever write errors into the first byte in
- * the flip flag buffer, so we dont have to clear it
- * all every time
- */
- }
+ if (rstat & SER_PAR_ERR_MASK)
+ add_char_and_flag(info, data, TTY_PARITY);
+ else if (rstat & SER_OVERRUN_MASK)
+ add_char_and_flag(info, data, TTY_OVERRUN);
+ else if (rstat & SER_FRAMING_ERR_MASK)
+ add_char_and_flag(info, data, TTY_FRAME);
}
- DEBUG_LOG(info->line, "recvl %lu\n", recvl);
-
- if (recvl) {
- unsigned char *buf;
- struct async_icount *icount = &info->icount;
-
- /* update stats */
- icount->rx += recvl;
-
- /* use the flip buffer next in turn to restart DMA into */
-
- if (tty->flip.buf_num) {
- buf = tty->flip.char_buf;
- } else {
- buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- }
+ if (!E100_RTS_GET(info) &&
+ CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT)
+ info->tty->driver.throttle(info->tty);
+
+ START_FLUSH_FAST_TIMER(info, "receive_chars");
- if (buf == phys_to_virt(descr->buf)) {
- printk("ttyS%d flip-buffer overrun!\n", info->line);
- icount->overrun++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- /* restart old buffer */
- } else {
- descr->buf = virt_to_phys(buf);
+ /* Restart the receiving DMA */
+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+}
- /* schedule or push a flip of the buffer */
+static _INLINE_ int
+start_recv_dma(struct e100_serial *info)
+{
+ struct etrax_dma_descr *descr = info->rec_descr;
+ unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE;
+ int i;
- info->tty->flip.count = recvl;
+ /* Set up the receiving descriptors */
+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
+ descr[i].ctrl = d_int;
+ descr[i].buf = virt_to_phys(buf);
+ descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
+ descr[i].hw_len = 0;
+ descr[i].status = 0;
+ descr[i].next = virt_to_phys(&descr[i+1]);
-#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
- /* this includes a check for low-latency */
- tty_flip_buffer_push(tty);
-#else
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
-#endif
- }
+ buf += SERIAL_DESCR_BUF_SIZE;
}
- /* restart the receiving dma */
+ /* Link the last descriptor to the first */
+ descr[i-1].next = virt_to_phys(&descr[0]);
- descr->sw_len = TTY_FLIPBUF_SIZE;
- descr->ctrl = d_int | d_eol | d_eop;
- descr->hw_len = 0;
- descr->status = 0;
+ /* Start with the first descriptor in the list */
+ info->cur_rec_descr = 0;
- *info->ifirstadr = virt_to_phys(descr);
+ /* Start the DMA */
+ *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
- e100_enable_serial_data_irq(info);
-#endif
- /* input dma should be running now */
-
- /* unthrottle if we have throttled */
- if (E100_RTS_GET(info))
- tty->driver.unthrottle(info->tty);
+ /* Input DMA should be running now */
+ return 1;
}
static void
start_receive(struct e100_serial *info)
{
- struct etrax_dma_descr *descr;
-
#ifdef CONFIG_SVINTO_SIM
/* No receive in the simulator. Will probably be when the rest of
* the serial interface works, and this piece will just be removed.
@@ -1410,21 +1459,10 @@ start_receive(struct e100_serial *info)
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
- descr = &info->rec_descr;
-
- /* start the receiving dma into the flip buffer */
-
- descr->ctrl = d_int | d_eol | d_eop;
- descr->sw_len = TTY_FLIPBUF_SIZE;
- descr->buf = virt_to_phys(info->tty->flip.char_buf_ptr);
- descr->hw_len = 0;
- descr->status = 0;
-
info->tty->flip.count = 0;
- *info->ifirstadr = virt_to_phys(descr);
- *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
+ start_recv_dma(info);
+
#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
start_flush_timer();
#endif
@@ -1474,9 +1512,16 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
info = rs_table + i;
if (!info->uses_dma)
continue;
- /* check for dma_descr (dont need to check for dma_eop in output dma for serial */
+ /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
if (ireg & info->irq) {
/* we can send a new dma bunch. make it so. */
+ DEBUG_LOG(info->line, "tr_interrupt %i\n", i);
+ /* Read jiffies_usec first,
+ * we want this time to be as late as possible
+ */
+ PROCSTAT(ser_stat[info->line].tx_dma_ints++);
+ info->last_tx_active_usec = GET_JIFFIES_USEC();
+ info->last_tx_active = jiffies;
transmit_chars(info);
}
@@ -1524,77 +1569,26 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
}
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static int serial_fast_timer_started = 0;
-static int serial_fast_timer_expired = 0;
-static void flush_timeout_function(unsigned long data);
-#define START_FLUSH_FAST_TIMER(info, string) {\
- unsigned long timer_flags; \
- save_flags(timer_flags); \
- cli(); \
- TIMERD(DEBUG_LOG(info->line, "start_timer? %i ", info->line)); \
- if (fast_timers[info->line].function == NULL) { \
- serial_fast_timer_started++; \
- TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
- TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
- start_one_shot_timer(&fast_timers[info->line], \
- flush_timeout_function, \
- (unsigned long)info, \
- info->char_time_usec*4, \
- string); \
- } \
- else { \
- /* DEBUG_LOG(info->line, " ## timer %i running ##\n", info->line); */ \
- } \
- restore_flags(timer_flags); \
-}
-
-#else
-#define START_FLUSH_FAST_TIMER(info, string)
-#endif
-
-void _INLINE_ check_flush_timeout(struct e100_serial *info)
+static _INLINE_ int
+force_eop_if_needed(struct e100_serial *info)
{
- unsigned char rstat;
- unsigned int magic;
-
- if (0 /*info->tty->processing_flip*/) {
- if (!E100_RTS_GET(info)) {
- int left = (*info->ihwswadr >> 16) - (*info->istatusadr & 0x3F);
-
- if (left < TTY_THROTTLE_LIMIT)
- info->tty->driver.throttle(info->tty);
- }
-
- PROCSTAT(ser_stat[info->line].processing_flip++);
- START_FLUSH_FAST_TIMER(info, "flip");
- return;
- }
-
/* We check data_avail bit to determine if data has
* arrived since last time
*/
- magic = info->fifo_magic;
-#ifdef SERIAL_DEBUG_DATA
- if (info->fifo_magic || info->fifo_didmagic) {
- DEBUG_LOG(info->line, "timeout_int: did fifo_magic %03X\n",
- (info->fifo_didmagic << 8) | info->fifo_magic);
- }
-#endif
- rstat = info->port[REG_STATUS];
+ unsigned char rstat = info->port[REG_STATUS];
+
/* error or datavail? */
if (rstat & SER_ERROR_MASK) {
- /* Some error has occured */
- /* If there has been valid data,
- * an EOP interrupt will be made automatically.
- * If no data, the normal ser_interrupt should be enabled
- * and handle it.
+ /* Some error has occurred. If there has been valid data, an
+ * EOP interrupt will be made automatically. If no data, the
+ * normal ser_interrupt should be enabled and handle it.
* So do nothing!
*/
DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
rstat | (info->line << 8));
- return;
+ return 0;
}
+
if (rstat & SER_DATA_AVAIL_MASK) {
/* Ok data, no error, count it */
TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
@@ -1602,32 +1596,87 @@ void _INLINE_ check_flush_timeout(struct e100_serial *info)
/* Read data to clear status flags */
(void)info->port[REG_DATA];
- magic++;
+ info->forced_eop = 0;
+ START_FLUSH_FAST_TIMER(info, "magic");
+ return 0;
}
- if (magic != info->fifo_magic) {
- info->fifo_magic = magic;
- info->fifo_didmagic = 0;
- START_FLUSH_FAST_TIMER(info, "magic");
- } else {
- /* hit the timeout, force an EOP for the input
- * dma channel if we haven't already
- */
- if (!info->fifo_didmagic && magic) {
- info->fifo_didmagic = 1;
- info->fifo_magic = 0;
- PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
- DEBUG_LOG(info->line, "timeout EOP %i\n", info->line);
- TIMERD(DEBUG_LOG(info->line, "timeout magic %i\n", magic));
- FORCE_EOP(info);
- }
+ /* hit the timeout, force an EOP for the input
+ * dma channel if we haven't already
+ */
+ if (!info->forced_eop) {
+ info->forced_eop = 1;
+ PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
+ DEBUG_LOG(info->line, "timeout EOP %i\n", info->line);
+ FORCE_EOP(info);
}
-} /* check_flush_timeout */
+
+ return 1;
+}
+
+static _INLINE_ void
+flush_to_flip_buffer(struct e100_serial *info)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE);
+ unsigned int length;
+ unsigned long flags;
+
+ if (!count)
+ return;
+
+ save_flags(flags);
+ cli();
+
+ length = tty->flip.count;
+
+ do {
+ if (length + count > TTY_FLIPBUF_SIZE)
+ count = TTY_FLIPBUF_SIZE - length;
+
+ memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count);
+ memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count);
+ info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1));
+ length += count;
+
+ count = CIRC_CNT_TO_END(info->recv.head,
+ info->recv.tail,
+ SERIAL_RECV_SIZE);
+ } while (length < TTY_FLIPBUF_SIZE && count);
+
+ tty->flip.count = length;
+
+ restore_flags(flags);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,66)
+ /* this includes a check for low-latency */
+ tty_flip_buffer_push(tty);
+#else
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
+
+ /* unthrottle if we have throttled */
+ if (E100_RTS_GET(info) &&
+ CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT)
+ tty->driver.unthrottle(info->tty);
+}
+
+static _INLINE_ void
+check_flush_timeout(struct e100_serial *info)
+{
+ force_eop_if_needed(info);
+
+ flush_to_flip_buffer(info);
+
+ if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE))
+ START_FLUSH_FAST_TIMER(info, "flip");
+}
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
static void flush_timeout_function(unsigned long data)
{
struct e100_serial *info = (struct e100_serial *)data;
+
fast_timers[info->line].function = NULL;
serial_fast_timer_expired++;
TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
@@ -1681,7 +1730,6 @@ timed_flush_handler(unsigned long ptr)
{
struct e100_serial *info;
int i;
- unsigned int magic;
#ifdef CONFIG_SVINTO_SIM
return;
@@ -1689,35 +1737,8 @@ timed_flush_handler(unsigned long ptr)
for (i = 0; i < NR_PORTS; i++) {
info = rs_table + i;
- if (!info->enabled || !(info->flags & ASYNC_INITIALIZED))
- continue;
-
- /* istatusadr (bit 6-0) hold number of bytes in fifo
- * ihwswadr (bit 31-16) holds number of bytes in dma buffer
- * ihwswadr (bit 15-0) specifies size of dma buffer
- */
-
- magic = (*info->istatusadr & 0x3f);
- magic += ((*info->ihwswadr & 0xffff) - (*info->ihwswadr >> 16));
-
- /* if magic is equal to fifo_magic (magic in previous
- * timeout_interrupt) then no new data has arrived since last
- * interrupt and we'll force eop to flush fifo+dma buffers
- */
-
- if (magic != info->fifo_magic) {
- info->fifo_magic = magic;
- info->fifo_didmagic = 0;
- } else {
- /* hit the timeout, force an EOP for the input
- * dma channel if we haven't already
- */
- if (!info->fifo_didmagic && magic) {
- info->fifo_didmagic = 1;
- info->fifo_magic = 0;
- FORCE_EOP(info);
- }
- }
+ if (info->uses_dma)
+ check_flush_timeout(info);
}
/* restart flush timer */
@@ -1770,7 +1791,7 @@ If RXD pin is 0 we can expect another character (see 2. below).
Multiple frame errors with data == 0x00 (B),
but the part of the break trigs is interpreted as a start bit (and possibly
-som 0 bits followed by a number of 1 bits and a stop bit).
+some 0 bits followed by a number of 1 bits and a stop bit).
Depending on parity settings etc. this last character can be either
a fake "valid" char (F) or have a parity error (E).
@@ -1805,19 +1826,20 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
if (rstat & SER_ERROR_MASK) {
unsigned char data;
+
info->last_rx_active_usec = GET_JIFFIES_USEC();
info->last_rx_active = jiffies;
- /* if we got an error, we must reset it by
- * reading the data_in field
+ /* If we got an error, we must reset it by reading the
+ * data_in field
*/
data = info->port[REG_DATA];
- if ((data == 0x00) && (rstat & SER_FRAMING_ERR_MASK)) {
- /* Most likely a break, but we get
- * interrupts over and over again.
+ if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
+ /* Most likely a break, but we get interrupts over and
+ * over again.
*/
- if (info->break_detected_cnt == 0) {
+ if (!info->break_detected_cnt) {
DEBUG_LOG(info->line, "#BRK start\n", 0);
}
if (rstat & SER_RXD_MASK) {
@@ -1833,46 +1855,46 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
}
info->break_detected_cnt++;
} else {
- /* Error doesn't look like a break,
- * but could be end of a break
+ /* The error does not look like a break, but could be
+ * the end of one
*/
if (info->break_detected_cnt) {
DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
info->errorcode = ERRCODE_INSERT_BREAK;
+ } else {
+ if (info->errorcode == ERRCODE_INSERT_BREAK)
+ add_char_and_flag(info, '\0', TTY_BREAK);
+
+ if (rstat & SER_PAR_ERR_MASK)
+ add_char_and_flag(info, data, TTY_PARITY);
+ else if (rstat & SER_OVERRUN_MASK)
+ add_char_and_flag(info, data, TTY_OVERRUN);
+ else if (rstat & SER_FRAMING_ERR_MASK)
+ add_char_and_flag(info, data, TTY_FRAME);
+ info->errorcode = 0;
}
info->break_detected_cnt = 0;
DEBUG_LOG(info->line, "#iERR s d %04X\n",
((rstat & SER_ERROR_MASK) << 8) | data);
}
PROCSTAT(ser_stat[info->line].early_errors_cnt++);
-
-#if 0
- /* Reset DMA before starting */
- *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
- while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
- IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-#endif
- } else { /* it was a valid byte, now let the dma do the rest */
- unsigned char data;
+ } else { /* It was a valid byte, now let the DMA do the rest */
unsigned long curr_time_u = GET_JIFFIES_USEC();
unsigned long curr_time = jiffies;
if (info->break_detected_cnt) {
- /* Detect if this character is a new
- * valid char or the last char in a
- * break sequence:
- * If LSBits are 0 and MSBits are high
- * AND the time is close to the
- * previous interrupt we should discard
- * it.
+ /* Detect if this character is a new valid char or the
+ * last char in a break sequence: If LSBits are 0 and
+ * MSBits are high AND the time is close to the
+ * previous interrupt we should discard it.
*/
long elapsed_usec =
- (curr_time - info->last_rx_active) * (1000000/HZ) +
- curr_time_u - info->last_rx_active_usec;
- if (elapsed_usec<2*info->char_time_usec) {
+ (curr_time - info->last_rx_active) * (1000000/HZ) +
+ curr_time_u - info->last_rx_active_usec;
+ if (elapsed_usec < 2*info->char_time_usec) {
DEBUG_LOG(info->line, "FBRK %i\n", info->line);
- /* Report as BREAK (error) and
- * let receive_chars handle it
+ /* Report as BREAK (error) and let
+ * receive_chars() handle it
*/
info->errorcode = ERRCODE_SET_BREAK;
} else {
@@ -1880,22 +1902,19 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
}
DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
}
- /* Reset data_avail by
- * reading the data_in field
- */
- data = info->port[REG_DATA];
- info->break_detected_cnt = 0;
- info->fifo_magic++; /* Count received chars */
+
#ifdef SERIAL_DEBUG_INTR
printk("** OK, disabling ser_interupts\n");
#endif
- PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
- DEBUG_LOG(info->line, " ser_int OK %03X\n",
- (info->line << 8) | data);
e100_disable_serial_data_irq(info);
+
+ info->break_detected_cnt = 0;
+
+ PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
+ DEBUG_LOG(info->line, "ser_int OK %d\n", info->line);
}
- /* restart the DMA never hurts */
+ /* Restarting the DMA never hurts */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
START_FLUSH_FAST_TIMER(info, "ser_int");
} /* handle_ser_interrupt */
@@ -1973,7 +1992,7 @@ do_serial_hangup(void *private_)
{
struct e100_serial *info = (struct e100_serial *) private_;
struct tty_struct *tty;
-
+
tty = info->tty;
if (!tty)
return;
@@ -1985,43 +2004,46 @@ static int
startup(struct e100_serial * info)
{
unsigned long flags;
- unsigned long page;
+ unsigned long xmit_page;
+ unsigned char *recv_page;
+
+ xmit_page = get_zeroed_page(GFP_KERNEL);
+ if (!xmit_page)
+ return -ENOMEM;
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
+ recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL);
+ if (!recv_page) {
+ free_page(xmit_page);
return -ENOMEM;
+ }
save_flags(flags); cli();
/* if it was already initialized, skip this */
-
+
if (info->flags & ASYNC_INITIALIZED) {
- free_page(page);
restore_flags(flags);
+ free_page(xmit_page);
+ kfree(recv_page);
return 0;
}
-
+
if (info->xmit.buf)
- free_page(page);
+ free_page(xmit_page);
else
- info->xmit.buf = (unsigned char *) page;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf);
-#endif
-
- if (info->tty) {
-
- /* clear the tty flip flag buffer since we will not
- * be using it (we only use the first byte..)
- */
+ info->xmit.buf = (unsigned char *) xmit_page;
- memset(info->tty->flip.flag_buf, 0, TTY_FLIPBUF_SIZE * 2);
+ if (info->recv.buf)
+ kfree(recv_page);
+ else {
+ info->recv.buf = (unsigned char *) recv_page;
+ info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE;
}
- save_flags(flags);
- cli();
-
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf);
+#endif
+
#ifdef CONFIG_SVINTO_SIM
/* Bits and pieces collected from below. Better to have them
in one ifdef:ed clause than to mix in a lot of ifdefs,
@@ -2029,7 +2051,8 @@ startup(struct e100_serial * info)
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit.head = info->xmit.tail = 0;
-
+ info->recv.head = info->recv.tail = 0;
+
/* No real action in the simulator, but may set info important
to ioctl. */
change_speed(info);
@@ -2039,33 +2062,35 @@ startup(struct e100_serial * info)
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
-
+
/*
* Reset the DMA channels and make sure their interrupts are cleared
*/
-
+
info->uses_dma = 1;
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
- /* wait until reset cycle is complete */
+ /* Wait until reset cycle is complete */
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
+
+ /* Make sure the irqs are cleared */
*info->iclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
*info->oclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
+
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit.head = info->xmit.tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
+ info->recv.head = info->recv.tail = 0;
/*
* and set the speed and other flags of the serial port
@@ -2085,7 +2110,7 @@ startup(struct e100_serial * info)
e100_enable_txdma_irq(info);
e100_enable_rxdma_irq(info);
- info->tr_running = 0; /* to be sure we dont lock up the transmitter */
+ info->tr_running = 0; /* to be sure we don't lock up the transmitter */
/* setup the dma input descriptor and start dma */
@@ -2120,7 +2145,7 @@ shutdown(struct e100_serial * info)
unsigned long flags;
#ifndef CONFIG_SVINTO_SIM
- /* shut down the transmitter and receiver */
+ /* shut down the transmitter and receiver */
e100_disable_rx(info);
info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
@@ -2150,9 +2175,14 @@ shutdown(struct e100_serial * info)
cli(); /* Disable interrupts */
if (info->xmit.buf) {
- unsigned long pg = (unsigned long) info->xmit.buf;
- info->xmit.buf = 0;
- free_page(pg);
+ free_page((unsigned long)info->xmit.buf);
+ info->xmit.buf = NULL;
+ }
+
+ if (info->recv.buf) {
+ kfree(info->recv.buf);
+ info->recv.buf = NULL;
+ info->flag_buf = NULL;
}
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
@@ -2258,11 +2288,11 @@ rs_flush_chars(struct tty_struct *tty)
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
- if (info->tr_running
- || info->xmit.head == info->xmit.tail
- || tty->stopped
- || tty->hw_stopped
- || !info->xmit.buf)
+ if (info->tr_running ||
+ info->xmit.head == info->xmit.tail ||
+ tty->stopped ||
+ tty->hw_stopped ||
+ !info->xmit.buf)
return;
#ifdef SERIAL_DEBUG_FLOW
@@ -2299,7 +2329,7 @@ rs_write(struct tty_struct * tty, int from_user,
#ifdef CONFIG_SVINTO_SIM
/* Really simple. The output is here and now. */
SIMCOUT(buf, count);
- return;
+ return count;
#endif
save_flags(flags);
@@ -2370,8 +2400,8 @@ rs_write(struct tty_struct * tty, int from_user,
* the IRQ's are not running anyway for this port.
*/
- if (info->xmit.head != info->xmit.tail
- && !tty->stopped &&
+ if (info->xmit.head != info->xmit.tail &&
+ !tty->stopped &&
!tty->hw_stopped &&
!info->tr_running) {
start_transmit(info);
@@ -2528,20 +2558,20 @@ get_serial_info(struct e100_serial * info,
tmp.flags = info->flags;
tmp.close_delay = info->close_delay;
tmp.closing_wait = info->closing_wait;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
}
static int
-set_serial_info(struct e100_serial * info,
- struct serial_struct * new_info)
+set_serial_info(struct e100_serial *info,
+ struct serial_struct *new_info)
{
struct serial_struct new_serial;
struct e100_serial old_info;
- int retval = 0;
+ int retval = 0;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
old_info = *info;
@@ -2636,6 +2666,7 @@ const struct state_str control_state_str[] = {
char *get_control_state_str(int MLines, char *s)
{
int i = 0;
+
s[0]='\0';
while (control_state_str[i].str != NULL) {
if (MLines & control_state_str[i].state) {
@@ -2805,9 +2836,13 @@ static int
rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+#if defined(CONFIG_ETRAX_RS485) || (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+ int error;
+#endif
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
int retval;
+#endif
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
@@ -3108,7 +3143,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
struct e100_serial *info)
{
DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
+ unsigned long flags;
int retval;
int do_clocal = 0, extra_count = 0;
@@ -3292,7 +3327,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
}
/*
- * If the port is the middle of closing, bail out now
+ * If the port is in the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
@@ -3346,12 +3381,11 @@ rs_open(struct tty_struct *tty, struct file * filp)
static inline int line_info(char *buf, struct e100_serial *info)
{
- char stat_buf[30], control, status;
+ char stat_buf[30];
int ret;
- unsigned long flags;
ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
- info->line, info->port, info->irq);
+ info->line, (unsigned long)info->port, info->irq);
if (!info->port || (info->type == PORT_UNKNOWN)) {
ret += sprintf(buf+ret, "\n");
@@ -3376,19 +3410,24 @@ static inline int line_info(char *buf, struct e100_serial *info)
ret += sprintf(buf+ret, " baud:%d", info->baud);
ret += sprintf(buf+ret, " tx:%lu rx:%lu",
- info->icount.tx, info->icount.rx);
+ (unsigned long)info->icount.tx,
+ (unsigned long)info->icount.rx);
if (info->icount.frame)
- ret += sprintf(buf+ret, " fe:%lu", info->icount.frame);
+ ret += sprintf(buf+ret, " fe:%lu",
+ (unsigned long)info->icount.frame);
if (info->icount.parity)
- ret += sprintf(buf+ret, " pe:%lu", info->icount.parity);
+ ret += sprintf(buf+ret, " pe:%lu",
+ (unsigned long)info->icount.parity);
if (info->icount.brk)
- ret += sprintf(buf+ret, " brk:%lu", info->icount.brk);
+ ret += sprintf(buf+ret, " brk:%lu",
+ (unsigned long)info->icount.brk);
if (info->icount.overrun)
- ret += sprintf(buf+ret, " oe:%lu", info->icount.overrun);
+ ret += sprintf(buf+ret, " oe:%lu",
+ (unsigned long)info->icount.overrun);
/*
* Last thing is the RS-232 status lines
@@ -3526,8 +3565,7 @@ rs_init(void)
info->tty = 0;
info->type = PORT_ETRAX;
info->tr_running = 0;
- info->fifo_magic = 0;
- info->fifo_didmagic = 0;
+ info->forced_eop = 0;
info->flags = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = 30*HZ;
@@ -3541,8 +3579,21 @@ rs_init(void)
info->normal_termios = serial_driver.init_termios;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
- info->xmit.buf = 0;
+ info->xmit.buf = NULL;
info->xmit.tail = info->xmit.head = 0;
+ info->recv.buf = NULL;
+ info->recv.tail = info->recv.head = 0;
+ info->flag_buf = NULL;
+ info->last_tx_active_usec = 0;
+ info->last_tx_active = 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+ /* Set sane defaults */
+ info->rs485.rts_on_send = 0;
+ info->rs485.rts_after_sent = 1;
+ info->rs485.delay_rts_before_send = 0;
+ info->rs485.enabled = 0;
+#endif
if (info->enabled) {
printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
diff --git a/arch/cris/drivers/serial.h b/arch/cris/drivers/serial.h
index 119f2fb85..c06d47342 100644
--- a/arch/cris/drivers/serial.h
+++ b/arch/cris/drivers/serial.h
@@ -23,81 +23,90 @@
* For definitions of the flags field, see tty.h
*/
+#define SERIAL_RECV_DESCRIPTORS 8
+
struct e100_serial {
- int baud;
- volatile u8 *port; /* R_SERIALx_CTRL */
- u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
- volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */
- volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */
- volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD, output */
- const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */
- volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */
-
- volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
- volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */
- volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD, input */
- const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */
- volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */
-
- int flags; /* defined in tty.h */
-
- u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
- u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
- u8 iseteop; /* bit number for R_SET_EOP for the input dma */
- int enabled; /* Set to 1 if the port is enabled in HW config */
-
+ int baud;
+ volatile u8 *port; /* R_SERIALx_CTRL */
+ u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+ /* Output registers */
+ volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+ volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */
+ volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */
+ const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */
+ volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW */
+ volatile u32 *odescradr; /* adr to R_DMA_CHx_DESCR */
+
+ /* Input registers */
+ volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+ volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */
+ volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
+ const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS */
+ volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW */
+ volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
+
+ int flags; /* defined in tty.h */
+
+ u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+ u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+ u8 iseteop; /* bit number for R_SET_EOP for the input dma */
+
+ int enabled; /* Set to 1 if the port is enabled in HW config */
-/* end of fields defined in rs_table[] in .c-file */
- int uses_dma; /* Set to 1 if DMA should be used */
- unsigned char fifo_didmagic; /* a fifo eop has been forced */
+ /* end of fields defined in rs_table[] in .c-file */
- struct etrax_dma_descr tr_descr, rec_descr;
+ int uses_dma; /* Set to 1 if DMA should be used */
+ unsigned char forced_eop; /* a fifo eop has been forced */
- int fifo_magic; /* fifo amount - bytes left in dma buffer */
+ struct etrax_dma_descr tr_descr;
+ struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS];
+ int cur_rec_descr;
- volatile int tr_running; /* 1 if output is running */
+ volatile int tr_running; /* 1 if output is running */
- struct tty_struct *tty;
+ struct tty_struct *tty;
int read_status_mask;
int ignore_status_mask;
int x_char; /* xon/xoff character */
int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
unsigned long event;
unsigned long last_active;
int line;
- int type; /* PORT_ETRAX */
+ int type; /* PORT_ETRAX */
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
long session; /* Session of opening process */
long pgrp; /* pgrp of opening process */
- struct circ_buf xmit;
+ struct circ_buf xmit;
+ struct circ_buf recv;
+ unsigned char *flag_buf;
struct tq_struct tqueue;
- struct async_icount icount; /* error-statistics etc.*/
- struct termios normal_termios;
- struct termios callout_termios;
+ struct async_icount icount; /* error-statistics etc.*/
+ struct termios normal_termios;
+ struct termios callout_termios;
#ifdef DECLARE_WAITQUEUE
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-#else
- struct wait_queue *open_wait;
- struct wait_queue *close_wait;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+#else
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
#endif
- unsigned long char_time_usec; /* The time for 1 char, in usecs */
- unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */
- unsigned long last_tx_active; /* Last tx time in jiffies */
- unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */
- unsigned long last_rx_active; /* Last rx time in jiffies */
+ unsigned long char_time_usec; /* The time for 1 char, in usecs */
+ unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */
+ unsigned long last_tx_active; /* Last tx time in jiffies */
+ unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */
+ unsigned long last_rx_active; /* Last rx time in jiffies */
- int break_detected_cnt;
- int errorcode;
+ int break_detected_cnt;
+ int errorcode;
#ifdef CONFIG_RS485
- struct rs485_control rs485; /* RS-485 support */
+ struct rs485_control rs485; /* RS-485 support */
#endif
};
@@ -116,4 +125,4 @@ struct e100_serial {
#endif /* __KERNEL__ */
-#endif /* !(_ETRAX_SERIAL_H) */
+#endif /* !_ETRAX_SERIAL_H */
diff --git a/arch/cris/drivers/sync_serial.c b/arch/cris/drivers/sync_serial.c
index 4d3f9c01b..6974945fa 100644
--- a/arch/cris/drivers/sync_serial.c
+++ b/arch/cris/drivers/sync_serial.c
@@ -711,7 +711,7 @@ static void start_dma(struct sync_port* port, const char* data, int count)
{
port->out_descr.hw_len = 0;
port->out_descr.next = 0;
- port->out_descr.ctrl = d_int | d_eol | d_eop;
+ port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait;
port->out_descr.sw_len = count;
port->out_descr.buf = virt_to_phys(port->out_buffer);
port->out_descr.status = 0;
diff --git a/arch/cris/drivers/usb-host.c b/arch/cris/drivers/usb-host.c
index b2a93ce4d..8e4e9e932 100644
--- a/arch/cris/drivers/usb-host.c
+++ b/arch/cris/drivers/usb-host.c
@@ -192,15 +192,15 @@ static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4)));
static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
-static urb_t *URB_List[NBR_OF_EP_DESC];
+static struct urb *URB_List[NBR_OF_EP_DESC];
static kmem_cache_t *usb_desc_cache;
static struct usb_bus *etrax_usb_bus;
static void dump_urb (struct urb *urb);
static void init_rx_buffers(void);
-static int etrax_rh_unlink_urb (urb_t *urb);
-static void etrax_rh_send_irq(urb_t *urb);
-static void etrax_rh_init_int_timer(urb_t *urb);
+static int etrax_rh_unlink_urb (struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
static void etrax_rh_int_timer_do(unsigned long ptr);
static void etrax_usb_setup_epid(char epid, char devnum, char endpoint,
@@ -210,13 +210,13 @@ static int etrax_usb_allocate_epid(void);
static void etrax_usb_free_epid(char epid);
static void cleanup_sb(USB_SB_Desc_t *sb);
-static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen);
-static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen);
+static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen);
+static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen);
-static int etrax_usb_submit_ctrl_urb(urb_t *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
-static int etrax_usb_submit_urb(urb_t *urb);
-static int etrax_usb_unlink_urb(urb_t *urb);
+static int etrax_usb_submit_urb(struct urb *urb);
+static int etrax_usb_unlink_urb(struct urb *urb);
static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
@@ -225,7 +225,7 @@ static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs);
-static int etrax_rh_submit_urb (urb_t *urb);
+static int etrax_rh_submit_urb (struct urb *urb);
static int etrax_usb_hc_init(void);
static void etrax_usb_hc_cleanup(void);
@@ -421,7 +421,7 @@ static void init_tx_intr_ep(void)
}
-static int etrax_usb_unlink_intr_urb(urb_t *urb)
+static int etrax_usb_unlink_intr_urb(struct urb *urb)
{
struct usb_device *usb_dev = urb->dev;
etrax_hc_t *hc = usb_dev->bus->hcpriv;
@@ -512,7 +512,7 @@ void etrax_usb_do_intr_recover(int epid)
} while (tmp_ep != first_ep);
}
-static int etrax_usb_submit_intr_urb(urb_t *urb)
+static int etrax_usb_submit_intr_urb(struct urb *urb)
{
USB_EP_Desc_t *tmp_ep;
USB_EP_Desc_t *first_ep;
@@ -643,7 +643,7 @@ static int etrax_usb_submit_intr_urb(urb_t *urb)
static int handle_intr_transfer_attn(char epid, int status)
{
- urb_t *old_urb;
+ struct urb *old_urb;
DBFENTER;
@@ -696,7 +696,7 @@ static int handle_intr_transfer_attn(char epid, int status)
DBFEXIT;
}
-static int etrax_rh_unlink_urb (urb_t *urb)
+static int etrax_rh_unlink_urb (struct urb *urb)
{
etrax_hc_t *hc;
@@ -713,7 +713,7 @@ static int etrax_rh_unlink_urb (urb_t *urb)
return 0;
}
-static void etrax_rh_send_irq(urb_t *urb)
+static void etrax_rh_send_irq(struct urb *urb)
{
__u16 data = 0;
etrax_hc_t *hc = urb->dev->bus->hcpriv;
@@ -746,7 +746,7 @@ static void etrax_rh_send_irq(urb_t *urb)
/* DBFEXIT; */
}
-static void etrax_rh_init_int_timer(urb_t *urb)
+static void etrax_rh_init_int_timer(struct urb *urb)
{
etrax_hc_t *hc;
@@ -765,12 +765,12 @@ static void etrax_rh_init_int_timer(urb_t *urb)
static void etrax_rh_int_timer_do(unsigned long ptr)
{
- urb_t *urb;
+ struct urb *urb;
etrax_hc_t *hc;
/* DBFENTER; */
- urb = (urb_t*)ptr;
+ urb = (struct urb *)ptr;
hc = urb->dev->bus->hcpriv;
if (hc->rh.send) {
@@ -904,7 +904,7 @@ static int etrax_usb_allocate_epid(void)
return -1;
}
-static int etrax_usb_submit_bulk_urb(urb_t *urb)
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
{
char epid;
char devnum;
@@ -912,7 +912,7 @@ static int etrax_usb_submit_bulk_urb(urb_t *urb)
char maxlen;
char slow;
- urb_t *tmp_urb;
+ struct urb *tmp_urb;
etrax_urb_priv_t *urb_priv;
unsigned long flags;
@@ -962,7 +962,7 @@ static int etrax_usb_submit_bulk_urb(urb_t *urb)
return 0;
}
-static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen)
+static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen)
{
USB_SB_Desc_t *sb_desc_1;
@@ -1080,7 +1080,7 @@ static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen)
static int handle_bulk_transfer_attn(char epid, int status)
{
- urb_t *old_urb;
+ struct urb *old_urb;
etrax_urb_priv_t *hc_priv;
unsigned long flags;
@@ -1159,7 +1159,7 @@ static int handle_bulk_transfer_attn(char epid, int status)
/* ---------------------------------------------------------------------------- */
-static int etrax_usb_submit_ctrl_urb(urb_t *urb)
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
{
char epid;
char devnum;
@@ -1167,7 +1167,7 @@ static int etrax_usb_submit_ctrl_urb(urb_t *urb)
char maxlen;
char slow;
- urb_t *tmp_urb;
+ struct urb *tmp_urb;
etrax_urb_priv_t *urb_priv;
unsigned long flags;
@@ -1217,7 +1217,7 @@ static int etrax_usb_submit_ctrl_urb(urb_t *urb)
return 0;
}
-static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen)
+static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen)
{
USB_SB_Desc_t *sb_desc_1;
USB_SB_Desc_t *sb_desc_2;
@@ -1358,7 +1358,7 @@ static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen)
DBFEXIT;
}
-static int etrax_usb_submit_urb(urb_t *urb)
+static int etrax_usb_submit_urb(struct urb *urb)
{
etrax_hc_t *hc;
int rval = -EINVAL;
@@ -1403,7 +1403,7 @@ static int etrax_usb_submit_urb(urb_t *urb)
return rval;
}
-static int etrax_usb_unlink_urb(urb_t *urb)
+static int etrax_usb_unlink_urb(struct urb *urb)
{
etrax_hc_t *hc = urb->dev->bus->hcpriv;
int epid;
@@ -1448,7 +1448,7 @@ static int etrax_usb_unlink_urb(urb_t *urb)
cli();
for (epid = 0; epid < 32; epid++) {
- urb_t *u = URB_List[epid];
+ struct urb *u = URB_List[epid];
pos = 0;
for (; u; u = u->next) {
@@ -1474,7 +1474,7 @@ static int etrax_usb_unlink_urb(urb_t *urb)
URB_List[epid] = u->next;
} else {
- urb_t *up;
+ struct urb *up;
for (up = URB_List[epid]; up->next != u; up = up->next);
up->next = u->next;
}
@@ -1522,7 +1522,7 @@ static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
etrax_hc_t *hc = (etrax_hc_t *)vhc;
int epid;
char eol;
- urb_t *urb;
+ struct urb *urb;
USB_EP_Desc_t *tmp_ep;
USB_SB_Desc_t *tmp_sb;
@@ -1551,7 +1551,7 @@ static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
{
int epid = 0;
- urb_t *urb;
+ struct urb *urb;
etrax_urb_priv_t *urb_priv;
*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
@@ -1649,7 +1649,7 @@ static void cleanup_sb(USB_SB_Desc_t *sb)
static int handle_control_transfer_attn(char epid, int status)
{
- urb_t *old_urb;
+ struct urb *old_urb;
etrax_urb_priv_t *hc_priv;
DBFENTER;
@@ -1710,7 +1710,7 @@ static int handle_control_transfer_attn(char epid, int status)
static void etrax_usb_hc_intr_bottom_half(void *data)
{
struct usb_reg_context *reg = (struct usb_reg_context *)data;
- urb_t *old_urb;
+ struct urb *old_urb;
int error_code;
int epid;
@@ -1976,7 +1976,7 @@ static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs)
DBFEXIT;
}
-static int etrax_rh_submit_urb(urb_t *urb)
+static int etrax_rh_submit_urb(struct urb *urb)
{
struct usb_device *usb_dev = urb->dev;
etrax_hc_t *hc = usb_dev->bus->hcpriv;
diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile
index be2063e2f..9a92e3b2b 100644
--- a/arch/cris/kernel/Makefile
+++ b/arch/cris/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 2001/10/22 13:10:21 pkj Exp $
+# $Id: Makefile,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
#
# Makefile for the linux kernel.
#
diff --git a/arch/cris/kernel/debugport.c b/arch/cris/kernel/debugport.c
index c6b1b8805..059a2b412 100644
--- a/arch/cris/kernel/debugport.c
+++ b/arch/cris/kernel/debugport.c
@@ -12,6 +12,9 @@
* init_etrax_debug()
*
* $Log: debugport.c,v $
+ * Revision 1.2 2002/01/21 15:21:50 bjornw
+ * Update for kdev_t changes
+ *
* Revision 1.6 2001/04/17 13:58:39 orjanf
* * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
*
@@ -214,7 +217,7 @@ enableDebugIRQ(void)
static kdev_t
console_device(struct console *c)
{
- return MKDEV(TTY_MAJOR, 64 + c->index);
+ return mk_kdev(TTY_MAJOR, 64 + c->index);
}
static int __init
@@ -224,17 +227,16 @@ console_setup(struct console *co, char *options)
}
static struct console sercons = {
- "ttyS",
- console_write,
- NULL,
- console_device,
- NULL,
- NULL,
- console_setup,
- CON_PRINTBUFFER,
- DEBUG_PORT_IDX,
- 0,
- NULL
+ name: "ttyS",
+ write: console_write,
+ read: NULL,
+ device: console_device,
+ unblank: NULL,
+ setup: console_setup,
+ flags: CON_PRINTBUFFER,
+ index: DEBUG_PORT_IDX,
+ cflag: 0,
+ next: NULL
};
/*
diff --git a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S
index a33a1c12a..8512ba943 100644
--- a/arch/cris/kernel/entry.S
+++ b/arch/cris/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.35 2001/10/30 17:10:15 bjornw Exp $
+/* $Id: entry.S,v 1.3 2002/01/21 15:22:20 bjornw Exp $
*
* linux/arch/cris/entry.S
*
@@ -7,6 +7,18 @@
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: entry.S,v $
+ * Revision 1.3 2002/01/21 15:22:20 bjornw
+ * NICE_DOGGY fix from 2.4 arch/cris
+ *
+ * Revision 1.37 2001/12/07 17:03:55 bjornw
+ * Call a c-hook called watchdog_bite_hook instead of show_registers directly
+ *
+ * Revision 1.36 2001/11/22 13:36:36 bjornw
+ * * In ret_from_intr, check regs->dccr for usermode reentrance instead of
+ * DCCR explicitely (because the latter might not reflect current reality)
+ * * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before
+ * since $r9 is call-clobbered and is potentially needed afterwards
+ *
* Revision 1.35 2001/10/30 17:10:15 bjornw
* Add some syscalls
*
@@ -217,8 +229,11 @@ _handle_softirq:
ret_from_intr:
;; check for resched only if we're going back to user-mode
-
- move $ccr, $r0
+ ;; this test matches the user_regs(regs) macro
+ ;; we cannot simply test $dccr, because that does not necessarily
+ ;; reflect what mode we'll return into.
+
+ move.d [$sp + LDCCR], $r0; regs->dccr
btstq 8, $r0 ; U-flag
bpl _Rexit ; go back directly
nop
@@ -468,8 +483,6 @@ mmu_bus_fault:
moveq 1, $r10
push $r10 ; frametype == 1, BUSFAULT frame type
- moveq 0, $r9 ; busfault is equivalent to an irq
-
move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault
jsr handle_mmu_bus_fault ; in arch/cris/mm/fault.c
@@ -479,6 +492,8 @@ mmu_bus_fault:
;; process due to a SEGV, scheduled due to a page blocking or
;; whatever.
+ moveq 0, $r9 ; busfault is equivalent to an irq
+
ba ret_from_intr
nop
@@ -559,6 +574,17 @@ _killed_by_death:
;; We'll see this in ksymoops dumps.
Watchdog_bite:
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+ ;; We just restart the watchdog here to be sure we dont get
+ ;; hit while printing the watchdogmsg below
+ ;; This restart is compatible with the rest of the C-code, so
+ ;; the C-code can keep restarting the watchdog after this point.
+ ;; The non-NICE_DOGGY code below though, disables the possibility
+ ;; to restart since it changes the watchdog key, to avoid any
+ ;; buggy loops etc. keeping the watchdog alive after this.
+ jsr reset_watchdog
+#else
+
;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
;; time for an oops-dump over a 115k2 serial wire. Another 100ms should do.
@@ -576,6 +602,8 @@ Watchdog_bite:
| IO_STATE (R_WATCHDOG, enable, start), $r10
move.d $r10, [$r11]
+#endif
+
;; Note that we don't do "setf m" here (or after two necessary NOPs),
;; since *not* doing that saves us from re-entrancy checks. We don't want
;; to get here again due to possible subsequent NMIs; we want the watchdog
@@ -585,7 +613,7 @@ Watchdog_bite:
jsr printk
move.d $sp, $r10
- jsr show_registers
+ jsr watchdog_bite_hook
;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
;; rather than "spurious_interrupt".
diff --git a/arch/cris/kernel/head.S b/arch/cris/kernel/head.S
index 3eef976e5..bbd4eb3dd 100644
--- a/arch/cris/kernel/head.S
+++ b/arch/cris/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.41 2001/10/29 14:55:58 pkj Exp $
+/* $Id: head.S,v 1.2 2001/12/18 13:35:19 bjornw Exp $
*
* Head of the kernel - alter with care
*
@@ -7,6 +7,15 @@
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: head.S,v $
+ * Revision 1.2 2001/12/18 13:35:19 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.43 2001/11/08 15:09:43 starvik
+ * Only start MII clock if Ethernet is configured
+ *
+ * Revision 1.42 2001/11/08 14:37:34 starvik
+ * Start MII clock early to make sure that it is running at tranceiver reset
+ *
* Revision 1.41 2001/10/29 14:55:58 pkj
* Corrected pa$r0 to par0.
*
@@ -156,7 +165,10 @@
#define CRAMFS_MAGIC 0x28cd3d45
#define RAM_INIT_MAGIC 0x56902387
-
+
+#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
+ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
+
;; exported symbols
.globl etrax_irv
@@ -301,6 +313,12 @@ _inflash0:
;; after init.
.section ".text.init"
_inflash:
+#ifdef CONFIG_ETRAX_ETHERNET
+ ;; Start MII clock to make sure it is running when tranceiver is reset
+ move.d START_ETHERNET_CLOCK, $r0
+ move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+
;; We need to initialze DRAM registers before we start using the DRAM
cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized?
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index 9dd53469b..5f2dda734 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $
+/* $Id: irq.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
*
* linux/arch/cris/kernel/irq.c
*
@@ -138,7 +138,7 @@ set_break_vector(int n, irqvectptr addr)
/* IRQ0 and 1 are special traps */
void hwbreakpoint(void);
void IRQ1_interrupt(void);
-BUILD_IRQ(2, 0x04) /* the timer interrupt */
+BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */
BUILD_IRQ(3, 0x08)
BUILD_IRQ(4, 0x10)
BUILD_IRQ(5, 0x20)
diff --git a/arch/cris/kernel/kgdb.c b/arch/cris/kernel/kgdb.c
index e5c6428d7..5d5c9d4bb 100644
--- a/arch/cris/kernel/kgdb.c
+++ b/arch/cris/kernel/kgdb.c
@@ -18,6 +18,9 @@
*! Jul 21 1999 Bjorn Wesen eLinux port
*!
*! $Log: kgdb.c,v $
+*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+*! Import of Linux 2.5.1
+*!
*! Revision 1.6 2001/10/09 13:10:03 matsfg
*! Added $ on registers and removed some underscores
*!
@@ -55,7 +58,7 @@
*!
*!---------------------------------------------------------------------------
*!
-*! $Id: kgdb.c,v 1.6 2001/10/09 13:10:03 matsfg Exp $
+*! $Id: kgdb.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*!
*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
*!
diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c
index aaf66ee05..ef798138f 100644
--- a/arch/cris/kernel/ksyms.c
+++ b/arch/cris/kernel/ksyms.c
@@ -23,34 +23,45 @@
extern void dump_thread(struct pt_regs *, struct user *);
extern unsigned long get_cmos_time(void);
+extern void __Udiv(void);
extern void __ashrdi3(void);
extern void iounmap(void *addr);
-/* platform dependent support */
-
+/* Platform dependent support */
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(get_cmos_time);
+EXPORT_SYMBOL(loops_per_usec);
+/* String functions */
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(simple_strtol);
EXPORT_SYMBOL(strstr);
-
+EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strncmp);
+
+/* Math functions */
+EXPORT_SYMBOL(__Udiv);
EXPORT_SYMBOL(__ashrdi3);
+/* Memory functions */
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
-/* export shadow registers for the CPU I/O pins */
+/* Semaphore functions */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+/* Export shadow registers for the CPU I/O pins */
EXPORT_SYMBOL(genconfig_shadow);
EXPORT_SYMBOL(port_pa_data_shadow);
EXPORT_SYMBOL(port_pa_dir_shadow);
@@ -59,8 +70,7 @@ EXPORT_SYMBOL(port_pb_dir_shadow);
EXPORT_SYMBOL(port_pb_config_shadow);
EXPORT_SYMBOL(port_g_data_shadow);
-/* other stuff */
-
+/* Userspace access functions */
EXPORT_SYMBOL(strncpy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__generic_copy_from_user);
@@ -71,8 +81,8 @@ EXPORT_SYMBOL(__copy_user);
#undef memcpy
#undef memset
-extern void * memset(void *,int,__kernel_size_t);
-extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memset(void *, int, __kernel_size_t);
+extern void * memcpy(void *, const void *, __kernel_size_t);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 00be67c79..37263479c 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.20 2001/10/03 08:21:39 jonashg Exp $
+/* $Id: process.c,v 1.3 2002/01/21 15:22:49 bjornw Exp $
*
* linux/arch/cris/kernel/process.c
*
@@ -8,6 +8,15 @@
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: process.c,v $
+ * Revision 1.3 2002/01/21 15:22:49 bjornw
+ * current->counter is gone
+ *
+ * Revision 1.22 2001/11/13 09:40:43 orjanf
+ * Added dump_fpu (needed for core dumps).
+ *
+ * Revision 1.21 2001/11/12 18:26:21 pkj
+ * Fixed compiler warnings.
+ *
* Revision 1.20 2001/10/03 08:21:39 jonashg
* cause_of_death does not exist if CONFIG_SVINTO_SIM is defined.
*
@@ -57,6 +66,7 @@
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/elfcore.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -77,7 +87,6 @@
* setup.
*/
-static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
@@ -135,14 +144,15 @@ void hard_reset_now (void)
* code to know about it than the watchdog handler in entry.S and
* this code, implementing hard reset through the watchdog.
*/
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
extern int cause_of_death;
+#endif
printk("*** HARD RESET ***\n");
cli();
#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
cause_of_death = 0xbedead;
-
#else
/* Since we dont plan to keep on reseting the watchdog,
the key can be arbitrary hence three */
@@ -243,9 +253,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*/
void dump_thread(struct pt_regs * regs, struct user * dump)
{
- int i;
#if 0
-/* changed the size calculations - should hopefully work better. lbt */
+ int i;
+
+ /* changed the size calculations - should hopefully work better. lbt */
dump->magic = CMAGIC;
dump->start_code = 0;
dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
@@ -265,6 +276,12 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
#endif
}
+/* Fill in the fpu structure for a core dump. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+ return 0;
+}
+
/*
* Be aware of the "magic" 7th argument in the four system-calls below.
* They need the latest stackframe, which is put as the 7th argument by
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
index fd0f23159..59f7d38fe 100644
--- a/arch/cris/kernel/ptrace.c
+++ b/arch/cris/kernel/ptrace.c
@@ -8,6 +8,12 @@
* Authors: Bjorn Wesen
*
* $Log: ptrace.c,v $
+ * Revision 1.2 2001/12/18 13:35:20 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.8 2001/11/12 18:26:21 pkj
+ * Fixed compiler warnings.
+ *
* Revision 1.7 2001/09/26 11:53:49 bjornw
* PTRACE_DETACH works more simple in 2.4.10
*
@@ -74,8 +80,6 @@ static inline long get_reg(struct task_struct *task, unsigned int regno)
static inline int put_reg(struct task_struct *task, unsigned int regno,
unsigned long data)
{
- unsigned long *addr;
-
if (regno == PT_USP)
task->thread.usp = data;
else if (regno < PT_MAX)
@@ -207,9 +211,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
break;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- long tmp;
-
+ case PTRACE_CONT: /* restart after signal. */
ret = -EIO;
if ((unsigned long) data > _NSIG)
break;
@@ -222,16 +224,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
wake_up_process(child);
ret = 0;
break;
- }
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
- case PTRACE_KILL: {
- long tmp;
-
+ case PTRACE_KILL:
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
break;
@@ -239,11 +238,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* TODO: make sure any pending breakpoint is killed */
wake_up_process(child);
break;
- }
-
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- long tmp;
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
ret = -EIO;
if ((unsigned long) data > _NSIG)
break;
@@ -256,7 +252,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
wake_up_process(child);
ret = 0;
break;
- }
case PTRACE_DETACH:
ret = ptrace_detach(child, data);
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
index 2a7f45cc6..820359196 100644
--- a/arch/cris/kernel/setup.c
+++ b/arch/cris/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.22 2001/10/23 17:42:58 pkj Exp $
+/* $Id: setup.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
*
* linux/arch/cris/kernel/setup.c
*
@@ -26,10 +26,12 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/seq_file.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/smp.h>
+#include <asm/pgtable.h>
#include <asm/types.h>
#include <asm/svinto.h>
@@ -72,10 +74,10 @@ extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S *
void __init
setup_arch(char **cmdline_p)
{
- unsigned long bootmap_size;
+ extern void init_etrax_debug(void);
+ unsigned long bootmap_size;
unsigned long start_pfn, max_pfn;
unsigned long memory_start;
- extern void console_print_etrax(const char *b);
/* register an initial console printing routine for printk's */
@@ -87,12 +89,12 @@ setup_arch(char **cmdline_p)
if(romfs_in_flash || !romfs_length) {
/* if we have the romfs in flash, or if there is no rom filesystem,
- * our free area starts directly after the BSS
+ * our free area starts directly after the BSS
*/
memory_start = (unsigned long) &_end;
} else {
/* otherwise the free area starts after the ROM filesystem */
- printk("ROM fs in RAM, size %d bytes\n", romfs_length);
+ printk("ROM fs in RAM, size %lu bytes\n", romfs_length);
memory_start = romfs_start + romfs_length;
}
@@ -193,7 +195,7 @@ setup_arch(char **cmdline_p)
#define HAS_ATA 0x0020
#define HAS_USB 0x0040
#define HAS_IRQ_BUG 0x0080
-#define HAS_MMU_BUG 0x0100
+#define HAS_MMU_BUG 0x0100
static struct cpu_info {
char *model;
@@ -213,50 +215,27 @@ static struct cpu_info {
{ "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG },
{ "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
{ "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG },
- { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU },
+ { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU },
{ "Unknown", 0, 0 } /* This entry MUST be the last */
};
-/*
- * get_cpuinfo - Get information on one CPU for use by the procfs.
- *
- * Prints info on the next CPU into buffer. Beware, doesn't check for
- * buffer overflow. Current implementation of procfs assumes that the
- * resulting data is <= 1K.
- *
- * BUFFER is PAGE_SIZE - 1K bytes long.
- *
- * Args:
- * buffer -- you guessed it, the data buffer
- * cpu_np -- Input: next cpu to get (start at 0). Output: Updated.
- *
- * Returns number of bytes written to buffer.
- */
-int get_cpuinfo(char *buffer, unsigned *cpu_np)
+static int show_cpuinfo(struct seq_file *m, void *v)
{
- int revision;
- struct cpu_info *info;
- unsigned n;
+ unsigned long revision;
+ struct cpu_info *info;
/* read the version register in the CPU and print some stuff */
revision = rdvr();
- if (revision < 0 || revision >= sizeof cpu_info/sizeof *cpu_info) {
+ if (revision >= sizeof cpu_info/sizeof *cpu_info)
info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1];
- } else
+ else
info = &cpu_info[revision];
- /* No SMP at the moment, so just toggle 0/1 */
- n = *cpu_np;
- *cpu_np = 1;
- if (n != 0) {
- return (0);
- }
-
- return sprintf(buffer,
+ return seq_printf(m,
"cpu\t\t: CRIS\n"
- "cpu revision\t: %d\n"
+ "cpu revision\t: %lu\n"
"cpu model\t: %s\n"
"cache size\t: %d kB\n"
"fpu\t\t: %s\n"
@@ -283,4 +262,28 @@ int get_cpuinfo(char *buffer, unsigned *cpu_np)
(loops_per_jiffy * HZ + 500) / 500000,
((loops_per_jiffy * HZ + 500) / 5000) % 100);
}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ /* We only got one CPU... */
+ return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return NULL;
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+ start: c_start,
+ next: c_next,
+ stop: c_stop,
+ show: show_cpuinfo,
+};
+
#endif /* CONFIG_PROC_FS */
diff --git a/arch/cris/kernel/shadows.c b/arch/cris/kernel/shadows.c
index ff2373a66..25fac6494 100644
--- a/arch/cris/kernel/shadows.c
+++ b/arch/cris/kernel/shadows.c
@@ -1,4 +1,4 @@
-/* $Id: shadows.c,v 1.2 2001/03/15 14:25:16 bjornw Exp $
+/* $Id: shadows.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* Various shadow registers. Defines for these are in include/asm-etrax100/io.h
*/
diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c
index 7fbb2e803..6db339ce2 100644
--- a/arch/cris/kernel/sys_cris.c
+++ b/arch/cris/kernel/sys_cris.c
@@ -1,4 +1,4 @@
-/* $Id: sys_cris.c,v 1.10 2001/06/27 21:16:15 hp Exp $
+/* $Id: sys_cris.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* linux/arch/cris/kernel/sys_cris.c
*
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
index 00b8ff6e8..537040f95 100644
--- a/arch/cris/kernel/time.c
+++ b/arch/cris/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.9 2001/10/25 10:26:37 johana Exp $
+/* $Id: time.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
*
* linux/arch/cris/kernel/time.c
*
@@ -18,6 +18,7 @@
* Linux/CRIS specific code:
*
* Authors: Bjorn Wesen
+ * Johan Adolfsson
*
*/
@@ -61,6 +62,7 @@ unsigned short cris_timer0_value_us[TIMER0_DIV+1];
static unsigned long do_slow_gettimeoffset(void)
{
unsigned long count;
+ unsigned long usec_count = 0;
static unsigned long count_p = LATCH; /* for the first call after boot */
static unsigned long jiffies_p = 0;
@@ -93,16 +95,20 @@ static unsigned long do_slow_gettimeoffset(void)
*/
if( jiffies_t == jiffies_p ) {
if( count > count_p ) {
+ /* Timer wrapped */
+ count = count_p;
+ usec_count = 1000000/CLOCK_TICK_RATE/2;
}
} else
jiffies_p = jiffies_t;
-
count_p = count;
-
+ /* Convert timer value to usec using table lookup */
+ usec_count += cris_timer0_value_us[count];
+#if 0
count = ((LATCH-1) - count) * TICK_SIZE;
count = (count + LATCH/2) / LATCH;
-
- return count;
+#endif
+ return usec_count;
}
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
@@ -160,9 +166,8 @@ static int set_rtc_mmss(unsigned long nowtime)
{
int retval = 0;
int real_seconds, real_minutes, cmos_minutes;
- unsigned char save_control, save_freq_select;
- printk("set_rtc_mmss(%d)\n", nowtime);
+ printk("set_rtc_mmss(%lu)\n", nowtime);
if(!have_rtc)
return 0;
@@ -225,7 +230,9 @@ static int set_rtc_mmss(unsigned long nowtime)
/* right now, starting the watchdog is the same as resetting it */
#define start_watchdog reset_watchdog
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
static int watchdog_key = 0; /* arbitrary number */
+#endif
/* number of pages to consider "out of memory". it is normal that the memory
* is used though, so put this really low.
@@ -306,12 +313,12 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((time_status & STA_UNSYNC) == 0 &&
xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
+ xtime.tv_usec < 500000 + (tick >> 1)) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600;
-
+ }
}
#if 0
@@ -322,6 +329,7 @@ void print_timestamp(const char *s)
{
unsigned long flags;
unsigned int newjiff;
+
save_flags(flags);
cli();
newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA);
@@ -337,7 +345,6 @@ unsigned long
get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
- int i;
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c
index 9fcda3abd..af7d639de 100644
--- a/arch/cris/kernel/traps.c
+++ b/arch/cris/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $
+/* $Id: traps.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
*
* linux/arch/cris/traps.c
*
@@ -30,6 +30,55 @@
int kstack_depth_to_print = 24;
+void show_trace(unsigned long * stack)
+{
+ unsigned long addr, module_start, module_end;
+ extern char _stext, _etext;
+ int i;
+
+ printk("\nCall Trace: ");
+
+ i = 1;
+ module_start = VMALLOC_START;
+ module_end = VMALLOC_END;
+
+ while (((long) stack & (THREAD_SIZE-1)) != 0) {
+ if (__get_user (addr, stack)) {
+ /* This message matches "failing address" marked
+ s390 in ksymoops, so lines containing it will
+ not be filtered out by ksymoops. */
+ printk ("Failing address 0x%lx\n", (unsigned long)stack);
+ break;
+ }
+ stack++;
+
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (((addr >= (unsigned long) &_stext) &&
+ (addr <= (unsigned long) &_etext)) ||
+ ((addr >= module_start) && (addr <= module_end))) {
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("[<%08lx>] ", addr);
+ i++;
+ }
+ }
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+ /* TODO, this is not really useful since its called from
+ * SysRq-T and we don't have a keyboard.. :)
+ */
+}
+
+
/*
* These constants are for searching for possible module text
* segments. MODULE_RANGE is a guess of how much space is likely
@@ -48,9 +97,8 @@ int kstack_depth_to_print = 24;
void
show_stack(unsigned long *sp)
{
- unsigned long *stack, addr, module_start, module_end;
+ unsigned long *stack, addr;
int i;
- extern char _stext, _etext;
/*
* debugging aid: "show_stack(NULL);" prints a
@@ -62,7 +110,7 @@ show_stack(unsigned long *sp)
stack = sp;
- printk("\nStack from %08lx:\n ", stack);
+ printk("\nStack from %08lx:\n ", (unsigned long)stack);
for(i = 0; i < kstack_depth_to_print; i++) {
if (((long) stack & (THREAD_SIZE-1)) == 0)
break;
@@ -72,45 +120,13 @@ show_stack(unsigned long *sp)
/* This message matches "failing address" marked
s390 in ksymoops, so lines containing it will
not be filtered out by ksymoops. */
- printk ("Failing address 0x%lx\n", stack);
+ printk ("Failing address 0x%lx\n", (unsigned long)stack);
break;
}
stack++;
printk("%08lx ", addr);
}
-
- printk("\nCall Trace: ");
- stack = sp;
- i = 1;
- module_start = VMALLOC_START;
- module_end = VMALLOC_END;
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
- if (__get_user (addr, stack)) {
- /* This message matches "failing address" marked
- s390 in ksymoops, so lines containing it will
- not be filtered out by ksymoops. */
- printk ("Failing address 0x%lx\n", stack);
- break;
- }
- stack++;
-
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (((addr >= (unsigned long) &_stext) &&
- (addr <= (unsigned long) &_etext)) ||
- ((addr >= module_start) && (addr <= module_end))) {
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("[<%08lx>] ", addr);
- i++;
- }
- }
+ show_trace(sp);
}
#if 0
@@ -148,7 +164,7 @@ show_registers(struct pt_regs * regs)
regs->r8, regs->r9, regs->r10, regs->r11);
printk("r12: %08lx r13: %08lx oR10: %08lx\n",
regs->r12, regs->r13, regs->orig_r10);
- printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE);
+ printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
printk("Process %s (pid: %d, stackpage=%08lx)\n",
current->comm, current->pid, (unsigned long)current);
@@ -195,25 +211,56 @@ bad:
}
}
+/* Called from entry.S when the watchdog has bitten
+ * We print out something resembling an oops dump, and if
+ * we have the nice doggy development flag set, we halt here
+ * instead of rebooting.
+ */
+
+void
+watchdog_bite_hook(struct pt_regs *regs)
+{
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+ cli();
+ stop_watchdog();
+ show_registers(regs);
+ while(1) /* nothing */;
+#else
+ show_registers(regs);
+#endif
+}
+
+/* This is normally the 'Oops' routine */
+
void
die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
+ extern void reset_watchdog(void);
+ extern void stop_watchdog(void);
+
if(user_mode(regs))
return;
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+ /* This printout might take too long and trigger the
+ * watchdog normally. If we're in the nice doggy
+ * development mode, stop the watchdog during printout.
+ */
stop_watchdog();
+#endif
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
reset_watchdog();
-
+#endif
do_exit(SIGSEGV);
}
void __init
trap_init(void)
{
- /* Nothing needs to be done */
+ /* Nothing needs to be done */
}
diff --git a/arch/cris/lib/checksum.S b/arch/cris/lib/checksum.S
index 134aac28d..fd15a76f7 100644
--- a/arch/cris/lib/checksum.S
+++ b/arch/cris/lib/checksum.S
@@ -1,4 +1,4 @@
-/* $Id: checksum.S,v 1.6 2001/10/01 14:47:35 bjornw Exp $
+/* $Id: checksum.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
* A fast checksum routine using movem
* Copyright (c) 1998-2001 Axis Communications AB
*
diff --git a/arch/cris/lib/checksumcopy.S b/arch/cris/lib/checksumcopy.S
index ad3a8f5db..4d8bc348d 100644
--- a/arch/cris/lib/checksumcopy.S
+++ b/arch/cris/lib/checksumcopy.S
@@ -1,4 +1,4 @@
-/* $Id: checksumcopy.S,v 1.7 2001/10/01 14:47:35 bjornw Exp $
+/* $Id: checksumcopy.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
* A fast checksum+copy routine using movem
* Copyright (c) 1998, 2001 Axis Communications AB
*
diff --git a/arch/cris/lib/dmacopy.c b/arch/cris/lib/dmacopy.c
index 318577a2d..fe8f091ed 100644
--- a/arch/cris/lib/dmacopy.c
+++ b/arch/cris/lib/dmacopy.c
@@ -1,4 +1,4 @@
-/* $Id: dmacopy.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+/* $Id: dmacopy.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax
*/
diff --git a/arch/cris/lib/dram_init.S b/arch/cris/lib/dram_init.S
index 0d59ce119..d46efd1ae 100644
--- a/arch/cris/lib/dram_init.S
+++ b/arch/cris/lib/dram_init.S
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.10 2001/10/04 12:00:21 martinnn Exp $
+/* $Id: dram_init.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* DRAM/SDRAM initialization - alter with care
* This file is intended to be included from other assembler files
@@ -11,6 +11,9 @@
* Authors: Mikael Starvik (starvik@axis.com)
*
* $Log: dram_init.S,v $
+ * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+ * Import of Linux 2.5.1
+ *
* Revision 1.10 2001/10/04 12:00:21 martinnn
* Added missing underscores.
*
diff --git a/arch/cris/lib/hw_settings.S b/arch/cris/lib/hw_settings.S
index aca3b351a..b35bb3baa 100644
--- a/arch/cris/lib/hw_settings.S
+++ b/arch/cris/lib/hw_settings.S
@@ -1,5 +1,5 @@
/*
- * $Id: hw_settings.S,v 1.3 2001/04/21 17:02:46 bjornw Exp $
+ * $Id: hw_settings.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* This table is used by some tools to extract hardware parameters.
* The table should be included in the kernel and the decompressor.
diff --git a/arch/cris/lib/old_checksum.c b/arch/cris/lib/old_checksum.c
index 6035a48ae..ae0f7b9eb 100644
--- a/arch/cris/lib/old_checksum.c
+++ b/arch/cris/lib/old_checksum.c
@@ -1,4 +1,4 @@
-/* $Id: old_checksum.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+/* $Id: old_checksum.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
diff --git a/arch/cris/mm/extable.c b/arch/cris/mm/extable.c
index 2431ee143..7351f59f8 100644
--- a/arch/cris/mm/extable.c
+++ b/arch/cris/mm/extable.c
@@ -2,6 +2,9 @@
* linux/arch/cris/mm/extable.c
*
* $Log: extable.c,v $
+ * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw
+ * Import of Linux 2.5.1
+ *
* Revision 1.3 2001/09/27 13:52:40 bjornw
* Harmonize underscore-ness with other parts
*
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 7e1f6d7c2..e62134d47 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -6,6 +6,20 @@
* Authors: Bjorn Wesen
*
* $Log: fault.c,v $
+ * Revision 1.2 2001/12/18 13:35:22 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.20 2001/11/22 13:34:06 bjornw
+ * * Bug workaround (LX TR89): force a rerun of the whole of an interrupted
+ * unaligned write, because the second half of the write will be corrupted
+ * otherwise. Affected unaligned writes spanning not-yet mapped pages.
+ * * Optimization: use the wr_rd bit in R_MMU_CAUSE to know whether a miss
+ * was due to a read or a write (before we didn't know this until the next
+ * restart of the interrupted instruction, thus wasting one fault-irq)
+ *
+ * Revision 1.19 2001/11/12 19:02:10 pkj
+ * Fixed compiler warnings.
+ *
* Revision 1.18 2001/07/18 22:14:32 bjornw
* Enable interrupts in the bulk of do_page_fault
*
@@ -78,7 +92,14 @@ asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
int error_code);
/* debug of low-level TLB reload */
+#undef DEBUG
+
+#ifdef DEBUG
+#define D(x) x
+#else
#define D(x)
+#endif
+
/* debug of higher-level faults */
#define DPG(x)
@@ -94,9 +115,12 @@ void
handle_mmu_bus_fault(struct pt_regs *regs)
{
int cause, select;
+#ifdef DEBUG
int index;
int page_id;
- int miss, we, acc, inv;
+ int acc, inv;
+#endif
+ int miss, we, writeac;
pmd_t *pmd;
pte_t pte;
int errcode;
@@ -106,75 +130,83 @@ handle_mmu_bus_fault(struct pt_regs *regs)
select = *R_TLB_SELECT;
address = cause & PAGE_MASK; /* get faulting address */
-
- D(page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause));
- D(acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause));
- D(inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause));
- D(index = IO_EXTRACT(R_TLB_SELECT, index, select));
+
+#ifdef DEBUG
+ page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
+ acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
+ inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
+ index = IO_EXTRACT(R_TLB_SELECT, index, select);
+#endif
miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause);
we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
+ writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause);
+
+ /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned
+ * write causes a MMU-fault, it will not be restarted correctly.
+ * This could happen if a write crosses a page-boundary and the
+ * second page is not yet COW'ed or even loaded. The workaround
+ * is to clear the unaligned bit in the CPU status record, so
+ * that the CPU will rerun both the first and second halves of
+ * the instruction. This will not have any sideeffects unless
+ * the first half goes to any device or memory that can't be
+ * written twice, and which is mapped through the MMU.
+ *
+ * We only need to do this for writes.
+ */
+
+ if(writeac)
+ regs->csrinstr &= ~(1 << 5);
- /* Note: the reason we don't set errcode's r/w flag here
- * using the 'we' flag, is because the latter is only given
- * if there is a write-protection exception, not given as a
- * general r/w access mode flag. It is currently not possible
- * to get this from the MMU (TODO: check if this is the case
- * for LXv2).
- *
- * The page-fault code won't care, but there will be two page-
- * faults instead of one for the case of a write to a non-tabled
- * page (miss, then write-protection).
+ /* Set errcode's R/W flag according to the mode which caused the
+ * fault
*/
- errcode = 0;
+ errcode = writeac << 1;
- D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
- "idx %d pid %d\n",
+ D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
regs->irp, address, miss, inv, we, acc, index, page_id));
/* for a miss, we need to reload the TLB entry */
- if(miss) {
-
+ if (miss) {
/* see if the pte exists at all
* refer through current_pgd, dont use mm->pgd
*/
-
+
pmd = (pmd_t *)(current_pgd + pgd_index(address));
- if(pmd_none(*pmd))
+ if (pmd_none(*pmd))
goto dofault;
- if(pmd_bad(*pmd)) {
- printk("bad pgdir entry 0x%x at 0x%x\n", *pmd, pmd);
+ if (pmd_bad(*pmd)) {
+ printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd);
pmd_clear(pmd);
return;
}
pte = *pte_offset(pmd, address);
- if(!pte_present(pte))
+ if (!pte_present(pte))
goto dofault;
-
- D(printk(" found pte %x pg %x ", pte_val(pte), pte_page(pte)));
- D(
- {
- if(pte_val(pte) & _PAGE_SILENT_WRITE)
- printk("Silent-W ");
- if(pte_val(pte) & _PAGE_KERNEL)
- printk("Kernel ");
- if(pte_val(pte) & _PAGE_SILENT_READ)
- printk("Silent-R ");
- if(pte_val(pte) & _PAGE_GLOBAL)
- printk("Global ");
- if(pte_val(pte) & _PAGE_PRESENT)
- printk("Present ");
- if(pte_val(pte) & _PAGE_ACCESSED)
- printk("Accessed ");
- if(pte_val(pte) & _PAGE_MODIFIED)
- printk("Modified ");
- if(pte_val(pte) & _PAGE_READ)
- printk("Readable ");
- if(pte_val(pte) & _PAGE_WRITE)
- printk("Writeable ");
- printk("\n");
- });
+
+#ifdef DEBUG
+ printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte));
+ if (pte_val(pte) & _PAGE_SILENT_WRITE)
+ printk("Silent-W ");
+ if (pte_val(pte) & _PAGE_KERNEL)
+ printk("Kernel ");
+ if (pte_val(pte) & _PAGE_SILENT_READ)
+ printk("Silent-R ");
+ if (pte_val(pte) & _PAGE_GLOBAL)
+ printk("Global ");
+ if (pte_val(pte) & _PAGE_PRESENT)
+ printk("Present ");
+ if (pte_val(pte) & _PAGE_ACCESSED)
+ printk("Accessed ");
+ if (pte_val(pte) & _PAGE_MODIFIED)
+ printk("Modified ");
+ if (pte_val(pte) & _PAGE_READ)
+ printk("Readable ");
+ if (pte_val(pte) & _PAGE_WRITE)
+ printk("Writeable ");
+ printk("\n");
+#endif
/* load up the chosen TLB entry
* this assumes the pte format is the same as the TLB_LO layout.
@@ -189,10 +221,10 @@ handle_mmu_bus_fault(struct pt_regs *regs)
}
errcode = 1 | (we << 1);
-
+
dofault:
/* leave it to the MM system fault handler below */
- D(printk("do_page_fault %p errcode %d\n", address, errcode));
+ D(printk("do_page_fault %lx errcode %d\n", address, errcode));
do_page_fault(address, regs, errcode);
}
@@ -221,20 +253,19 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
struct mm_struct *mm;
struct vm_area_struct * vma;
int writeaccess;
- int fault;
unsigned long fixup;
siginfo_t info;
tsk = current;
- /*
- * We fault-in kernel-space virtual memory on-demand. The
- * 'reference' page table is init_mm.pgd.
- *
- * NOTE! We MUST NOT take any locks for this case. We may
- * be in an interrupt or a critical region, and should
- * only copy the information from the master page table,
- * nothing more.
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
*
* NOTE2: This is done so that, when updating the vmalloc
* mappings we don't have to walk all processes pgdirs and
@@ -243,13 +274,13 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
* bit set so sometimes the TLB can use a lingering entry.
*
* This verifies that the fault happens in kernel space
- * and that the fault was not a protection error (error_code & 1).
- */
+ * and that the fault was not a protection error (error_code & 1).
+ */
- if (address >= VMALLOC_START &&
+ if (address >= VMALLOC_START &&
!(error_code & 1) &&
!user_mode(regs))
- goto vmalloc_fault;
+ goto vmalloc_fault;
/* we can and should enable interrupts at this point */
sti();
@@ -312,28 +343,27 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
*/
switch (handle_mm_fault(mm, vma, address, writeaccess)) {
- case 1:
- tsk->min_flt++;
- break;
- case 2:
- tsk->maj_flt++;
- break;
- case 0:
- goto do_sigbus;
- default:
- goto out_of_memory;
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ goto do_sigbus;
+ default:
+ goto out_of_memory;
}
up_read(&mm->mmap_sem);
return;
-
+
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
-
up_read(&mm->mmap_sem);
bad_area_nosemaphore:
@@ -361,10 +391,10 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
* code)
*/
- if ((fixup = search_exception_table(regs->irp)) != 0) {
+ if ((fixup = search_exception_table(regs->irp)) != 0) {
/* Adjust the instruction pointer in the stackframe */
- regs->irp = fixup;
+ regs->irp = fixup;
/* We do not want to return by restoring the CPU-state
* anymore, so switch frame-types (see ptrace.h)
@@ -372,9 +402,9 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
regs->frametype = CRIS_FRAME_NORMAL;
- D(printk("doing fixup to 0x%x\n", fixup));
- return;
- }
+ D(printk("doing fixup to 0x%lx\n", fixup));
+ return;
+ }
/*
* Oops. The kernel tried to access some bad page. We'll have to
@@ -397,9 +427,9 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
*/
out_of_memory:
- up_read(&mm->mmap_sem);
+ up_read(&mm->mmap_sem);
printk("VM: killing process %s\n", tsk->comm);
- if(user_mode(regs))
+ if (user_mode(regs))
do_exit(SIGKILL);
goto no_context;
@@ -407,40 +437,40 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
up_read(&mm->mmap_sem);
/*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
info.si_code = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void *)address;
force_sig_info(SIGBUS, &info, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!user_mode(regs))
- goto no_context;
- return;
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+ return;
vmalloc_fault:
- {
- /*
- * Synchronize this task's top level page-table
- * with the 'reference' page table.
+ {
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
*
* Use current_pgd instead of tsk->active_mm->pgd
* since the latter might be unavailable if this
* code is executed in a misfortunately run irq
* (like inside schedule() between switch_mm and
* switch_to...).
- */
+ */
- int offset = pgd_index(address);
- pgd_t *pgd, *pgd_k;
- pmd_t *pmd, *pmd_k;
+ int offset = pgd_index(address);
+ pgd_t *pgd, *pgd_k;
+ pmd_t *pmd, *pmd_k;
pte_t *pte_k;
- pgd = current_pgd + offset;
- pgd_k = init_mm.pgd + offset;
+ pgd = (pgd_t *)current_pgd + offset;
+ pgd_k = init_mm.pgd + offset;
/* Since we're two-level, we don't need to do both
* set_pgd and set_pmd (they do the same thing). If
@@ -454,13 +484,13 @@ vmalloc_fault:
* it exists.
*/
- pmd = pmd_offset(pgd, address);
- pmd_k = pmd_offset(pgd_k, address);
+ pmd = pmd_offset(pgd, address);
+ pmd_k = pmd_offset(pgd_k, address);
- if (!pmd_present(*pmd_k))
- goto bad_area_nosemaphore;
+ if (!pmd_present(*pmd_k))
+ goto bad_area_nosemaphore;
- set_pmd(pmd, *pmd_k);
+ set_pmd(pmd, *pmd_k);
/* Make sure the actual PTE exists as well to
* catch kernel vmalloc-area accesses to non-mapped
@@ -468,10 +498,10 @@ vmalloc_fault:
* silently loop forever.
*/
- pte_k = pte_offset(pmd_k, address);
- if (!pte_present(*pte_k))
- goto no_context;
+ pte_k = pte_offset(pmd_k, address);
+ if (!pte_present(*pte_k))
+ goto no_context;
- return;
- }
+ return;
+ }
}
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
index b9dd26a8c..b7544841b 100644
--- a/arch/cris/mm/init.c
+++ b/arch/cris/mm/init.c
@@ -7,6 +7,15 @@
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: init.c,v $
+ * Revision 1.2 2001/12/18 13:35:22 bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.31 2001/11/13 16:22:00 bjornw
+ * Skip calculating totalram and sharedram in si_meminfo
+ *
+ * Revision 1.30 2001/11/12 19:02:10 pkj
+ * Fixed compiler warnings.
+ *
* Revision 1.29 2001/07/25 16:09:50 bjornw
* val->sharedram will stay 0
*
@@ -459,29 +468,18 @@ free_initmem(void)
free_page(addr);
totalram_pages++;
}
- printk ("Freeing unused kernel memory: %dk freed\n",
+ printk ("Freeing unused kernel memory: %luk freed\n",
(&__init_end - &__init_begin) >> 10);
}
void
si_meminfo(struct sysinfo *val)
{
- int i;
-
- i = max_mapnr;
- val->totalram = 0;
- val->sharedram = 0;
- val->freeram = nr_free_pages();
- val->bufferram = atomic_read(&buffermem_pages);
- while (i-- > 0) {
- if (PageReserved(mem_map+i))
- continue;
- val->totalram++;
- if (!atomic_read(&mem_map[i].count))
- continue;
- val->sharedram += atomic_read(&mem_map[i].count) - 1;
- }
- val->mem_unit = PAGE_SIZE;
- val->totalhigh = 0;
- val->freehigh = 0;
+ val->totalram = totalram_pages;
+ val->sharedram = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+ val->totalhigh = 0;
+ val->freehigh = 0;
+ val->mem_unit = PAGE_SIZE;
}
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index dc4850353..b20f83cd1 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -491,8 +491,6 @@ CONFIG_PCMCIA_PCNET=y
# CONFIG_PCMCIA_XIRTULIP is not set
CONFIG_NET_PCMCIA_RADIO=y
CONFIG_PCMCIA_RAYCS=y
-# CONFIG_PCMCIA_NETWAVE is not set
-# CONFIG_PCMCIA_WAVELAN is not set
# CONFIG_AIRONET4500_CS is not set
#
@@ -738,6 +736,7 @@ CONFIG_USB=y
# USB Host Controller Drivers
#
# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
CONFIG_USB_UHCI_ALT=y
# CONFIG_USB_OHCI is not set
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 02a1a5d09..c81844e10 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -766,14 +766,14 @@ static void apm_cpu_idle(void)
start_idle = jiffies;
while (1) {
- if (!current->need_resched) {
+ if (!need_resched()) {
if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
if (!current_cpu_data.hlt_works_ok)
continue;
if (hlt_counter)
continue;
__cli();
- if (!current->need_resched)
+ if (!need_resched())
safe_halt();
else
__sti();
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index 0a4412a2f..bfa7b8bfb 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -79,6 +79,7 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
* through the ICC by us (IPIs)
*/
#ifdef CONFIG_SMP
+BUILD_SMP_INTERRUPT(task_migration_interrupt,TASK_MIGRATION_VECTOR)
BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
@@ -473,6 +474,9 @@ void __init init_IRQ(void)
*/
set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+ /* IPI for task migration */
+ set_intr_gate(TASK_MIGRATION_VECTOR, task_migration_interrupt);
+
/* IPI for invalidation */
set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index e17b07ecd..0f0b20014 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -42,7 +42,6 @@
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/desc.h>
-#include <asm/mmu_context.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif
@@ -81,7 +80,7 @@ static void default_idle(void)
{
if (current_cpu_data.hlt_works_ok && !hlt_counter) {
__cli();
- if (!current->need_resched)
+ if (!need_resched())
safe_halt();
else
__sti();
@@ -127,7 +126,7 @@ void cpu_idle (void)
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
- while (!current->need_resched)
+ while (!need_resched())
idle();
schedule();
check_pgt_cache();
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index c0b3a94a1..af1dc7387 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -485,6 +485,35 @@ void flush_tlb_all(void)
do_flush_tlb_all_local();
}
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+/*
+ * This function sends a 'task migration' IPI to another CPU.
+ * Must be called from syscall contexts, with interrupts *enabled*.
+ */
+void smp_migrate_task(int cpu, task_t *p)
+{
+ /*
+ * The target CPU will unlock the migration spinlock:
+ */
+ spin_lock(&migration_lock);
+ new_task = p;
+ send_IPI_mask(1 << cpu, TASK_MIGRATION_VECTOR);
+}
+
+/*
+ * Task migration callback.
+ */
+asmlinkage void smp_task_migration_interrupt(void)
+{
+ task_t *p;
+
+ ack_APIC_irq();
+ p = new_task;
+ spin_unlock(&migration_lock);
+ sched_task_migrated(p);
+}
/*
* this function sends a 'reschedule' IPI to another CPU.
* it goes straight through and wastes no time serializing
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 97663b228..34ca9174a 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -462,6 +462,7 @@ int __init start_secondary(void *unused)
* things done here to the most necessary things.
*/
cpu_init();
+ init_idle();
smp_callin();
while (!atomic_read(&smp_commenced))
rep_nop();
@@ -470,8 +471,8 @@ int __init start_secondary(void *unused)
* the local TLBs too.
*/
local_flush_tlb();
+ idle_startup_done();
- init_idle();
return cpu_idle();
}
diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c
index 7d50e87b8..c37a93bea 100644
--- a/arch/i386/math-emu/fpu_entry.c
+++ b/arch/i386/math-emu/fpu_entry.c
@@ -559,7 +559,7 @@ FPU_fwait_done:
RE_ENTRANT_CHECK_ON;
#endif /* DEBUG */
- if (FPU_lookahead && !current->need_resched)
+ if (FPU_lookahead && !need_resched())
{
FPU_ORIG_EIP = FPU_EIP - code_base;
if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 82eb84428..bfdb34b43 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -117,10 +117,10 @@ cpu_idle (void *unused)
while (1) {
#ifdef CONFIG_SMP
- if (!current->need_resched)
+ if (!need_resched())
min_xtp();
#endif
- while (!current->need_resched)
+ while (!need_resched())
continue;
#ifdef CONFIG_SMP
normal_xtp();
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 520a1ea26..ec9a7c0dc 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -56,7 +56,7 @@ asmlinkage void ret_from_fork(void);
static void default_idle(void)
{
while(1) {
- if (!current->need_resched)
+ if (!need_resched())
#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 248c51d94..de4a3a187 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -39,7 +39,7 @@ void cpu_idle(void)
init_idle();
while (1) {
- while (!current->need_resched)
+ while (!need_resched())
if (cpu_wait)
(*cpu_wait)();
schedule();
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 9712dfc05..4d3367c65 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -1674,8 +1674,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp)
oldepc = xcp->cp0_epc;
do {
- if (current->need_resched)
- schedule();
+ cond_resched();
prevepc = xcp->cp0_epc;
insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff --git a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
index 595b39670..aad1e7834 100644
--- a/arch/mips64/kernel/process.c
+++ b/arch/mips64/kernel/process.c
@@ -35,7 +35,7 @@ asmlinkage int cpu_idle(void)
init_idle();
current->nice = 20;
while (1) {
- while (!current->need_resched)
+ while (!need_resched())
if (wait_available)
__asm__("wait");
schedule();
diff --git a/arch/mips64/math-emu/cp1emu.c b/arch/mips64/math-emu/cp1emu.c
index fbb8911b8..5acd218d2 100644
--- a/arch/mips64/math-emu/cp1emu.c
+++ b/arch/mips64/math-emu/cp1emu.c
@@ -1707,8 +1707,7 @@ int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp)
oldepc = xcp->cp0_epc;
do {
- if (current->need_resched)
- schedule();
+ cond_resched();
prevepc = xcp->cp0_epc;
insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index aae398f1e..c49239b95 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -73,8 +73,8 @@ void cpu_idle(void)
current->nice = 20;
while (1) {
- while (!current->need_resched) {
- }
+ while (!need_resched())
+ barrier();
schedule();
check_pgt_cache();
}
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index 3fff2ebb6..2d93e549c 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -66,15 +66,15 @@ int idled(void)
int oldval = xchg(&current->need_resched, -1);
if (!oldval) {
- while(current->need_resched == -1)
- ; /* Do Nothing */
+ while (need_resched())
+ barrier(); /* Do Nothing */
}
}
#endif
- if (do_power_save && !current->need_resched)
+ if (do_power_save && !need_resched())
power_save();
- if (current->need_resched) {
+ if (need_resched()) {
schedule();
check_pgt_cache();
}
@@ -150,7 +150,7 @@ void zero_paged(void)
if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
return;
- while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
+ while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() )
{
/*
* Mark a page as reserved so we can mess with it
@@ -161,8 +161,7 @@ void zero_paged(void)
if ( !pageptr )
return;
- if ( current->need_resched )
- schedule();
+ cond_resched();
/*
* Make the page no cache so we don't blow our cache with 0's
@@ -181,8 +180,7 @@ void zero_paged(void)
*/
for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
{
- if ( current->need_resched )
- schedule();
+ cond_resched();
*(unsigned long *)(bytecount + pageptr) = 0;
}
@@ -243,7 +241,7 @@ void power_save(void)
* -- Cort
*/
_nmask_and_or_msr(MSR_EE, 0);
- if (!current->need_resched)
+ if (!need_resched())
{
asm("mfspr %0,1008" : "=r" (hid0) :);
hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 978c6647b..9ae8a6350 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -60,7 +60,7 @@ int cpu_idle(void *unused)
wait_psw.mask = _WAIT_PSW_MASK;
wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
while(1) {
- if (current->need_resched) {
+ if (need_resched()) {
schedule();
check_pgt_cache();
continue;
diff --git a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c
index c54bb41e7..caa8b6016 100644
--- a/arch/s390x/kernel/process.c
+++ b/arch/s390x/kernel/process.c
@@ -60,7 +60,7 @@ int cpu_idle(void *unused)
wait_psw.mask = _WAIT_PSW_MASK;
wait_psw.addr = (unsigned long) &&idle_wakeup;
while(1) {
- if (current->need_resched) {
+ if (need_resched()) {
schedule();
check_pgt_cache();
continue;
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index ae0dfa9b8..f991af5c7 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -44,11 +44,11 @@ void cpu_idle(void *unused)
while (1) {
if (hlt_counter) {
- if (current->need_resched)
+ if (need_resched())
break;
} else {
__cli();
- while (!current->need_resched) {
+ while (!need_resched()) {
__sti();
asm volatile("sleep" : : : "memory");
__cli();
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 8d7d1689b..22f1f3379 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.160 2002-01-11 08:45:38 davem Exp $
+/* $Id: process.c,v 1.161 2002-01-23 11:27:32 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -106,7 +106,7 @@ int cpu_idle(void)
{
/* endless idle loop with no priority at all */
while(1) {
- if(current->need_resched) {
+ if(need_resched()) {
schedule();
check_pgt_cache();
}
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 2676d0b1c..e9b3d744f 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.31 2002-01-05 07:33:16 davem Exp $
+/* $Id: pci_psycho.c,v 1.32 2002-01-23 11:27:32 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -345,7 +345,7 @@ static unsigned char psycho_pil_table[] = {
/*0x2f*/15, /* Correctable ECC */
/*0x30*/15, /* PCI Bus A Error */
/*0x31*/15, /* PCI Bus B Error */
-/*0x32*/1, /* Power Management */
+/*0x32*/15, /* Power Management */
};
static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -354,7 +354,7 @@ static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = psycho_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 1;
+ ret = 2;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
@@ -377,7 +377,7 @@ static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
break;
default:
- ret = 1;
+ ret = 2;
break;
};
}
@@ -410,6 +410,10 @@ static unsigned int __init psycho_irq_build(struct pci_pbm_info *pbm,
/* Now build the IRQ bucket. */
pil = psycho_ino_to_pil(pdev, ino);
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = p->controller_regs + imap_off;
imap += 4;
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index e9db0065b..a5d23d674 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.41 2001-11-14 13:17:56 davem Exp $
+/* $Id: pci_sabre.c,v 1.42 2002-01-23 11:27:32 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -582,7 +582,7 @@ static unsigned char sabre_pil_table[] = {
/*0x2f*/15, /* Correctable ECC */
/*0x30*/15, /* PCI Bus A Error */
/*0x31*/15, /* PCI Bus B Error */
-/*0x32*/1, /* Power Management */
+/*0x32*/15, /* Power Management */
};
static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -596,7 +596,7 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = sabre_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 1;
+ ret = 2;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
@@ -619,7 +619,7 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
break;
default:
- ret = 1;
+ ret = 2;
break;
};
}
@@ -651,6 +651,10 @@ static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,
/* Now build the IRQ bucket. */
pil = sabre_ino_to_pil(pdev, ino);
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = p->controller_regs + imap_off;
imap += 4;
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 080042657..8da0a54de 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.23 2001-11-14 13:17:56 davem Exp $
+/* $Id: pci_schizo.c,v 1.24 2002-01-23 11:27:32 davem Exp $
* pci_schizo.c: SCHIZO specific PCI controller support.
*
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -344,7 +344,7 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = schizo_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 1;
+ ret = 2;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
@@ -367,7 +367,7 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
break;
default:
- ret = 1;
+ ret = 2;
break;
};
}
@@ -395,6 +395,10 @@ static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
/* Now build the IRQ bucket. */
pil = schizo_ino_to_pil(pdev, ino);
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = p->controller_regs + pbm_off + imap_off;
imap += 4;
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 6cf8e54b9..2612a846b 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.128 2002-01-11 08:45:38 davem Exp $
+/* $Id: process.c,v 1.129 2002-01-23 11:27:32 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -61,7 +61,7 @@ int cpu_idle(void)
* But this requires writing back the contents of the
* L2 cache etc. so implement this later. -DaveM
*/
- while (!current->need_resched)
+ while (!need_resched())
barrier();
schedule();
@@ -80,7 +80,7 @@ int cpu_idle(void)
int cpu_idle(void)
{
while(1) {
- if (current->need_resched != 0) {
+ if (need_resched()) {
unidle_me();
schedule();
check_pgt_cache();
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 66e468c19..6538b8d70 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.18 2001-12-17 07:05:09 davem Exp $
+/* $Id: sbus.c,v 1.19 2002-01-23 11:27:32 davem Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -628,10 +628,10 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
/* SBUS SYSIO INO number to Sparc PIL level. */
static unsigned char sysio_ino_to_pil[] = {
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
3, /* Onboard SCSI */
5, /* Onboard Ethernet */
/*XXX*/ 8, /* Onboard BPP */
@@ -754,6 +754,10 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
panic("Bad SYSIO IRQ translations...");
}
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = sysio_irq_offsets[ino];
if (imap == ((unsigned long)-1)) {
prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index f5a9badf7..8ff3e19b5 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -218,10 +218,12 @@ void __init smp_callin(void)
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
+ init_idle();
+
while (!smp_threads_ready)
membar("#LoadLoad");
- init_idle();
+ idle_startup_done();
}
void cpu_panic(void)
@@ -875,6 +877,48 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
}
}
+/* Process migration IPIs. */
+
+extern unsigned long xcall_migrate_task;
+
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+void smp_migrate_task(int cpu, task_t *p)
+{
+ unsigned long mask = 1UL << cpu;
+
+ if (cpu == smp_processor_id())
+ return;
+
+ if (smp_processors_ready && (cpu_present_map & mask) != 0) {
+ u64 data0 = (((u64)&xcall_migrate_task) & 0xffffffff);
+
+ spin_lock(&migration_lock);
+ new_task = p;
+
+ if (tlb_type == spitfire)
+ spitfire_xcall_deliver(data0, 0, 0, mask);
+ else
+ cheetah_xcall_deliver(data0, 0, 0, mask);
+ }
+}
+
+/* Called at PIL level 1. */
+asmlinkage void smp_task_migration_interrupt(int irq, struct pt_regs *regs)
+{
+ task_t *p;
+
+ if (irq != PIL_MIGRATE)
+ BUG();
+
+ clear_softint(1 << irq);
+
+ p = new_task;
+ spin_unlock(&migration_lock);
+ sched_task_migrated(p);
+}
+
/* CPU capture. */
/* #define CAPTURE_DEBUG */
extern unsigned long xcall_capture;
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 22721d923..3e1575346 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.36 2001-11-28 23:32:16 davem Exp $
+/* $Id: ttable.S,v 1.37 2002-01-23 11:27:32 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
*
* Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,12 @@ tl0_stdfmna: TRAP_NOSAVE(do_stdfmna)
tl0_privact: TRAP_NOSAVE(__do_privact)
tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
-tl0_irq1: TRAP_IRQ(handler_irq, 1) TRAP_IRQ(handler_irq, 2)
+#ifdef CONFIG_SMP
+tl0_irq1: TRAP_IRQ(smp_task_migration_interrupt, 1)
+#else
+tl0_irq1: BTRAP(0x41)
+#endif
+tl0_irq2: TRAP_IRQ(handler_irq, 2)
tl0_irq3: TRAP_IRQ(handler_irq, 3) TRAP_IRQ(handler_irq, 4)
tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6)
tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index a6f2c19ba..6c9a963c7 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.70 2001-11-29 16:42:10 kanoj Exp $
+/* $Id: ultra.S,v 1.71 2002-01-23 11:27:36 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -10,6 +10,7 @@
#include <asm/page.h>
#include <asm/spitfire.h>
#include <asm/mmu_context.h>
+#include <asm/pil.h>
/* Basically, all this madness has to do with the
* fact that Cheetah does not support IMMU flushes
@@ -691,4 +692,11 @@ xcall_call_function:
b,pt %xcc, rtrap
clr %l6
+ .globl xcall_migrate_task
+xcall_migrate_task:
+ mov 1, %g2
+ sllx %g2, (PIL_MIGRATE), %g2
+ wr %g2, 0x0, %set_softint
+ retry
+
#endif /* CONFIG_SMP */
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 35543c2fa..de039206e 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -64,6 +64,8 @@ const struct pci_device_id cciss_pci_device_id[] = {
0x0E11, 0x4080, 0, 0, 0},
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
0x0E11, 0x4082, 0, 0, 0},
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
+ 0x0E11, 0x4083, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -78,6 +80,7 @@ static struct board_type products[] = {
{ 0x40700E11, "Smart Array 5300", &SA5_access },
{ 0x40800E11, "Smart Array 5i", &SA5B_access},
{ 0x40820E11, "Smart Array 532", &SA5B_access},
+ { 0x40830E11, "Smart Array 5312", &SA5B_access},
};
/* How long to wait (in millesconds) for board to go into simple mode */
@@ -102,6 +105,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
static int revalidate_allvol(kdev_t dev);
static int revalidate_logvol(kdev_t dev, int maxusage);
static int frevalidate_logvol(kdev_t dev);
+static int deregister_disk(int ctlr, int logvol);
+static int register_new_disk(kdev_t dev, int cltr);
static void cciss_getgeometry(int cntl_num);
@@ -148,6 +153,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
" Memory Address: 0x%08lx\n"
" IRQ: %d\n"
" Logical drives: %d\n"
+ " Highest Logical Volume ID: %d\n"
" Current Q depth: %d\n"
" Max Q depth since init: %d\n"
" Max # commands on controller since init: %d\n"
@@ -159,12 +165,15 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
(unsigned long)h->vaddr,
(unsigned int)h->intr,
h->num_luns,
+ h->highest_lun,
h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG);
pos += size; len += size;
cciss_proc_tape_report(ctlr, buffer, &pos, &len);
- for(i=0; i<h->num_luns; i++) {
+ for(i=0; i<h->highest_lun; i++) {
drv = &h->drv[i];
+ if (drv->block_size == 0)
+ continue;
size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
ctlr, i, drv->block_size, drv->nr_blocks);
pos += size; len += size;
@@ -344,9 +353,10 @@ static void cciss_geninit( int ctlr)
for(j=0; j<MAX_PART; j++)
hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024;
- hba[ctlr]->gendisk.nr_real++;
+ //hba[ctlr]->gendisk.nr_real++;
(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
}
+ hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
}
/*
* Open. Make sure the device is really there.
@@ -416,24 +426,42 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
switch(cmd) {
case HDIO_GETGEO:
{
- struct hd_geometry *geo = (struct hd_geometry *)arg;
- int diskinfo[4];
-
- if (hba[ctlr]->drv[dsk].cylinders) {
- diskinfo[0] = hba[ctlr]->drv[dsk].heads;
- diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
- diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
- } else {
- diskinfo[0] = 0xff;
- diskinfo[1] = 0x3f;
- diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
- }
- put_user(diskinfo[0], &geo->heads);
- put_user(diskinfo[1], &geo->sectors);
- put_user(diskinfo[2], &geo->cylinders);
- put_user(get_start_sect(inode->i_rdev), &geo->start);
- return 0;
+ struct hd_geometry driver_geo;
+ if (hba[ctlr]->drv[dsk].cylinders) {
+ driver_geo.heads = hba[ctlr]->drv[dsk].heads;
+ driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
+ driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
+ } else {
+ driver_geo.heads = 0xff;
+ driver_geo.sectors = 0x3f;
+ driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+ }
+ driver_geo.start=
+ hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
+ if (copy_to_user((void *) arg, &driver_geo,
+ sizeof( struct hd_geometry)))
+ return -EFAULT;
+ return(0);
}
+ case HDIO_GETGEO_BIG:
+ {
+ struct hd_big_geometry driver_geo;
+ if (hba[ctlr]->drv[dsk].cylinders) {
+ driver_geo.heads = hba[ctlr]->drv[dsk].heads;
+ driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
+ driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
+ } else {
+ driver_geo.heads = 0xff;
+ driver_geo.sectors = 0x3f;
+ driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+ }
+ driver_geo.start=
+ hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
+ if (copy_to_user((void *) arg, &driver_geo,
+ sizeof( struct hd_big_geometry)))
+ return -EFAULT;
+ return(0);
+ }
case BLKRRPART:
return revalidate_logvol(inode->i_rdev, 1);
case BLKGETSIZE:
@@ -603,7 +631,14 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
case CCISS_REVALIDVOLS:
return( revalidate_allvol(inode->i_rdev));
-
+
+ case CCISS_DEREGDISK:
+ return( deregister_disk(ctlr,dsk));
+
+ case CCISS_REGNEWD:
+ {
+ return(register_new_disk(inode->i_rdev, ctlr));
+ }
case CCISS_PASSTHRU:
{
IOCTL_Command_struct iocommand;
@@ -827,8 +862,503 @@ static int revalidate_allvol(kdev_t dev)
return 0;
}
+static int deregister_disk(int ctlr, int logvol)
+{
+ unsigned long flags;
+ struct gendisk *gdev = &(hba[ctlr]->gendisk);
+ ctlr_info_t *h = hba[ctlr];
+ int start, max_p, i;
+
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ /* make sure logical volume is NOT is use */
+ if( h->drv[logvol].usage_count > 1)
+ {
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ return -EBUSY;
+ }
+ h->drv[logvol].usage_count++;
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+ /* invalidate the devices and deregister the disk */
+ max_p = 1 << gdev->minor_shift;
+ start = logvol << gdev->minor_shift;
+ for (i=max_p-1; i>=0; i--)
+ {
+ int minor = start+i;
+ kdev_t kdev = mk_kdev(MAJOR_NR+ctlr, minor);
+ // printk("invalidating( %d %d)\n", ctlr, minor);
+ invalidate_device(kdev, 1);
+ /* so open will now fail */
+ h->sizes[minor] = 0;
+ /* so it will no longer appear in /proc/partitions */
+ gdev->part[minor].start_sect = 0;
+ gdev->part[minor].nr_sects = 0;
+ }
+ /* check to see if it was the last disk */
+ if (logvol == h->highest_lun)
+ {
+ /* if so, find the new hightest lun */
+ int i, newhighest =-1;
+ for(i=0; i<h->highest_lun; i++)
+ {
+ /* if the disk has size > 0, it is available */
+ if (h->sizes[i << gdev->minor_shift] != 0)
+ newhighest = i;
+ }
+ h->highest_lun = newhighest;
+
+ }
+ --h->num_luns;
+ gdev->nr_real = h->highest_lun+1;
+ /* zero out the disk size info */
+ h->drv[logvol].nr_blocks = 0;
+ h->drv[logvol].block_size = 0;
+ h->drv[logvol].LunID = 0;
+ return(0);
+}
+static int sendcmd_withirq(__u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int use_unit_num,
+ unsigned int log_unit,
+ __u8 page_code )
+{
+ ctlr_info_t *h = hba[ctlr];
+ CommandList_struct *c;
+ u64bit buff_dma_handle;
+ unsigned long flags;
+ int return_status = IO_OK;
+
+ if ((c = cmd_alloc(h , 0)) == NULL)
+ {
+ return -ENOMEM;
+ }
+ // Fill in the command type
+ c->cmd_type = CMD_IOCTL_PEND;
+ // Fill in Command Header
+ c->Header.ReplyQueue = 0; // unused in simple mode
+ if( buff != NULL) // buffer to fill
+ {
+ c->Header.SGList = 1;
+ c->Header.SGTotal= 1;
+ } else // no buffers to fill
+ {
+ c->Header.SGList = 0;
+ c->Header.SGTotal= 0;
+ }
+ c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag
+ // Fill in Request block
+ switch(cmd)
+ {
+ case CISS_INQUIRY:
+ /* If the logical unit number is 0 then, this is going
+ to controller so It's a physical command
+ mode = 0 target = 0.
+ So we have nothing to write.
+ Otherwise
+ mode = 1 target = LUNID
+ */
+ if(use_unit_num != 0)
+ {
+ c->Header.LUN.LogDev.VolId=
+ hba[ctlr]->drv[log_unit].LunID;
+ c->Header.LUN.LogDev.Mode = 1;
+ }
+ if(page_code != 0)
+ {
+ c->Request.CDB[1] = 0x01;
+ c->Request.CDB[2] = page_code;
+ }
+ c->Request.CDBLen = 6;
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ; // Read
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] = CISS_INQUIRY;
+ c->Request.CDB[4] = size & 0xFF;
+ break;
+ case CISS_REPORT_LOG:
+ /* Talking to controller so It's a physical command
+ mode = 00 target = 0.
+ So we have nothing to write.
+ */
+ c->Request.CDBLen = 12;
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ; // Read
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] = CISS_REPORT_LOG;
+ c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ c->Request.CDB[9] = size & 0xFF;
+ break;
+ case CCISS_READ_CAPACITY:
+ c->Header.LUN.LogDev.VolId=
+ hba[ctlr]->drv[log_unit].LunID;
+ c->Header.LUN.LogDev.Mode = 1;
+ c->Request.CDBLen = 10;
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ; // Read
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] = CCISS_READ_CAPACITY;
+ break;
+ default:
+ printk(KERN_WARNING
+ "cciss: Unknown Command 0x%c sent attempted\n", cmd);
+ cmd_free(h, c, 1);
+ return(IO_ERROR);
+ };
+
+ // Fill in the scatter gather information
+ if (size > 0 )
+ {
+ buff_dma_handle.val = (__u64) pci_map_single( h->pdev,
+ buff, size, PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
+ c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
+ c->SG[0].Len = size;
+ c->SG[0].Ext = 0; // we are not chaining
+ }
+
+ /* Put the request on the tail of the queue and send it */
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ start_io(h);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+ /* wait for completion */
+ while(c->cmd_type != CMD_IOCTL_DONE)
+ schedule_timeout(1);
+ /* unlock the buffers from DMA */
+ pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+ size, PCI_DMA_BIDIRECTIONAL);
+
+ if(c->err_info->CommandStatus != 0)
+ { /* an error has occurred */
+ switch(c->err_info->CommandStatus)
+ {
+ case CMD_TARGET_STATUS:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ " completed with errors\n", c);
+ if( c->err_info->ScsiStatus)
+ {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ c,
+ c->err_info->ScsiStatus);
+ }
+
+ break;
+ case CMD_DATA_UNDERRUN:
+ case CMD_DATA_OVERRUN:
+ /* expected for inquire and report lun commands */
+ break;
+ case CMD_INVALID:
+ printk(KERN_WARNING "cciss: Cmd %p is "
+ "reported invalid\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "protocol error \n", c);
+ return_status = IO_ERROR;
+ break;
+case CMD_HARDWARE_ERR:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ " hardware error\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ "connection lost\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cmd %p was "
+ "aborted\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cmd %p reports "
+ "abort failed\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING "cciss: cmd %p aborted "
+ "do to an unsolicited abort\n", c);
+ return_status = IO_ERROR;
+
+
+ break;
+ default:
+ printk(KERN_WARNING "cciss: cmd %p returned "
+ "unknown status %x\n", c,
+ c->err_info->CommandStatus);
+ return_status = IO_ERROR;
+ }
+ }
+ cmd_free(h, c, 0);
+ return(return_status);
+}
+static int register_new_disk(kdev_t dev, int ctlr)
+{
+ struct gendisk *gdev = &(hba[ctlr]->gendisk);
+ ctlr_info_t *h = hba[ctlr];
+ int start, max_p, i;
+ int num_luns;
+ int logvol;
+ int new_lun_found = 0;
+ int new_lun_index = 0;
+ int free_index_found = 0;
+ int free_index = 0;
+ ReportLunData_struct *ld_buff;
+ ReadCapdata_struct *size_buff;
+ InquiryData_struct *inq_buff;
+ int return_code;
+ int listlength = 0;
+ __u32 lunid = 0;
+ unsigned int block_size;
+ unsigned int total_size;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ /* if we have no space in our disk array left to add anything */
+ if( h->num_luns >= CISS_MAX_LUN)
+ return -EINVAL;
+
+ ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+ if (ld_buff == NULL)
+ {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return -1;
+ }
+ memset(ld_buff, 0, sizeof(ReportLunData_struct));
+ size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL)
+ {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ return -1;
+ }
+ inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL)
+ {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ kfree(size_buff);
+ return -1;
+ }
+
+ return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+ sizeof(ReportLunData_struct), 0, 0, 0 );
+
+ if( return_code == IO_OK)
+ {
+
+ // printk("LUN Data\n--------------------------\n");
+
+ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
+ listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+ } else /* reading number of logical volumes failed */
+ {
+ printk(KERN_WARNING "cciss: report logical volume"
+ " command failed\n");
+ listlength = 0;
+ return -1;
+ }
+ num_luns = listlength / 8; // 8 bytes pre entry
+ if (num_luns > CISS_MAX_LUN)
+ {
+ num_luns = CISS_MAX_LUN;
+ }
+#ifdef CCISS_DEBUG
+ printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+ ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+ ld_buff->LUNListLength[3], num_luns);
+#endif
+ for(i=0; i< num_luns; i++)
+ {
+ int j;
+ int lunID_found = 0;
+
+ lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+ lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+ /* check to see if this is a new lun */
+ for(j=0; j <= h->highest_lun; j++)
+ {
+#ifdef CCISS_DEBUG
+ printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
+ lunid);
+#endif /* CCISS_DEBUG */
+ if (h->drv[j].LunID == lunid)
+ {
+ lunID_found = 1;
+ break;
+ }
+
+ }
+ if( lunID_found == 1)
+ continue;
+ else
+ { /* It is the new lun we have been looking for */
+#ifdef CCISS_DEBUG
+ printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+ new_lun_index = i;
+ new_lun_found = 1;
+ break;
+ }
+ }
+ if (!new_lun_found)
+ {
+ printk(KERN_WARNING "cciss: New Logical Volume not found\n");
+ return -1;
+ }
+ /* Now find the free index */
+ for(i=0; i <CISS_MAX_LUN; i++)
+ {
+#ifdef CCISS_DEBUG
+ printk("Checking Index %d\n", i);
+#endif /* CCISS_DEBUG */
+ if(hba[ctlr]->drv[i].LunID == 0)
+ {
+#ifdef CCISS_DEBUG
+ printk("free index found at %d\n", i);
+#endif /* CCISS_DEBUG */
+ free_index_found = 1;
+ free_index = i;
+ break;
+ }
+ }
+ if (!free_index_found)
+ {
+ printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
+ return -1;
+ }
+
+ logvol = free_index;
+ hba[ctlr]->drv[logvol].LunID = lunid;
+ /* there could be gaps in lun numbers, track hightest */
+ if(hba[ctlr]->highest_lun < lunid)
+ hba[ctlr]->highest_lun = logvol;
+
+ memset(size_buff, 0, sizeof(ReadCapdata_struct));
+ return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
+ sizeof( ReadCapdata_struct), 1, logvol, 0 );
+ if (return_code == IO_OK)
+ {
+ total_size = (0xff &
+ (unsigned int)(size_buff->total_size[0])) << 24;
+ total_size |= (0xff &
+ (unsigned int)(size_buff->total_size[1])) << 16;
+ total_size |= (0xff &
+ (unsigned int)(size_buff->total_size[2])) << 8;
+ total_size |= (0xff & (unsigned int)
+ (size_buff->total_size[3]));
+ total_size++; // command returns highest block address
+
+ block_size = (0xff &
+ (unsigned int)(size_buff->block_size[0])) << 24;
+ block_size |= (0xff &
+ (unsigned int)(size_buff->block_size[1])) << 16;
+ block_size |= (0xff &
+ (unsigned int)(size_buff->block_size[2])) << 8;
+ block_size |= (0xff &
+ (unsigned int)(size_buff->block_size[3]));
+ } else /* read capacity command failed */
+ {
+ printk(KERN_WARNING "cciss: read capacity failed\n");
+ total_size = 0;
+ block_size = BLOCK_SIZE;
+ }
+ printk(KERN_INFO " blocks= %d block_size= %d\n",
+ total_size, block_size);
+ /* Execute the command to read the disk geometry */
+ memset(inq_buff, 0, sizeof(InquiryData_struct));
+ return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+ sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+ if (return_code == IO_OK)
+ {
+ if(inq_buff->data_byte[8] == 0xFF)
+ {
+ printk(KERN_WARNING "cciss: reading geometry failed, "
+ "volume does not support reading geometry\n");
+
+ hba[ctlr]->drv[logvol].block_size = block_size;
+ hba[ctlr]->drv[logvol].nr_blocks = total_size;
+ hba[ctlr]->drv[logvol].heads = 255;
+ hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track
+ hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+ } else
+ {
+
+ hba[ctlr]->drv[logvol].block_size = block_size;
+ hba[ctlr]->drv[logvol].nr_blocks = total_size;
+ hba[ctlr]->drv[logvol].heads =
+ inq_buff->data_byte[6];
+ hba[ctlr]->drv[logvol].sectors =
+ inq_buff->data_byte[7];
+ hba[ctlr]->drv[logvol].cylinders =
+ (inq_buff->data_byte[4] & 0xff) << 8;
+ hba[ctlr]->drv[logvol].cylinders +=
+ inq_buff->data_byte[5];
+ }
+ }
+ else /* Get geometry failed */
+ {
+
+ printk(KERN_WARNING "cciss: reading geometry failed, "
+ "continuing with default geometry\n");
+
+ hba[ctlr]->drv[logvol].block_size = block_size;
+ hba[ctlr]->drv[logvol].nr_blocks = total_size;
+ hba[ctlr]->drv[logvol].heads = 255;
+ hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track
+ hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+ }
+ printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n",
+ hba[ctlr]->drv[logvol].heads,
+ hba[ctlr]->drv[logvol].sectors,
+ hba[ctlr]->drv[logvol].cylinders);
+ hba[ctlr]->drv[logvol].usage_count = 0;
+ max_p = 1 << gdev->minor_shift;
+ start = logvol<< gdev->minor_shift;
+
+ for(i=max_p-1; i>=0; i--) {
+ int minor = start+i;
+ kdev_t kdev = mk_kdev(MAJOR_NR + ctlr, minor);
+ invalidate_device(kdev, 1);
+ gdev->part[minor].start_sect = 0;
+ gdev->part[minor].nr_sects = 0;
+
+ /* reset the blocksize so we can read the partition table */
+ blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+ }
+
+ ++hba[ctlr]->num_luns;
+ gdev->nr_real = hba[ctlr]->highest_lun + 1;
+ /* setup partitions per disk */
+ grok_partitions(dev, hba[ctlr]->drv[logvol].nr_blocks);
+
+ kfree(ld_buff);
+ kfree(size_buff);
+ kfree(inq_buff);
+ return (logvol);
+}
/*
* Wait polling for a command to complete.
* The memory mapped FIFO is polled for the completion.
@@ -959,6 +1489,15 @@ static int sendcmd(
c->Request.Timeout = 0; // Don't time out
c->Request.CDB[0] = CCISS_READ_CAPACITY;
break;
+ case CCISS_CACHE_FLUSH:
+ c->Request.CDBLen = 12;
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_WRITE; // No data
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] = BMIC_WRITE; // BMIC Passthru
+ c->Request.CDB[6] = BMIC_CACHE_FLUSH;
+ break;
default:
printk(KERN_WARNING
"cciss: Unknown Command 0x%c sent attempted\n",
@@ -1169,17 +1708,32 @@ static inline void complete_command( CommandList_struct *cmd, int timeout)
{ /* an error has occurred */
switch(cmd->err_info->CommandStatus)
{
+ unsigned char sense_key;
case CMD_TARGET_STATUS:
- printk(KERN_WARNING "cciss: cmd %p has "
- " completed with errors\n", cmd);
- if( cmd->err_info->ScsiStatus)
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status = %x\n",
- cmd,
- cmd->err_info->ScsiStatus);
- }
-
+ status = 0;
+
+ if( cmd->err_info->ScsiStatus == 0x02)
+ {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has CHECK CONDITION "
+ " byte 2 = 0x%x\n", cmd,
+ cmd->err_info->SenseInfo[2]
+ );
+ /* check the sense key */
+ sense_key = 0xf &
+ cmd->err_info->SenseInfo[2];
+ /* no status or recovered error */
+ if((sense_key == 0x0) ||
+ (sense_key == 0x1))
+ {
+ status = 1;
+ }
+ } else
+ {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status 0x%x\n",
+ cmd, cmd->err_info->ScsiStatus);
+ }
break;
case CMD_DATA_UNDERRUN:
printk(KERN_WARNING "cciss: cmd %p has"
@@ -1460,6 +2014,15 @@ static void print_cfg_table( CfgTable_struct *tb)
}
#endif /* CCISS_DEBUG */
+static void release_io_mem(ctlr_info_t *c)
+{
+ /* if IO mem was not protected do nothing */
+ if( c->io_mem_addr == 0)
+ return;
+ release_region(c->io_mem_addr, c->io_mem_length);
+ c->io_mem_addr = 0;
+ c->io_mem_length = 0;
+}
static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
{
ushort vendor_id, device_id, command;
@@ -1489,17 +2052,49 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
printk(KERN_ERR "cciss: Unable to set DMA mask\n");
return(-1);
}
-
+
(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
(void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
(void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
&cache_line_size);
(void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
&latency_timer);
-
(void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID,
&board_id);
+ /* check to see if controller has been disabled */
+ if(!(command & 0x02))
+ {
+ printk(KERN_WARNING "cciss: controller appears to be disabled\n");
+ return(-1);
+ }
+
+ /* search for our IO range so we can protect it */
+ for(i=0; i<6; i++)
+ {
+ /* is this an IO range */
+ if( pdev->resource[i].flags & 0x01 )
+ {
+ c->io_mem_addr = pdev->resource[i].start;
+ c->io_mem_length = pdev->resource[i].end -
+ pdev->resource[i].start +1;
+#ifdef CCISS_DEBUG
+ printk("IO value found base_addr[%d] %lx %lx\n", i,
+ c->io_mem_addr, c->io_mem_length);
+#endif /* CCISS_DEBUG */
+ /* register the IO range */
+ if(!request_region( c->io_mem_addr,
+ c->io_mem_length, "cciss"))
+ {
+ printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
+ c->io_mem_addr, c->io_mem_length);
+ c->io_mem_addr= 0;
+ c->io_mem_length = 0;
+ }
+ break;
+ }
+ }
+
#ifdef CCISS_DEBUG
printk("vendor_id = %x\n", vendor_id);
printk("device_id = %x\n", device_id);
@@ -1520,7 +2115,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
* table
*/
- c->paddr = addr[0] & 0xfffffff0; /* remove the addressing mode bits */
+ c->paddr = addr[0] ; /* addressing mode bits already removed */
#ifdef CCISS_DEBUG
printk("address 0 = %x\n", c->paddr);
#endif /* CCISS_DEBUG */
@@ -1617,7 +2212,7 @@ static void cciss_getgeometry(int cntl_num)
int return_code;
int i;
int listlength = 0;
- int lunid = 0;
+ __u32 lunid = 0;
int block_size;
int total_size;
@@ -1689,14 +2284,19 @@ static void cciss_getgeometry(int cntl_num)
ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
ld_buff->LUNListLength[3], hba[cntl_num]->num_luns);
#endif /* CCISS_DEBUG */
- for(i=0; i< hba[cntl_num]->num_luns ; i++)
+
+ hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
+ for(i=0; i< hba[cntl_num]->num_luns; i++)
{
+
lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
hba[cntl_num]->drv[i].LunID = lunid;
+
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i,
ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2],
@@ -1729,7 +2329,8 @@ static void cciss_getgeometry(int cntl_num)
} else /* read capacity command failed */
{
printk(KERN_WARNING "cciss: read capacity failed\n");
- total_size = block_size = 0;
+ total_size = 0;
+ block_size = BLOCK_SIZE;
}
printk(KERN_INFO " blocks= %d block_size= %d\n",
total_size, block_size);
@@ -1781,6 +2382,7 @@ static void cciss_getgeometry(int cntl_num)
}
kfree(ld_buff);
kfree(size_buff);
+ kfree(inq_buff);
}
/* Function to find the first free pointer into our hba[] array */
@@ -1834,6 +2436,7 @@ static int __init cciss_init_one(struct pci_dev *pdev,
memset(hba[i], 0, sizeof(ctlr_info_t));
if (cciss_pci_init(hba[i], pdev) != 0)
{
+ release_io_mem(hba[i]);
free_hba(i);
return (-1);
}
@@ -1856,6 +2459,7 @@ static int __init cciss_init_one(struct pci_dev *pdev,
{
printk(KERN_ERR "cciss: Unable to get major number "
"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
+ release_io_mem(hba[i]);
free_hba(i);
return(-1);
}
@@ -1867,6 +2471,7 @@ static int __init cciss_init_one(struct pci_dev *pdev,
printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
hba[i]->intr, hba[i]->devname);
unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
+ release_io_mem(hba[i]);
free_hba(i);
return(-1);
}
@@ -1895,6 +2500,7 @@ static int __init cciss_init_one(struct pci_dev *pdev,
hba[i]->errinfo_pool_dhandle);
free_irq(hba[i]->intr, hba[i]);
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+ release_io_mem(hba[i]);
free_hba(i);
printk( KERN_ERR "cciss: out of memory");
return(-1);
@@ -1944,7 +2550,7 @@ static int __init cciss_init_one(struct pci_dev *pdev,
hba[i]->gendisk.minor_shift = NWD_SHIFT;
hba[i]->gendisk.part = hba[i]->hd;
hba[i]->gendisk.sizes = hba[i]->sizes;
- hba[i]->gendisk.nr_real = hba[i]->num_luns;
+ hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;
/* Get on the disk list */
add_gendisk(&(hba[i]->gendisk));
@@ -1965,6 +2571,8 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
{
ctlr_info_t *tmp_ptr;
int i;
+ char flush_buf[4];
+ int return_code;
if (pci_get_drvdata(pdev) == NULL)
{
@@ -1979,8 +2587,16 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
"already be removed \n");
return;
}
- /* Turn board interrupts off */
- hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+ /* Turn board interrupts off and send the flush cache command */
+ /* sendcmd will turn off interrupt, and send the flush...
+ * To write all data in the battery backed cache to disks */
+ memset(flush_buf, 0, 4);
+ return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL);
+ if(return_code != IO_OK)
+ {
+ printk(KERN_WARNING "Error Flushing cache on controller %d\n",
+ i);
+ }
free_irq(hba[i]->intr, hba[i]);
pci_set_drvdata(pdev, NULL);
iounmap((void*)hba[i]->vaddr);
@@ -1996,6 +2612,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
kfree(hba[i]->cmd_pool_bits);
+ release_io_mem(hba[i]);
free_hba(i);
}
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index c6eb34da2..9c8c86aef 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -46,6 +46,8 @@ struct ctlr_info
__u32 board_id;
ulong vaddr;
__u32 paddr;
+ unsigned long io_mem_addr;
+ unsigned long io_mem_length;
CfgTable_struct *cfgtable;
int intr;
@@ -53,6 +55,7 @@ struct ctlr_info
int commands_outstanding;
int max_outstanding; /* Debug */
int num_luns;
+ int highest_lun;
int usage_count; /* number of opens all all minor devices */
// information about each logical volume
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index 6ba126d3d..cf9c9fd36 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -124,6 +124,12 @@ typedef struct _ReadCapdata_struct
#define CCISS_READ 0x28 // Read(10)
#define CCISS_WRITE 0x2a // Write(10)
+// BMIC commands
+#define BMIC_READ 0x26
+#define BMIC_WRITE 0x27
+#define BMIC_CACHE_FLUSH 0xc2
+#define CCISS_CACHE_FLUSH 0x01 //C2 was already being used by CCISS
+
//Command List Structure
typedef union _SCSI3Addr_struct {
struct {
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 142b4a8e8..e59352d85 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -186,7 +186,8 @@ void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
* full 4GB zone, so we have to resort to low memory for any bounces.
* ISA has its own < 16MB zone.
*/
- if (dma_addr == BLK_BOUNCE_ISA) {
+ if (bounce_pfn < blk_max_low_pfn) {
+ BUG_ON(dma_addr < BLK_BOUNCE_ISA);
init_emergency_isa_pool();
q->bounce_gfp = GFP_NOIO | GFP_DMA;
} else
@@ -302,8 +303,8 @@ void blk_queue_assign_lock(request_queue_t *q, spinlock_t *lock)
static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
"REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
"REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK",
- "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE",
- "REQ_SPECIAL" };
+ "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
+ "REQ_SENSE", "REQ_SPECIAL" };
void blk_dump_rq_flags(struct request *rq, char *msg)
{
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 881ef1555..37bb44587 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -422,7 +422,7 @@ static void __init ps2esdi_geninit(void)
blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128);
for (i = 0; i < ps2esdi_drives; i++) {
- register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
+ register_disk(&ps2esdi_gendisk,mk_kdev(MAJOR_NR,i<<6),1<<6,
&ps2esdi_fops,
ps2esdi_info[i].head * ps2esdi_info[i].sect *
ps2esdi_info[i].cyl);
@@ -466,7 +466,7 @@ static void do_ps2esdi_request(request_queue_t * q)
#if 0
printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld, buffer: %p\n",
DEVICE_NAME,
- CURRENT_DEV, MINOR(CURRENT->rq_dev),
+ CURRENT_DEV, minor(CURRENT->rq_dev),
CURRENT->cmd, CURRENT->sector,
CURRENT->current_nr_sectors, CURRENT->buffer);
#endif
@@ -481,12 +481,12 @@ static void do_ps2esdi_request(request_queue_t * q)
} /* check for above 16Mb dmas */
else if ((CURRENT_DEV < ps2esdi_drives) &&
(CURRENT->sector + CURRENT->current_nr_sectors <=
- ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects) &&
+ ps2esdi[minor(CURRENT->rq_dev)].nr_sects) &&
CURRENT->flags & REQ_CMD) {
#if 0
printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld\n",
DEVICE_NAME,
- CURRENT_DEV, MINOR(CURRENT->rq_dev),
+ CURRENT_DEV, minor(CURRENT->rq_dev),
CURRENT->cmd, CURRENT->sector,
CURRENT->current_nr_sectors);
#endif
@@ -510,7 +510,7 @@ static void do_ps2esdi_request(request_queue_t * q)
/* is request is valid */
else {
printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,
- CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);
+ CURRENT->sector, ps2esdi[minor(CURRENT->rq_dev)].nr_sects);
end_request(FAIL);
}
@@ -849,7 +849,7 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
switch (int_ret_code & 0x0f) {
case INT_TRANSFER_REQ:
ps2esdi_prep_dma(CURRENT->buffer, CURRENT->current_nr_sectors,
- (CURRENT->cmd == READ)
+ (rq_data_dir(CURRENT) == READ)
? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER
: MCA_DMA_MODE_16 | MCA_DMA_MODE_READ);
outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 4c0acc344..f71e3fa09 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -367,7 +367,7 @@ static ssize_t lp_write(struct file * file, const char * buf,
= lp_negotiate (port,
lp_table[minor].best_mode);
- } else if (current->need_resched)
+ } else if (need_resched())
schedule ();
if (count) {
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 8b1f582a7..90e1e9956 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -381,8 +381,7 @@ static inline size_t read_zero_pagealigned(char * buf, size_t size)
unsigned long unwritten = clear_user(buf, PAGE_SIZE);
if (unwritten)
return size + unwritten - PAGE_SIZE;
- if (current->need_resched)
- schedule();
+ cond_resched();
buf += PAGE_SIZE;
size -= PAGE_SIZE;
} while (size);
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index 54f2f46d9..b8f583ca3 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -68,11 +68,9 @@ static unsigned long flags;
static void PaceMsaAccess(unsigned short usDspBaseIO)
{
- if(current->need_resched)
- schedule();
+ cond_resched();
udelay(100);
- if(current->need_resched)
- schedule();
+ cond_resched();
}
unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 6e976f28c..bdebe0aee 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -170,9 +170,7 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
break;
}
- if (current->need_resched) {
- schedule ();
- }
+ cond_resched();
}
kfree (kbuffer);
@@ -242,9 +240,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
break;
}
- if (current->need_resched) {
- schedule ();
- }
+ cond_resched();
}
kfree (kbuffer);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index ddd026519..656a38b22 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1313,7 +1313,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
/*
* Check if we need to break out or reschedule....
*/
- if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) {
+ if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {
if (signal_pending(current)) {
if (ret == 0)
ret = -ERESTARTSYS;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index cea100d98..9fdd57eff 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -712,8 +712,7 @@ static inline ssize_t do_tty_write(
ret = -ERESTARTSYS;
if (signal_pending(current))
break;
- if (current->need_resched)
- schedule();
+ cond_resched();
}
}
if (written) {
diff --git a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c
index 5b4861915..ddcd791f4 100644
--- a/drivers/hotplug/cpqphp_core.c
+++ b/drivers/hotplug/cpqphp_core.c
@@ -404,6 +404,10 @@ static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *
result = pci_hp_register (new_slot->hotplug_slot);
if (result) {
err ("pci_hp_register failed with error %d\n", result);
+ kfree (new_slot->hotplug_slot->info);
+ kfree (new_slot->hotplug_slot->name);
+ kfree (new_slot->hotplug_slot);
+ kfree (new_slot);
return result;
}
@@ -429,6 +433,8 @@ static int ctrl_slot_cleanup (struct controller * ctrl)
while (old_slot) {
next_slot = old_slot->next;
pci_hp_deregister (old_slot->hotplug_slot);
+ kfree(old_slot->hotplug_slot->info);
+ kfree(old_slot->hotplug_slot->name);
kfree(old_slot->hotplug_slot);
kfree(old_slot);
old_slot = next_slot;
diff --git a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c
index 7e968759a..a576ffe4c 100644
--- a/drivers/i2c/i2c-algo-bit.c
+++ b/drivers/i2c/i2c-algo-bit.c
@@ -50,7 +50,7 @@
/* might not like this, as they have an internal timeout of some mils */
/*
#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
- if (need_resched) schedule();
+ cond_resched();
*/
@@ -120,8 +120,7 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
if (start+adap->timeout <= jiffies) {
return -ETIMEDOUT;
}
- if (current->need_resched)
- schedule();
+ cond_resched();
}
DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
#ifdef SLO_IO
diff --git a/drivers/i2c/i2c-algo-ite.c b/drivers/i2c/i2c-algo-ite.c
index 59170078f..919a287fa 100644
--- a/drivers/i2c/i2c-algo-ite.c
+++ b/drivers/i2c/i2c-algo-ite.c
@@ -67,7 +67,7 @@
/* might not like this, as they have an internal timeout of some mils */
/*
#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
- if (need_resched) schedule();
+ cond_resched();
*/
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index cbc80707b..baf50487d 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -123,12 +123,10 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u
*/
static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
- if (rq_data_dir(rq) == READ)
- goto good_command;
- if (rq_data_dir(rq) == WRITE)
+ if (rq->flags & REQ_CMD)
goto good_command;
- printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
+ blk_dump_rq_flags(rq, "do_rw_disk, bad command");
ide_end_request(0, HWGROUP(drive));
return ide_stopped;
@@ -179,8 +177,10 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
ide_task_t args;
+ int sectors;
task_ioreg_t command = get_command(drive, rq_data_dir(rq));
+
unsigned int track = (block / drive->sect);
unsigned int sect = (block % drive->sect) + 1;
unsigned int head = (track % drive->head);
@@ -189,7 +189,16 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi
memset(&taskfile, 0, sizeof(task_struct_t));
memset(&hobfile, 0, sizeof(hob_struct_t));
- taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+ sectors = rq->nr_sectors;
+ if (sectors == 256)
+ sectors = 0;
+ if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+ sectors = drive->mult_count;
+ if (sectors > rq->current_nr_sectors)
+ sectors = rq->current_nr_sectors;
+ }
+
+ taskfile.sector_count = sectors;
taskfile.sector_number = sect;
taskfile.low_cylinder = cyl;
taskfile.high_cylinder = (cyl>>8);
@@ -225,13 +234,23 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
ide_task_t args;
+ int sectors;
task_ioreg_t command = get_command(drive, rq_data_dir(rq));
+ sectors = rq->nr_sectors;
+ if (sectors == 256)
+ sectors = 0;
+ if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+ sectors = drive->mult_count;
+ if (sectors > rq->current_nr_sectors)
+ sectors = rq->current_nr_sectors;
+ }
+
memset(&taskfile, 0, sizeof(task_struct_t));
memset(&hobfile, 0, sizeof(hob_struct_t));
- taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+ taskfile.sector_count = sectors;
taskfile.sector_number = block;
taskfile.low_cylinder = (block>>=8);
taskfile.high_cylinder = (block>>=8);
@@ -273,14 +292,24 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
ide_task_t args;
+ int sectors;
task_ioreg_t command = get_command(drive, rq_data_dir(rq));
memset(&taskfile, 0, sizeof(task_struct_t));
memset(&hobfile, 0, sizeof(hob_struct_t));
- taskfile.sector_count = rq->nr_sectors;
- hobfile.sector_count = (rq->nr_sectors>>8);
+ sectors = rq->nr_sectors;
+ if (sectors == 256)
+ sectors = 0;
+ if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+ sectors = drive->mult_count;
+ if (sectors > rq->current_nr_sectors)
+ sectors = rq->current_nr_sectors;
+ }
+
+ taskfile.sector_count = sectors;
+ hobfile.sector_count = sectors >> 8;
if (rq->nr_sectors == 65536) {
taskfile.sector_count = 0x00;
@@ -652,7 +681,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = drive->mult_req;
taskfile.command = WIN_SETMULT;
- do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+ do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
}
} else if (s->all) {
int special = s->all;
@@ -789,23 +818,12 @@ static ide_proc_entry_t idedisk_proc[] = {
#endif /* CONFIG_PROC_FS */
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
static int set_multcount(ide_drive_t *drive, int arg)
{
-#if 1
- struct hd_drive_task_hdr taskfile;
- struct hd_drive_hob_hdr hobfile;
-
- if (drive->special.b.set_multmode)
- return -EBUSY;
-
- memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
- memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
- taskfile.sector_count = drive->mult_req;
- taskfile.command = WIN_SETMULT;
- drive->mult_req = arg;
- drive->special.b.set_multmode = 1;
- ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else
struct request rq;
if (drive->special.b.set_multmode)
@@ -814,7 +832,6 @@ static int set_multcount(ide_drive_t *drive, int arg)
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif
return (drive->mult_count == arg) ? 0 : -EIO;
}
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 07e5e8260..7a66d6168 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -688,7 +688,7 @@ static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
/* Why does this happen? */
if (!rq)
return;
- if (rq->flags & IDEFLOPPY_RQ) {
+ if (!(rq->flags & IDEFLOPPY_RQ)) {
ide_end_request (uptodate, hwgroup);
return;
}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 4828e49f9..c591729ac 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -721,7 +721,7 @@ typedef struct idetape_packet_command_s {
int request_transfer; /* Bytes to transfer */
int actually_transferred; /* Bytes actually transferred */
int buffer_size; /* Size of our data buffer */
- struct buffer_head *bh;
+ struct bio *bio;
char *b_data;
int b_count;
byte *buffer; /* Data buffer */
@@ -805,7 +805,7 @@ typedef struct {
*/
typedef struct idetape_stage_s {
struct request rq; /* The corresponding request */
- struct buffer_head *bh; /* The data buffers */
+ struct bio *bio; /* The data buffers */
struct idetape_stage_s *next; /* Pointer to the next stage */
os_aux_t *aux; /* OnStream aux ptr */
} idetape_stage_t;
@@ -929,7 +929,7 @@ typedef struct {
int stage_size; /* Data buffer size (chosen based on the tape's recommendation */
idetape_stage_t *merge_stage;
int merge_stage_size;
- struct buffer_head *bh;
+ struct bio *bio;
char *b_data;
int b_count;
@@ -1013,7 +1013,7 @@ typedef struct {
* Measures number of frames:
*
* 1. written/read to/from the driver pipeline (pipeline_head).
- * 2. written/read to/from the tape buffers (buffer_head).
+ * 2. written/read to/from the tape buffers (bio).
* 3. written/read by the tape to/from the media (tape_head).
*/
int pipeline_head;
@@ -1493,52 +1493,52 @@ static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
{
- struct buffer_head *bh = pc->bh;
+ struct bio *bio = pc->bio;
int count;
while (bcount) {
#if IDETAPE_DEBUG_BUGS
- if (bh == NULL) {
- printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+ if (bio == NULL) {
+ printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n");
idetape_discard_data (drive, bcount);
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
- count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
- atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+ count = IDE_MIN (bio->bi_size - pc->b_count, bcount);
+ atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
bcount -= count;
- atomic_add(count, &bh->b_count);
- if (atomic_read(&bh->b_count) == bh->b_size) {
- bh = bh->b_reqnext;
- if (bh)
- atomic_set(&bh->b_count, 0);
+ pc->b_count += bio->bi_size;
+ if (pc->b_count == bio->bi_size) {
+ bio = bio->bi_next;
+ if (bio)
+ pc->b_count = 0;
}
}
- pc->bh = bh;
+ pc->bio = bio;
}
static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
{
- struct buffer_head *bh = pc->bh;
+ struct bio *bio = pc->bio;
int count;
while (bcount) {
#if IDETAPE_DEBUG_BUGS
- if (bh == NULL) {
- printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+ if (bio == NULL) {
+ printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n");
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
count = IDE_MIN (pc->b_count, bcount);
- atapi_output_bytes (drive, pc->b_data, count);
+ atapi_output_bytes (drive, bio_data(bio), count);
bcount -= count;
pc->b_data += count;
pc->b_count -= count;
if (!pc->b_count) {
- pc->bh = bh = bh->b_reqnext;
- if (bh) {
- pc->b_data = bh->b_data;
- pc->b_count = atomic_read(&bh->b_count);
+ pc->bio = bio = bio->bi_next;
+ if (bio) {
+ pc->b_data = bio_data(bio);
+ pc->b_count = bio->bi_size;
}
}
}
@@ -1547,25 +1547,25 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign
#ifdef CONFIG_BLK_DEV_IDEDMA
static void idetape_update_buffers (idetape_pc_t *pc)
{
- struct buffer_head *bh = pc->bh;
+ struct bio *bio = pc->bio;
int count, bcount = pc->actually_transferred;
if (test_bit (PC_WRITING, &pc->flags))
return;
while (bcount) {
#if IDETAPE_DEBUG_BUGS
- if (bh == NULL) {
- printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+ if (bio == NULL) {
+ printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n");
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
- count = IDE_MIN (bh->b_size, bcount);
- atomic_set(&bh->b_count, count);
- if (atomic_read(&bh->b_count) == bh->b_size)
- bh = bh->b_reqnext;
+ count = IDE_MIN (bio->bi_size, bcount);
+ pc->b_count = count;
+ if (pc->b_count == bio->bi_size)
+ bio = bio->bi_next;
bcount -= count;
}
- pc->bh = bh;
+ pc->bio = bio;
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -1625,7 +1625,7 @@ static void idetape_init_pc (idetape_pc_t *pc)
pc->request_transfer = 0;
pc->buffer = pc->pc_buffer;
pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
- pc->bh = NULL;
+ pc->bio = NULL;
pc->b_data = NULL;
}
@@ -1706,10 +1706,10 @@ static void idetape_abort_pipeline (ide_drive_t *drive)
printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
#endif
while (stage) {
- if (stage->rq.cmd == IDETAPE_WRITE_RQ)
- stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
- else if (stage->rq.cmd == IDETAPE_READ_RQ)
- stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
+ if (stage->rq.flags == IDETAPE_WRITE_RQ)
+ stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ;
+ else if (stage->rq.flags == IDETAPE_READ_RQ)
+ stage->rq.flags = IDETAPE_ABORTED_READ_RQ;
stage = stage->next;
}
}
@@ -1735,7 +1735,7 @@ static void idetape_active_next_stage (ide_drive_t *drive)
#endif /* IDETAPE_DEBUG_BUGS */
rq->buffer = NULL;
- rq->bh = stage->bh;
+ rq->bio = stage->bio;
tape->active_data_request = rq;
tape->active_stage = stage;
tape->next_stage = stage->next;
@@ -1769,21 +1769,21 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
*/
static void __idetape_kfree_stage (idetape_stage_t *stage)
{
- struct buffer_head *prev_bh, *bh = stage->bh;
+ struct bio *prev_bio, *bio = stage->bio;
int size;
- while (bh != NULL) {
- if (bh->b_data != NULL) {
- size = (int) bh->b_size;
+ while (bio != NULL) {
+ if (bio_data(bio) != NULL) {
+ size = (int) bio->bi_size;
while (size > 0) {
- free_page ((unsigned long) bh->b_data);
+ free_page ((unsigned long) bio_data(bio));
size -= PAGE_SIZE;
- bh->b_data += PAGE_SIZE;
+ bio->bi_size += PAGE_SIZE;
}
}
- prev_bh = bh;
- bh = bh->b_reqnext;
- kfree (prev_bh);
+ prev_bio = bio;
+ bio = bio->bi_next;
+ kfree (prev_bio);
}
kfree (stage);
}
@@ -1868,13 +1868,13 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
tape->active_stage = NULL;
tape->active_data_request = NULL;
tape->nr_pending_stages--;
- if (rq->cmd == IDETAPE_WRITE_RQ) {
+ if (rq->flags == IDETAPE_WRITE_RQ) {
#if ONSTREAM_DEBUG
if (tape->debug_level >= 2) {
if (tape->onstream) {
stage = tape->first_stage;
aux = stage->aux;
- p = stage->bh->b_data;
+ p = bio_data(stage->bio);
if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
}
@@ -1908,7 +1908,7 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
complete(tape->waiting);
}
}
- } else if (rq->cmd == IDETAPE_READ_RQ) {
+ } else if (rq->flags == IDETAPE_READ_RQ) {
if (error == IDETAPE_ERROR_EOD) {
set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
idetape_abort_pipeline(drive);
@@ -1984,7 +1984,7 @@ static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct re
{
ide_init_drive_cmd (rq);
rq->buffer = (char *) pc;
- rq->cmd = IDETAPE_PC_RQ1;
+ rq->flags = IDETAPE_PC_RQ1;
(void) ide_do_drive_cmd (drive, rq, ide_preempt);
}
@@ -2164,12 +2164,12 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
}
}
if (test_bit (PC_WRITING, &pc->flags)) {
- if (pc->bh != NULL)
+ if (pc->bio != NULL)
idetape_output_buffers (drive, pc, bcount.all);
else
atapi_output_bytes (drive,pc->current_position,bcount.all); /* Write the current buffer */
} else {
- if (pc->bh != NULL)
+ if (pc->bio != NULL)
idetape_input_buffers (drive, pc, bcount.all);
else
atapi_input_bytes (drive,pc->current_position,bcount.all); /* Read the current buffer */
@@ -2523,21 +2523,22 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
return ide_stopped;
}
-static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
{
- struct buffer_head *p = bh;
+ struct bio *p = bio;
+ struct bio_vec *bv = bio_iovec(p);
idetape_init_pc (pc);
pc->c[0] = IDETAPE_READ_CMD;
put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
pc->c[1] = 1;
pc->callback = &idetape_rw_callback;
- pc->bh = bh;
- atomic_set(&bh->b_count, 0);
+ pc->bio = bio;
+ bv->bv_len = 0;
pc->buffer = NULL;
if (tape->onstream) {
while (p) {
- atomic_set(&p->b_count, 0);
- p = p->b_reqnext;
+ bv->bv_len = 0;
+ p = p->bi_next;
}
}
if (!tape->onstream) {
@@ -2553,30 +2554,31 @@ static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, uns
}
}
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
{
int size = 32768;
- struct buffer_head *p = bh;
+ struct bio *p = bio;
idetape_init_pc (pc);
pc->c[0] = IDETAPE_READ_BUFFER_CMD;
pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
pc->c[7] = size >> 8;
pc->c[8] = size & 0xff;
pc->callback = &idetape_pc_callback;
- pc->bh = bh;
- atomic_set(&bh->b_count, 0);
+ pc->bio = bio;
+ atomic_set(&bio->bi_cnt, 0);
pc->buffer = NULL;
while (p) {
- atomic_set(&p->b_count, 0);
- p = p->b_reqnext;
+ p->bi_size = 0;
+ p = p->bi_next;
}
pc->request_transfer = pc->buffer_size = size;
}
-static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
{
- struct buffer_head *p = bh;
+ struct bio *p = bio;
+ struct bio_vec *bv= bio_iovec(p);
idetape_init_pc (pc);
pc->c[0] = IDETAPE_WRITE_CMD;
put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
@@ -2585,13 +2587,13 @@ static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, un
set_bit (PC_WRITING, &pc->flags);
if (tape->onstream) {
while (p) {
- atomic_set(&p->b_count, p->b_size);
- p = p->b_reqnext;
+ bv->bv_len = p->bi_size;
+ p = p->bi_next;
}
}
- pc->bh = bh;
- pc->b_data = bh->b_data;
- pc->b_count = atomic_read(&bh->b_count);
+ pc->bio = bio;
+ pc->b_data = bio_data(bio);
+ pc->b_count = bio->bi_size;
pc->buffer = NULL;
if (!tape->onstream) {
pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
@@ -2618,16 +2620,16 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 5)
- printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+/* printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */
if (tape->debug_level >= 2)
- printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+ printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
#endif /* IDETAPE_DEBUG_LOG */
- if (!IDETAPE_RQ_CMD (rq->cmd)) {
+ if (!IDETAPE_RQ_CMD (rq->flags)) {
/*
* We do not support buffer cache originated requests.
*/
- printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
+ printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
ide_end_request (0, HWGROUP (drive)); /* Let the common code handle it */
return ide_stopped;
}
@@ -2661,7 +2663,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
*/
if (tape->onstream)
status.b.dsc = 1;
- if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
+ if (!drive->dsc_overlap && rq->flags != IDETAPE_PC_RQ2)
set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
/*
@@ -2674,7 +2676,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
*/
if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
tape->measure_insert_time = 1;
- if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+ if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
tape->req_buffer_fill = 0;
tape->writes_since_buffer_fill = 0;
tape->reads_since_buffer_fill = 0;
@@ -2688,19 +2690,19 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
calculate_speeds(drive);
if (tape->onstream && tape->max_frames &&
- ((rq->cmd == IDETAPE_WRITE_RQ &&
+ ((rq->flags == IDETAPE_WRITE_RQ &&
( tape->cur_frames == tape->max_frames ||
( tape->speed_control && tape->cur_frames > 5 &&
(tape->insert_speed > tape->max_insert_speed ||
(0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
- (rq->cmd == IDETAPE_READ_RQ &&
+ (rq->flags == IDETAPE_READ_RQ &&
( tape->cur_frames == 0 ||
( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
- rq->cmd, tape->cur_frames, tape->max_frames);
+ printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n",
+ rq->flags, tape->cur_frames, tape->max_frames);
#endif
if (tape->postpone_cnt++ < 500) {
status.b.dsc = 0;
@@ -2718,7 +2720,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
- if (rq->cmd == IDETAPE_PC_RQ2) {
+ if (rq->flags == IDETAPE_PC_RQ2) {
idetape_media_access_finished (drive);
return ide_stopped;
} else {
@@ -2729,7 +2731,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
idetape_postpone_request (drive);
return ide_stopped;
}
- switch (rq->cmd) {
+ switch (rq->flags) {
case IDETAPE_READ_RQ:
tape->buffer_head++;
#if USE_IOTRACE
@@ -2744,7 +2746,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
tape->req_buffer_fill = 1;
}
pc = idetape_next_pc_storage (drive);
- idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+ idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
break;
case IDETAPE_WRITE_RQ:
tape->buffer_head++;
@@ -2761,15 +2763,15 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
calculate_speeds(drive);
}
pc = idetape_next_pc_storage (drive);
- idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+ idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
break;
case IDETAPE_READ_BUFFER_RQ:
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage (drive);
- idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+ idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
break;
case IDETAPE_ABORTED_WRITE_RQ:
- rq->cmd = IDETAPE_WRITE_RQ;
+ rq->flags = IDETAPE_WRITE_RQ;
idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
return ide_stopped;
case IDETAPE_ABORTED_READ_RQ:
@@ -2777,12 +2779,12 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
if (tape->debug_level >= 2)
printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
#endif
- rq->cmd = IDETAPE_READ_RQ;
+ rq->flags = IDETAPE_READ_RQ;
idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
return ide_stopped;
case IDETAPE_PC_RQ1:
pc = (idetape_pc_t *) rq->buffer;
- rq->cmd = IDETAPE_PC_RQ2;
+ rq->flags = IDETAPE_PC_RQ2;
break;
case IDETAPE_PC_RQ2:
idetape_media_access_finished (drive);
@@ -2822,61 +2824,65 @@ static inline int idetape_pipeline_active (idetape_tape_t *tape)
static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
{
idetape_stage_t *stage;
- struct buffer_head *prev_bh, *bh;
+ struct bio *prev_bio, *bio;
int pages = tape->pages_per_stage;
- char *b_data;
+ char *b_data = NULL;
+ struct bio_vec *bv;
if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
return NULL;
stage->next = NULL;
- bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
- if (bh == NULL)
+ bio = stage->bio = bio_alloc(GFP_KERNEL,1);
+ bv = bio_iovec(bio);
+ bv->bv_len = 0;
+ if (bio == NULL)
goto abort;
- bh->b_reqnext = NULL;
- if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ bio->bi_next = NULL;
+ if ((bio->bi_io_vec[0].bv_page = alloc_page(GFP_KERNEL)) == NULL)
goto abort;
if (clear)
- memset(bh->b_data, 0, PAGE_SIZE);
- bh->b_size = PAGE_SIZE;
- atomic_set(&bh->b_count, full ? bh->b_size : 0);
- set_bit (BH_Lock, &bh->b_state);
+ memset(bio_data(bio), 0, PAGE_SIZE);
+ bio->bi_size = PAGE_SIZE;
+ if(bv->bv_len == full) bv->bv_len = bio->bi_size;
+ set_bit (BH_Lock, &bio->bi_flags);
while (--pages) {
- if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
goto abort;
if (clear)
- memset(b_data, 0, PAGE_SIZE);
- if (bh->b_data == b_data + PAGE_SIZE) {
- bh->b_size += PAGE_SIZE;
- bh->b_data -= PAGE_SIZE;
+ memset(bio_data(bio), 0, PAGE_SIZE);
+ if (bio->bi_size == bv->bv_len + PAGE_SIZE) {
+ bio->bi_size += PAGE_SIZE;
+ bv->bv_len += PAGE_SIZE;
+ bv->bv_offset -= PAGE_SIZE;
if (full)
- atomic_add(PAGE_SIZE, &bh->b_count);
+ bio->bi_size += PAGE_SIZE;
continue;
}
- if (b_data == bh->b_data + bh->b_size) {
- bh->b_size += PAGE_SIZE;
+ if (b_data == bio_data(bio) + bio->bi_size) {
+ bio->bi_size += PAGE_SIZE;
if (full)
- atomic_add(PAGE_SIZE, &bh->b_count);
+ bio->bi_size += PAGE_SIZE;
continue;
}
- prev_bh = bh;
- if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
- free_page ((unsigned long) b_data);
+ prev_bio = bio;
+ if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) {
+ free_page ((unsigned long) bio_data(bio));
goto abort;
}
- bh->b_reqnext = NULL;
- bh->b_data = b_data;
- bh->b_size = PAGE_SIZE;
- atomic_set(&bh->b_count, full ? bh->b_size : 0);
- set_bit (BH_Lock, &bh->b_state);
- prev_bh->b_reqnext = bh;
- }
- bh->b_size -= tape->excess_bh_size;
+ bio->bi_next = NULL;
+ //bio->bi_io_vec[0].bv_offset = b_data;
+ bio->bi_size = PAGE_SIZE;
+ atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
+ set_bit (BH_Lock, &bio->bi_flags);
+ prev_bio->bi_next = bio;
+ }
+ bio->bi_size -= tape->excess_bh_size;
if (full)
- atomic_sub(tape->excess_bh_size, &bh->b_count);
+ atomic_sub(tape->excess_bh_size, &bio->bi_cnt);
if (tape->onstream)
- stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
+ stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE);
return stage;
abort:
__idetape_kfree_stage (stage);
@@ -2903,39 +2909,39 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
{
- struct buffer_head *bh = tape->bh;
+ struct bio *bio = tape->bio;
int count;
while (n) {
#if IDETAPE_DEBUG_BUGS
- if (bh == NULL) {
- printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+ if (bio == NULL) {
+ printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n");
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
- count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
- copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+ count = IDE_MIN (bio->bi_size - tape->b_count, n);
+ copy_from_user (bio_data(bio) + tape->b_count, buf, count);
n -= count;
- atomic_add(count, &bh->b_count);
+ bio->bi_size += count;
buf += count;
- if (atomic_read(&bh->b_count) == bh->b_size) {
- bh = bh->b_reqnext;
- if (bh)
- atomic_set(&bh->b_count, 0);
+ if (tape->b_count == bio->bi_size) {
+ bio = bio->bi_next;
+ if (bio)
+ tape->b_count = 0;
}
}
- tape->bh = bh;
+ tape->bio = bio;
}
static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
{
- struct buffer_head *bh = tape->bh;
+ struct bio *bio = tape->bio;
int count;
while (n) {
#if IDETAPE_DEBUG_BUGS
- if (bh == NULL) {
- printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+ if (bio == NULL) {
+ printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n");
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
@@ -2946,10 +2952,10 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape
tape->b_count -= count;
buf += count;
if (!tape->b_count) {
- tape->bh = bh = bh->b_reqnext;
- if (bh) {
- tape->b_data = bh->b_data;
- tape->b_count = atomic_read(&bh->b_count);
+ tape->bio = bio = bio->bi_next;
+ if (bio) {
+ tape->b_data = bio_data(bio);
+ tape->b_count = bio->bi_size;
}
}
}
@@ -2957,25 +2963,25 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape
static void idetape_init_merge_stage (idetape_tape_t *tape)
{
- struct buffer_head *bh = tape->merge_stage->bh;
+ struct bio *bio = tape->merge_stage->bio;
- tape->bh = bh;
+ tape->bio = bio;
if (tape->chrdev_direction == idetape_direction_write)
- atomic_set(&bh->b_count, 0);
+ atomic_set(&bio->bi_cnt, 0);
else {
- tape->b_data = bh->b_data;
- tape->b_count = atomic_read(&bh->b_count);
+ tape->b_data = bio_data(bio);
+ tape->b_count = atomic_read(&bio->bi_cnt);
}
}
static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
{
- struct buffer_head *tmp;
+ struct bio *tmp;
os_aux_t *tmp_aux;
- tmp = stage->bh; tmp_aux = stage->aux;
- stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
- tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+ tmp = stage->bio; tmp_aux = stage->aux;
+ stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux;
+ tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux;
idetape_init_merge_stage (tape);
}
@@ -3077,7 +3083,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_BUGS
- if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
+ if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) {
printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
return;
}
@@ -3185,7 +3191,7 @@ static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
ide_init_drive_cmd (&rq);
rq.buffer = (char *) pc;
- rq.cmd = IDETAPE_PC_RQ1;
+ rq.flags = IDETAPE_PC_RQ1;
return ide_do_drive_cmd (drive, &rq, ide_wait);
}
@@ -3430,7 +3436,7 @@ static void idetape_update_stats (ide_drive_t *drive)
* idetape_queue_rw_tail generates a read/write request for the block
* device interface and wait for it to be serviced.
*/
-static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio)
{
idetape_tape_t *tape = drive->driver_data;
struct request rq;
@@ -3447,8 +3453,8 @@ static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struc
#endif /* IDETAPE_DEBUG_BUGS */
ide_init_drive_cmd (&rq);
- rq.bh = bh;
- rq.cmd = cmd;
+ rq.bio = bio;
+ rq.flags = cmd;
rq.sector = tape->first_frame_position;
rq.nr_sectors = rq.current_nr_sectors = blocks;
if (tape->onstream)
@@ -3489,15 +3495,15 @@ static void idetape_onstream_read_back_buffer (ide_drive_t *drive)
if (!first)
first = stage;
aux = stage->aux;
- p = stage->bh->b_data;
- idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
+ p = bio_data(stage->bio);
+ idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bio);
#if ONSTREAM_DEBUG
if (tape->debug_level >= 2)
printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
#endif
rq = &stage->rq;
ide_init_drive_cmd (rq);
- rq->cmd = IDETAPE_WRITE_RQ;
+ rq->flags = IDETAPE_WRITE_RQ;
rq->sector = tape->first_frame_position;
rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
@@ -3646,18 +3652,18 @@ static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int
os_aux_t *aux = stage->aux;
os_partition_t *par = &aux->partition;
struct request *rq = &stage->rq;
- struct buffer_head *bh;
+ struct bio *bio;
if (!tape->onstream)
return 1;
if (tape->raw) {
if (rq->errors) {
- bh = stage->bh;
- while (bh) {
- memset(bh->b_data, 0, bh->b_size);
- bh = bh->b_reqnext;
+ bio = stage->bio;
+ while (bio) {
+ memset(bio_data(bio), 0, bio->bi_size);
+ bio = bio->bi_next;
}
- strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
+ strcpy(bio_data(stage->bio), "READ ERROR ON FRAME");
}
return 1;
}
@@ -3767,12 +3773,12 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
* Linux is short on memory. Fallback to
* non-pipelined operation mode for this request.
*/
- return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+ return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
}
}
rq = &new_stage->rq;
ide_init_drive_cmd (rq);
- rq->cmd = IDETAPE_WRITE_RQ;
+ rq->flags = IDETAPE_WRITE_RQ;
rq->sector = tape->first_frame_position; /* Doesn't actually matter - We always assume sequential access */
rq->nr_sectors = rq->current_nr_sectors = blocks;
@@ -3843,7 +3849,7 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int blocks, i, min;
- struct buffer_head *bh;
+ struct bio *bio;
#if IDETAPE_DEBUG_BUGS
if (tape->chrdev_direction != idetape_direction_write) {
@@ -3860,22 +3866,22 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
if (tape->merge_stage_size % tape->tape_block_size) {
blocks++;
i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
- bh = tape->bh->b_reqnext;
- while (bh) {
- atomic_set(&bh->b_count, 0);
- bh = bh->b_reqnext;
+ bio = tape->bio->bi_next;
+ while (bio) {
+ atomic_set(&bio->bi_cnt, 0);
+ bio = bio->bi_next;
}
- bh = tape->bh;
+ bio = tape->bio;
while (i) {
- if (bh == NULL) {
- printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+ if (bio == NULL) {
+ printk(KERN_INFO "ide-tape: bug, bio NULL\n");
break;
}
- min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
- memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
- atomic_add(min, &bh->b_count);
+ min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt));
+ memset(bio_data(bio) + bio->bi_size, 0, min);
+ atomic_add(min, &bio->bi_cnt);
i -= min;
- bh = bh->b_reqnext;
+ bio = bio->bi_next;
}
}
(void) idetape_add_chrdev_write_request (drive, blocks);
@@ -3949,7 +3955,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
* is switched from completion mode to buffer available
* mode.
*/
- bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+ bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
if (bytes_read < 0) {
kfree (tape->merge_stage);
tape->merge_stage = NULL;
@@ -3960,7 +3966,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
if (tape->restart_speed_control_req)
idetape_restart_speed_control(drive);
ide_init_drive_cmd (&rq);
- rq.cmd = IDETAPE_READ_RQ;
+ rq.flags = IDETAPE_READ_RQ;
rq.sector = tape->first_frame_position;
rq.nr_sectors = rq.current_nr_sectors = blocks;
if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
@@ -4083,7 +4089,7 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
}
if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
return 0;
- return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+ return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
}
rq_ptr = &tape->first_stage->rq;
bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -4137,21 +4143,21 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
{
idetape_tape_t *tape = drive->driver_data;
- struct buffer_head *bh;
+ struct bio *bio;
int count, blocks;
while (bcount) {
- bh = tape->merge_stage->bh;
+ bio = tape->merge_stage->bio;
count = IDE_MIN (tape->stage_size, bcount);
bcount -= count;
blocks = count / tape->tape_block_size;
while (count) {
- atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
- memset (bh->b_data, 0, atomic_read(&bh->b_count));
- count -= atomic_read(&bh->b_count);
- bh = bh->b_reqnext;
+ atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size));
+ memset (bio_data(bio), 0, bio->bi_size);
+ count -= atomic_read(&bio->bi_cnt);
+ bio = bio->bi_next;
}
- idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+ idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
}
}
@@ -4276,7 +4282,7 @@ static void idetape_pre_reset (ide_drive_t *drive)
*/
static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
{
- unsigned int i = MINOR(i_rdev) & ~0xc0;
+ unsigned int i = minor(i_rdev) & ~0xc0;
if (i >= MAX_HWIFS * MAX_DRIVES)
return NULL;
@@ -4654,7 +4660,7 @@ static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr,
printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
#endif
idetape_position_tape(drive, last_mark_addr, 0, 0);
- if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+ if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
__idetape_kfree_stage (stage);
idetape_position_tape(drive, position, 0, 0);
@@ -4673,7 +4679,7 @@ static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr,
#endif
aux->next_mark_addr = htonl(next_mark_addr);
idetape_position_tape(drive, last_mark_addr, 0, 0);
- if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+ if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
__idetape_kfree_stage (stage);
idetape_position_tape(drive, position, 0, 0);
@@ -4705,9 +4711,9 @@ static void idetape_write_filler (ide_drive_t *drive, int block, int cnt)
if (rc != 0)
return; /* don't write fillers if we cannot position the tape. */
- strcpy(stage->bh->b_data, "Filler");
+ strcpy(bio_data(stage->bio), "Filler");
while (cnt--) {
- if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+ if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
__idetape_kfree_stage (stage);
return;
@@ -4739,9 +4745,9 @@ static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
header.partition.last_frame_addr = htonl(tape->capacity);
header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
- memcpy(stage->bh->b_data, &header, sizeof(header));
+ memcpy(bio_data(stage->bio), &header, sizeof(header));
while (cnt--) {
- if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+ if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
__idetape_kfree_stage (stage);
return;
@@ -4860,7 +4866,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
* is switched from completion mode to buffer available
* mode.
*/
- retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+ retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
if (retval < 0) {
kfree (tape->merge_stage);
tape->merge_stage = NULL;
@@ -5326,12 +5332,12 @@ static int __idetape_analyze_headers (ide_drive_t *drive, int block)
printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
#endif
idetape_position_tape(drive, block, 0, 0);
- if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+ if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
__idetape_kfree_stage (stage);
return 0;
}
- header = (os_header_t *) stage->bh->b_data;
+ header = (os_header_t *) bio_data(stage->bio);
aux = stage->aux;
if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
@@ -5403,7 +5409,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
ide_drive_t *drive;
idetape_tape_t *tape;
idetape_pc_t pc;
- unsigned int minor=MINOR (inode->i_rdev);
+ unsigned int minor=minor(inode->i_rdev);
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
@@ -5460,7 +5466,7 @@ static void idetape_write_release (struct inode *inode)
{
ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
idetape_tape_t *tape = drive->driver_data;
- unsigned int minor=MINOR (inode->i_rdev);
+ unsigned int minor=minor(inode->i_rdev);
idetape_empty_write_pipeline (drive);
tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
@@ -5486,7 +5492,7 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
idetape_tape_t *tape;
idetape_pc_t pc;
- unsigned int minor=MINOR (inode->i_rdev);
+ unsigned int minor=minor(inode->i_rdev);
tape = drive->driver_data;
#if IDETAPE_DEBUG_LOG
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index b47951259..daae0cfdd 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -706,8 +706,8 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
ide__sti(); /* local CPU only */
if (!OK_STAT(stat, READY_STAT, BAD_STAT))
- return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
-
+ return ide_error(drive, "task_no_data_intr", stat);
+ /* calls ide_end_drive_cmd */
if (args)
ide_end_drive_cmd (drive, stat, GET_ERR());
@@ -723,6 +723,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
+ unsigned long flags;
if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
if (stat & (ERR_STAT|DRQ_STAT)) {
@@ -735,17 +736,21 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
}
}
DTF("stat: %02x\n", stat);
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
if (--rq->current_nr_sectors <= 0) {
/* (hs): swapped next 2 lines */
DTF("Request Ended stat: %02x\n", GET_STAT());
- ide_end_request(1, HWGROUP(drive));
+ if (ide_end_request(1, HWGROUP(drive))) {
+ ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
} else {
ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
return ide_started;
@@ -809,13 +814,14 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive)
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
+ unsigned long flags;
if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
if (stat & (ERR_STAT|DRQ_STAT)) {
return ide_error(drive, "task_mulin_intr", stat);
}
/* no data yet, so wait for another interrupt */
- ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+ ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
return ide_started;
}
@@ -834,10 +840,11 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive)
*/
nsect = 1;
while (rq->current_nr_sectors) {
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
@@ -848,22 +855,34 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive)
}
#endif /* ALTSTAT_SCREW_UP */
- nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ do {
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
- DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
- pBuf, nsect, rq->current_nr_sectors);
- drive->io_32bit = 0;
- taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
- drive->io_32bit = io_32bit;
- rq->errors = 0;
- rq->current_nr_sectors -= nsect;
- if (rq->current_nr_sectors != 0) {
- ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
- return ide_started;
- }
- ide_end_request(1, HWGROUP(drive));
- return ide_stopped;
+ pBuf = ide_map_rq(rq, &flags);
+
+ DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+ pBuf, nsect, rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors -= nsect;
+ msect -= nsect;
+ if (!rq->current_nr_sectors) {
+ if (!ide_end_request(1, HWGROUP(drive)))
+ return ide_stopped;
+ }
+ } while (msect);
+
+
+ /*
+ * more data left
+ */
+ ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+ return ide_started;
}
ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
@@ -879,10 +898,12 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
/* (ks/hs): Fixed Multi Write */
if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
(args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+ unsigned long flags;
+ char *buf = ide_map_rq(rq, &flags);
/* For Write_sectors we need to stuff the first sector */
- taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+ taskfile_output_data(drive, buf, SECTOR_WORDS);
rq->current_nr_sectors--;
- return ide_started;
+ ide_unmap_rq(rq, buf, &flags);
} else {
/*
* (ks/hs): Stuff the first sector(s)
@@ -913,8 +934,10 @@ ide_startstop_t task_out_intr (ide_drive_t *drive)
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
+ unsigned long flags;
if (!rq->current_nr_sectors) {
+ printk("task_out_intr: should not trigger\n");
ide_end_request(1, HWGROUP(drive));
return ide_stopped;
}
@@ -922,19 +945,24 @@ ide_startstop_t task_out_intr (ide_drive_t *drive)
if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
return ide_error(drive, "task_out_intr", stat);
}
+
if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
rq = HWGROUP(drive)->rq;
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors--;
}
if (rq->current_nr_sectors <= 0) {
- ide_end_request(1, HWGROUP(drive));
+ if (ide_end_request(1, HWGROUP(drive))) {
+ ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
} else {
ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
return ide_started;
@@ -961,14 +989,20 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive)
struct request *rq = HWGROUP(drive)->rq;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
char *pBuf = NULL;
+ unsigned long flags;
/*
* (ks/hs): Handle last IRQ on multi-sector transfer,
- * occurs after all data was sent
+ * occurs after all data was sent in this chunk
*/
if (rq->current_nr_sectors == 0) {
if (stat & (ERR_STAT|DRQ_STAT))
return ide_error(drive, "task_mulout_intr", stat);
+
+ /*
+ * there may be more, ide_do_request will restart it if
+ * necessary
+ */
ide_end_request(1, HWGROUP(drive));
return ide_stopped;
}
@@ -994,10 +1028,11 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive)
if (!msect) {
nsect = 1;
while (rq->current_nr_sectors) {
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ide_unmap_rq(pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
@@ -1008,12 +1043,16 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive)
}
#endif /* ALTSTAT_SCREW_UP */
- nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
+
+ pBuf = ide_map_rq(rq, &flags);
DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
pBuf, nsect, rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 00f8d9b4c..3709f188b 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1458,14 +1458,11 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
HWGROUP(drive)->rq = NULL;
rq->errors = 0;
- rq->sector = rq->bio->bi_sector;
- rq->current_nr_sectors = bio_sectors(rq->bio);
-
- /*
- * just to make sure...
- */
- if (rq->bio)
+ if (rq->bio) {
+ rq->sector = rq->bio->bi_sector;
+ rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
rq->buffer = NULL;
+ }
}
/*
diff --git a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in
index 558317daa..0ded2b74c 100644
--- a/drivers/ieee1394/Config.in
+++ b/drivers/ieee1394/Config.in
@@ -19,6 +19,7 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
comment "Protocol Drivers"
dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
+ dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index b6cdcb6bf..9c8aca295 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
+obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index dfad289de..57b731c83 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -70,7 +70,7 @@ static void add_host(struct hpsb_host *host)
{
host->csr.lock = SPIN_LOCK_UNLOCKED;
- host->csr.rom_size = host->template->get_rom(host, &host->csr.rom);
+ host->csr.rom_size = host->ops->get_rom(host, &host->csr.rom);
host->csr.state = 0;
host->csr.node_ids = 0;
@@ -152,7 +152,7 @@ static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
case CSR_CYCLE_TIME:
oldcycle = host->csr.cycle_time;
host->csr.cycle_time =
- host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+ host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
if (oldcycle > host->csr.cycle_time) {
/* cycle time wrapped around */
@@ -163,7 +163,7 @@ static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
case CSR_BUS_TIME:
oldcycle = host->csr.cycle_time;
host->csr.cycle_time =
- host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+ host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
if (oldcycle > host->csr.cycle_time) {
/* cycle time wrapped around */
@@ -181,32 +181,32 @@ static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
return RCODE_ADDRESS_ERROR;
case CSR_BUS_MANAGER_ID:
- if (host->template->hw_csr_reg)
- ret = host->template->hw_csr_reg(host, 0, 0, 0);
+ if (host->ops->hw_csr_reg)
+ ret = host->ops->hw_csr_reg(host, 0, 0, 0);
else
ret = host->csr.bus_manager_id;
*(buf++) = cpu_to_be32(ret);
out;
case CSR_BANDWIDTH_AVAILABLE:
- if (host->template->hw_csr_reg)
- ret = host->template->hw_csr_reg(host, 1, 0, 0);
+ if (host->ops->hw_csr_reg)
+ ret = host->ops->hw_csr_reg(host, 1, 0, 0);
else
ret = host->csr.bandwidth_available;
*(buf++) = cpu_to_be32(ret);
out;
case CSR_CHANNELS_AVAILABLE_HI:
- if (host->template->hw_csr_reg)
- ret = host->template->hw_csr_reg(host, 2, 0, 0);
+ if (host->ops->hw_csr_reg)
+ ret = host->ops->hw_csr_reg(host, 2, 0, 0);
else
ret = host->csr.channels_available_hi;
*(buf++) = cpu_to_be32(ret);
out;
case CSR_CHANNELS_AVAILABLE_LO:
- if (host->template->hw_csr_reg)
- ret = host->template->hw_csr_reg(host, 3, 0, 0);
+ if (host->ops->hw_csr_reg)
+ ret = host->ops->hw_csr_reg(host, 3, 0, 0);
else
ret = host->csr.channels_available_lo;
@@ -244,7 +244,7 @@ static int write_regs(struct hpsb_host *host, int nodeid, int destid,
host->csr.node_ids &= NODE_MASK << 16;
host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
host->node_id = host->csr.node_ids >> 16;
- host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
+ host->ops->devctl(host, SET_BUS_ID, host->node_id >> 6);
out;
case CSR_RESET_START:
@@ -269,7 +269,7 @@ static int write_regs(struct hpsb_host *host, int nodeid, int destid,
case CSR_CYCLE_TIME:
/* should only be set by cycle start packet, automatically */
host->csr.cycle_time = be32_to_cpu(*data);
- host->template->devctl(host, SET_CYCLE_COUNTER,
+ host->ops->devctl(host, SET_CYCLE_COUNTER,
be32_to_cpu(*(data++)));
out;
case CSR_BUS_TIME:
@@ -318,10 +318,10 @@ static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
data = be32_to_cpu(data);
arg = be32_to_cpu(arg);
- if (host->template->hw_csr_reg) {
+ if (host->ops->hw_csr_reg) {
quadlet_t old;
- old = host->template->
+ old = host->ops->
hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
data, arg);
diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
new file mode 100644
index 000000000..f5d81c436
--- /dev/null
+++ b/drivers/ieee1394/dv1394-private.h
@@ -0,0 +1,606 @@
+/*
+ * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
+ * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ * receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ * video1394.h - driver for OHCI 1394 boards
+ * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ * Peter Schlaile <udbz@rz.uni-karlsruhe.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 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.
+ */
+
+#ifndef _DV_1394_PRIVATE_H
+#define _DV_1394_PRIVATE_H
+
+#include "ieee1394.h"
+#include <linux/pci.h>
+#include <asm/scatterlist.h>
+
+/* data structures private to the dv1394 driver */
+/* none of this is exposed to user-space */
+
+
+/*
+ the 8-byte CIP (Common Isochronous Packet) header that precedes
+ each packet of DV data.
+
+ See the IEC 61883 standard.
+*/
+
+struct CIP_header { unsigned char b[8]; };
+
+static inline void fill_cip_header(struct CIP_header *cip,
+ unsigned char source_node_id,
+ unsigned long counter,
+ enum pal_or_ntsc format,
+ unsigned long timestamp)
+{
+ cip->b[0] = source_node_id;
+ cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
+ cip->b[2] = 0x00;
+ cip->b[3] = counter;
+
+ cip->b[4] = 0x80; /* const */
+
+ switch(format) {
+ case DV1394_PAL:
+ cip->b[5] = 0x80;
+ break;
+ case DV1394_NTSC:
+ cip->b[5] = 0x00;
+ break;
+ }
+
+ cip->b[6] = timestamp >> 8;
+ cip->b[7] = timestamp & 0xFF;
+}
+
+
+
+/*
+ DMA commands used to program the OHCI's DMA engine
+
+ See the Texas Instruments OHCI 1394 chipset documentation.
+*/
+
+struct output_more_immediate { u32 q[8]; };
+struct output_more { u32 q[4]; };
+struct output_last { u32 q[4]; };
+struct input_more { u32 q[4]; };
+struct input_last { u32 q[4]; };
+
+/* outputs */
+
+static inline void fill_output_more_immediate(struct output_more_immediate *omi,
+ unsigned char tag,
+ unsigned char channel,
+ unsigned char sync_tag,
+ unsigned int payload_size)
+{
+ omi->q[0] = 0x02000000 | 8 ; /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
+ omi->q[1] = 0;
+ omi->q[2] = 0;
+ omi->q[3] = 0;
+
+ /* IT packet header */
+ omi->q[4] = (0x0 << 16) /* DMA_SPEED_100 */
+ | (tag << 14)
+ | (channel << 8)
+ | (TCODE_ISO_DATA << 4)
+ | (sync_tag);
+
+ omi->q[5] = payload_size << 16;
+ omi->q[5] |= (0x7F << 8) | 0xA0; /* reserved field; mimic behavior of my Sony DSR-40 */
+
+ omi->q[6] = 0;
+ omi->q[7] = 0;
+}
+
+static inline void fill_output_more(struct output_more *om,
+ unsigned int data_size,
+ unsigned long data_phys_addr)
+{
+ om->q[0] = 0; /* OUTPUT_MORE */
+ om->q[0] |= data_size;
+
+ om->q[1] = data_phys_addr;
+ om->q[2] = 0;
+ om->q[3] = 0;
+}
+
+static inline void fill_output_last(struct output_last *ol,
+ int want_timestamp,
+ int want_interrupt,
+ unsigned int data_size,
+ unsigned long data_phys_addr)
+{
+ ol->q[0] = 0;
+ ol->q[0] |= 1 << 28; /* OUTPUT_LAST */
+
+ if(want_timestamp) /* controller will update timestamp at DMA time */
+ ol->q[0] |= 1 << 27;
+
+ if(want_interrupt)
+ ol->q[0] |= 3 << 20;
+
+ ol->q[0] |= 3 << 18; /* must take branch */
+ ol->q[0] |= data_size;
+
+ ol->q[1] = data_phys_addr;
+ ol->q[2] = 0;
+ ol->q[3] = 0;
+}
+
+/* inputs */
+
+static inline void fill_input_more(struct input_more *im,
+ int want_interrupt,
+ unsigned int data_size,
+ unsigned long data_phys_addr)
+{
+ im->q[0] = 2 << 28; /* INPUT_MORE */
+ im->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+ if (want_interrupt)
+ im->q[0] |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
+ im->q[0] |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
+ /* disable wait on sync field, not used in DV :-( */
+ im->q[0] |= data_size;
+
+ im->q[1] = data_phys_addr;
+ im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */
+ im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */
+}
+
+static inline void fill_input_last(struct input_last *il,
+ unsigned int data_size,
+ unsigned long data_phys_addr)
+{
+ il->q[0] = 3 << 28; /* INPUT_LAST */
+ il->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+ il->q[0] |= 3 << 20; /* enable interrupts */
+ il->q[0] |= 0xC << 16; /* enable branch to address */
+ /* disable wait on sync field, not used in DV :-( */
+ il->q[0] |= data_size;
+
+ il->q[1] = data_phys_addr;
+ il->q[2] = 1; /* branchAddress (filled in later) and Z = 1 descriptor in next block */
+ il->q[3] = data_size; /* xferStatus & resCount, resCount must be initialize to data_size */
+}
+
+
+
+/*
+ A "DMA descriptor block" consists of several contiguous DMA commands.
+ struct DMA_descriptor_block encapsulates all of the commands necessary
+ to send one packet of DV data.
+
+ There are three different types of these blocks:
+
+ 1) command to send an empty packet (CIP header only, no DV data):
+
+ OUTPUT_MORE-Immediate <-- contains the iso header in-line
+ OUTPUT_LAST <-- points to the CIP header
+
+ 2) command to send a full packet when the DV data payload does NOT
+ cross a page boundary:
+
+ OUTPUT_MORE-Immediate <-- contains the iso header in-line
+ OUTPUT_MORE <-- points to the CIP header
+ OUTPUT_LAST <-- points to entire DV data payload
+
+ 3) command to send a full packet when the DV payload DOES cross
+ a page boundary:
+
+ OUTPUT_MORE-Immediate <-- contains the iso header in-line
+ OUTPUT_MORE <-- points to the CIP header
+ OUTPUT_MORE <-- points to first part of DV data payload
+ OUTPUT_LAST <-- points to second part of DV data payload
+
+ This struct describes all three block types using unions.
+
+ !!! It is vital that an even number of these descriptor blocks fit on one
+ page of memory, since a block cannot cross a page boundary !!!
+
+ */
+
+struct DMA_descriptor_block {
+
+ union {
+ struct {
+ /* iso header, common to all output block types */
+ struct output_more_immediate omi;
+
+ union {
+ /* empty packet */
+ struct {
+ struct output_last ol; /* CIP header */
+ } empty;
+
+ /* full packet */
+ struct {
+ struct output_more om; /* CIP header */
+
+ union {
+ /* payload does not cross page boundary */
+ struct {
+ struct output_last ol; /* data payload */
+ } nocross;
+
+ /* payload crosses page boundary */
+ struct {
+ struct output_more om; /* data payload */
+ struct output_last ol; /* data payload */
+ } cross;
+ } u;
+
+ } full;
+ } u;
+ } out;
+
+ struct {
+ struct input_last il;
+ } in;
+
+ } u;
+
+ /* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
+ by padding out to 128 bytes */
+ u32 __pad__[12];
+};
+
+
+/* struct frame contains all data associated with one frame in the
+ ringbuffer these are allocated when the DMA context is initialized
+ do_dv1394_init(). They are re-used after the card finishes
+ transmitting the frame. */
+
+struct video_card; /* forward declaration */
+
+struct frame {
+
+ /* points to the struct video_card that owns this frame */
+ struct video_card *video;
+
+ /* index of this frame in video_card->frames[] */
+ unsigned int frame_num;
+
+ /* FRAME_CLEAR - DMA program not set up, waiting for data
+ FRAME_READY - DMA program written, ready to transmit
+
+ Changes to these should be locked against the interrupt
+ */
+ enum {
+ FRAME_CLEAR = 0,
+ FRAME_READY
+ } state;
+
+ /* whether this frame has been DMA'ed already; used only from
+ the IRQ handler to determine whether the frame can be reset */
+ int done;
+
+
+ /* kernel virtual pointer to the start of this frame's data in
+ the user ringbuffer. Use only for CPU access; to get the DMA
+ bus address you must go through the video->user_dma mapping */
+ unsigned long data;
+
+ /* Max # of packets per frame */
+ #define MAX_PACKETS 320
+
+
+ /* a PAGE_SIZE memory pool for allocating CIP headers
+ !header_pool must be aligned to PAGE_SIZE! */
+ struct CIP_header *header_pool;
+ dma_addr_t header_pool_dma;
+
+
+ /* a physically contiguous memory pool for allocating DMA
+ descriptor blocks; usually around 64KB in size
+ !descriptor_pool must be aligned to PAGE_SIZE! */
+ struct DMA_descriptor_block *descriptor_pool;
+ dma_addr_t descriptor_pool_dma;
+ unsigned long descriptor_pool_size;
+
+
+ /* # of packets allocated for this frame */
+ unsigned int n_packets;
+
+
+ /* below are several pointers (kernel virtual addresses, not
+ DMA bus addresses) to parts of the DMA program. These are
+ set each time the DMA program is written in
+ frame_prepare(). They are used later on, e.g. from the
+ interrupt handler, to check the status of the frame */
+
+ /* points to status/timestamp field of first DMA packet */
+ /* (we'll check it later to monitor timestamp accuracy) */
+ u32 *frame_begin_timestamp;
+
+ /* the timestamp we assigned to the first packet in the frame */
+ u32 assigned_timestamp;
+
+ /* pointer to the first packet's CIP header (where the timestamp goes) */
+ struct CIP_header *cip_syt1;
+
+ /* pointer to the second packet's CIP header
+ (only set if the first packet was empty) */
+ struct CIP_header *cip_syt2;
+
+ /* in order to figure out what caused an interrupt,
+ store pointers to the status fields of the two packets
+ that can cause interrupts. We'll check these from the
+ interrupt handler.
+ */
+ u32 *mid_frame_timestamp;
+ u32 *frame_end_timestamp;
+
+ /* branch address field of final packet. This is effectively
+ the "tail" in the chain of DMA descriptor blocks.
+ We will fill it with the address of the first DMA descriptor
+ block in the subsequent frame, once it is ready.
+ */
+ u32 *frame_end_branch;
+
+ /* the number of descriptors in the first descriptor block
+ of the frame. Needed to start DMA */
+ int first_n_descriptors;
+};
+
+
+struct packet {
+ u16 timestamp;
+ u16 invalid;
+ u16 iso_header;
+ u16 data_length;
+ u32 cip_h1;
+ u32 cip_h2;
+ unsigned char data[480];
+ unsigned char padding[16]; /* force struct size =512 for page alignment */
+};
+
+
+/* allocate/free a frame */
+static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
+static void frame_delete(struct frame *f);
+
+/* reset f so that it can be used again */
+static void frame_reset(struct frame *f);
+
+
+/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */
+
+struct dma_region {
+ unsigned int n_pages;
+ unsigned int n_dma_pages;
+ struct scatterlist *sglist;
+};
+
+/* return the DMA bus address of the byte with the given offset
+ relative to the beginning of the dma_region */
+
+static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset)
+{
+ int i;
+ struct scatterlist *sg;
+
+ for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) {
+ if(offset < sg_dma_len(sg)) {
+ return sg_dma_address(sg) + offset;
+ }
+ offset -= sg_dma_len(sg);
+ }
+
+ printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset);
+ return 0;
+}
+
+
+/* struct video_card contains all data associated with one instance
+ of the dv1394 driver
+*/
+
+struct video_card {
+
+ /* ohci card to which this instance corresponds */
+ struct ti_ohci *ohci;
+
+ /* OHCI card id; the link between the VFS inode and a specific video_card
+ (essentially the device minor number) */
+ int id;
+
+ /* entry in dv1394_cards */
+ struct list_head list;
+
+ /* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */
+ devfs_handle_t devfs_handle;
+
+ /* OHCI card IT DMA context number, -1 if not in use */
+ int ohci_it_ctx;
+
+ /* register offsets for current IT DMA context, 0 if not in use */
+ u32 ohci_IsoXmitContextControlSet;
+ u32 ohci_IsoXmitContextControlClear;
+ u32 ohci_IsoXmitCommandPtr;
+
+ /* OHCI card IR DMA context number, -1 if not in use */
+ int ohci_ir_ctx;
+
+ /* register offsets for current IR DMA context, 0 if not in use */
+ u32 ohci_IsoRcvContextControlSet;
+ u32 ohci_IsoRcvContextControlClear;
+ u32 ohci_IsoRcvCommandPtr;
+ u32 ohci_IsoRcvContextMatch;
+
+
+ /* CONCURRENCY CONTROL */
+
+ /* there are THREE levels of locking associated with video_card. */
+
+ /*
+ 1) the 'open' flag - this prevents more than one process from
+ opening the device. (the driver currently assumes only one opener).
+ This is a regular int, but use test_and_set_bit() (on bit zero)
+ for atomicity.
+ */
+ int open;
+
+ /*
+ 2) the spinlock - this provides mutual exclusion between the interrupt
+ handler and process-context operations. Generally you must take the
+ spinlock under the following conditions:
+ 1) DMA (and hence the interrupt handler) may be running
+ AND
+ 2) you need to operate on the video_card, especially active_frame
+
+ It is OK to play with video_card without taking the spinlock if
+ you are certain that DMA is not running. Even if DMA is running,
+ it is OK to *read* active_frame with the lock, then drop it
+ immediately. This is safe because the interrupt handler will never
+ advance active_frame onto a frame that is not READY (and the spinlock
+ must be held while marking a frame READY).
+ */
+ spinlock_t spinlock;
+
+ /*
+ 3) the sleeping semaphore 'sem' - this is used from process context only,
+ to serialize various operations on the video_card. Even though only one
+ open() is allowed, we still need to prevent multiple threads of execution
+ from entering calls like read, write, ioctl, etc.
+
+ I honestly can't think of a good reason to use dv1394 from several threads
+ at once, but we need to serialize anyway to prevent oopses =).
+
+ NOTE: if you need both spinlock and sem, take sem first to avoid deadlock!
+ */
+ struct semaphore sem;
+
+ /* people waiting for buffer space, please form a line here... */
+ wait_queue_head_t waitq;
+
+ /* support asynchronous I/O signals (SIGIO) */
+ struct fasync_struct *fasync;
+
+ /* the large, non-contiguous (rvmalloc()) ringbuffer for DV
+ data, exposed to user-space via mmap() */
+ unsigned char *user_buf;
+ unsigned long user_buf_size;
+ struct dma_region user_dma;
+
+ /* next byte in the ringbuffer that a write() call will fill */
+ size_t write_off;
+
+ struct frame *frames[DV1394_MAX_FRAMES];
+
+ /* n_frames also serves as an indicator that this struct video_card is
+ intialized and ready to run DMA buffers */
+
+ int n_frames;
+
+ /* this is the frame that is currently "owned" by the OHCI DMA controller
+ (set to -1 iff DMA is not running)
+
+ ! must lock against the interrupt handler when accessing it !
+
+ RULES:
+
+ Only the interrupt handler may change active_frame if DMA
+ is running; if not, process may change it
+
+ If the next frame is READY, the interrupt handler will advance
+ active_frame when the current frame is finished.
+
+ If the next frame is CLEAR, the interrupt handler will re-transmit
+ the current frame, and the dropped_frames counter will be incremented.
+
+ The interrupt handler will NEVER advance active_frame to a
+ frame that is not READY.
+
+ */
+ int active_frame;
+ int first_run;
+
+ /* the same locking rules apply to these three fields also: */
+
+ /* altered ONLY from process context. Must check first_clear_frame->state;
+ if it's READY, that means the ringbuffer is full with READY frames;
+ if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
+ unsigned int first_clear_frame;
+
+ /* altered both by process and interrupt */
+ unsigned int n_clear_frames;
+
+ /* only altered by the interrupt */
+ unsigned int dropped_frames;
+
+
+
+ /* the CIP accumulator and continuity counter are properties
+ of the DMA stream as a whole (not a single frame), so they
+ are stored here in the video_card */
+
+ unsigned long cip_accum;
+ unsigned long cip_n, cip_d;
+ unsigned int syt_offset;
+ unsigned int continuity_counter;
+
+ enum pal_or_ntsc pal_or_ntsc;
+
+ /* redundant, but simplifies the code somewhat */
+ unsigned int frame_size; /* in bytes */
+
+ /* the isochronous channel to use, -1 if video card is inactive */
+ int channel;
+
+
+ /* physically contiguous packet ringbuffer for receive */
+#define MAX_PACKET_BUFFER 30
+ struct packet *packet_buffer;
+ dma_addr_t packet_buffer_dma;
+ unsigned long packet_buffer_size;
+
+ unsigned int current_packet;
+ int first_frame; /* received first start frame marker? */
+};
+
+/*
+ if the video_card is not initialized, then the ONLY fields that are valid are:
+ ohci
+ open
+ n_frames
+*/
+
+static inline int video_card_initialized(struct video_card *v)
+{
+ return v->n_frames > 0;
+}
+
+static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
+static int do_dv1394_init_default(struct video_card *video);
+static int do_dv1394_shutdown(struct video_card *video, int free_user_buf);
+
+
+/* NTSC empty packet rate accurate to within 0.01%,
+ calibrated against a Sony DSR-40 DVCAM deck */
+
+#define CIP_N_NTSC 68000000
+#define CIP_D_NTSC 1000000000
+
+#define CIP_N_PAL 1
+#define CIP_D_PAL 16
+
+#endif /* _DV_1394_PRIVATE_H */
+
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
new file mode 100644
index 000000000..6a67e29f3
--- /dev/null
+++ b/drivers/ieee1394/dv1394.c
@@ -0,0 +1,2722 @@
+/*
+ * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
+ * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ * receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ * video1394.c - video driver for OHCI 1394 boards
+ * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *
+ * 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.
+ */
+
+/*
+ OVERVIEW
+
+ I designed dv1394 as a "pipe" that you can use to shoot DV onto a
+ FireWire bus. In transmission mode, dv1394 does the following:
+
+ 1. accepts contiguous frames of DV data from user-space, via write()
+ or mmap() (see dv1394.h for the complete API)
+ 2. wraps IEC 61883 packets around the DV data, inserting
+ empty synchronization packets as necessary
+ 3. assigns accurate SYT timestamps to the outgoing packets
+ 4. shoots them out using the OHCI card's IT DMA engine
+
+ Thanks to Dan Dennedy, we now have a receive mode that does the following:
+
+ 1. accepts raw IEC 61883 packets from the OHCI card
+ 2. re-assembles the DV data payloads into contiguous frames,
+ discarding empty packets
+ 3. sends the DV data to user-space via read() or mmap()
+*/
+
+/*
+ TODO:
+
+ - expose xmit and recv as separate devices
+
+ - tunable frame-drop behavior: either loop last frame, or halt transmission
+
+ - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
+ so that we don't rely on allocating 64KB of contiguous kernel memory
+ via pci_alloc_consistent()
+
+ DONE:
+ - safely obtain and release ISO Tx channels in cooperation with OHCI driver
+ - map received DIF blocks to their proper location in DV frame (ensure
+ recovery if dropped packet)
+ - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
+ - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
+ - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
+ - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
+ - set video->id correctly
+ - store video_cards in an array indexed by OHCI card ID, rather than a list
+ - implement DMA context allocation to cooperate with other users of the OHCI
+ - fix all XXX showstoppers
+ - disable IR/IT DMA interrupts on shutdown
+ - flush pci writes to the card by issuing a read
+ - devfs and character device dispatching (* needs testing with Linux 2.2.x)
+ - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
+ - keep all video_cards in a list (for open() via chardev), set file->private_data = video
+ - dv1394_poll should indicate POLLIN when receiving buffers are available
+ - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
+
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"
+#include "dv1394.h"
+#include "dv1394-private.h"
+
+#include "ohci1394.h"
+
+#ifndef virt_to_page
+#define virt_to_page(x) MAP_NR(x)
+#endif
+
+#ifndef vmalloc_32
+#define vmalloc_32(x) vmalloc(x)
+#endif
+
+
+/* DEBUG LEVELS:
+ 0 - no debugging messages
+ 1 - some debugging messages, but none during DMA frame transmission
+ 2 - lots of messages, including during DMA frame transmission
+ (will cause undeflows if your machine is too slow!)
+*/
+
+#define DV1394_DEBUG_LEVEL 0
+
+/* for debugging use ONLY: allow more than one open() of the device */
+/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
+
+#if DV1394_DEBUG_LEVEL >= 2
+#define irq_printk( args... ) printk( args )
+#else
+#define irq_printk( args... )
+#endif
+
+#if DV1394_DEBUG_LEVEL >= 1
+#define debug_printk( args... ) printk( args)
+#else
+#define debug_printk( args... )
+#endif
+
+/* issue a dummy PCI read to force the preceding write
+ to be posted to the PCI bus immediately */
+
+static inline void flush_pci_write(struct ti_ohci *ohci)
+{
+ mb();
+ reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+}
+
+static void irq_handler(int card, quadlet_t isoRecvIntEvent,
+ quadlet_t isoXmitIntEvent, void *data);
+
+
+/* GLOBAL DATA */
+
+/* list of all video_cards */
+static LIST_HEAD(dv1394_cards);
+static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
+
+static struct hpsb_highlevel *hl_handle; /* = NULL; */
+
+static devfs_handle_t dv1394_devfs_handle;
+
+/* translate from a struct file* to the corresponding struct video_card* */
+
+static inline struct video_card* file_to_video_card(struct file *file)
+{
+ return (struct video_card*) file->private_data;
+}
+
+
+/* Taken from bttv.c */
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+#define MDEBUG(x) do { } while(0) /* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ * out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed. We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define page_address(x) (x)
+#endif
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr)
+{
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+ struct page *ret = NULL;
+
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, adr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset(pmd, adr);
+ pte = *ptep;
+ if(pte_present(pte))
+ ret = pte_page(pte);
+ }
+ }
+ return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved, and for
+ * handling page faults on the rvmalloc()ed buffer
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va));
+ kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+ ret = __pa(kva);
+ MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+ return ret;
+}
+
+static void * rvmalloc(unsigned long size)
+{
+ void * mem;
+ unsigned long adr, page;
+
+ mem=vmalloc_32(size);
+ if (mem) {
+ memset(mem, 0, size); /* Clear the ram out,
+ no junk to the user */
+ adr=(unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa(adr);
+ mem_map_reserve(virt_to_page(__va(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ }
+ return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+ unsigned long adr, page;
+
+ if (mem) {
+ adr=(unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa(adr);
+ mem_map_unreserve(virt_to_page(__va(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ vfree(mem);
+ }
+}
+
+/***********************************/
+/* END Memory management functions */
+/***********************************/
+
+
+/*** FRAME METHODS *********************************************************/
+
+static void frame_reset(struct frame *f)
+{
+ f->state = FRAME_CLEAR;
+ f->done = 0;
+ f->n_packets = 0;
+ f->frame_begin_timestamp = NULL;
+ f->assigned_timestamp = 0;
+ f->cip_syt1 = NULL;
+ f->cip_syt2 = NULL;
+ f->mid_frame_timestamp = NULL;
+ f->frame_end_timestamp = NULL;
+ f->frame_end_branch = NULL;
+}
+
+static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
+{
+ struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
+ if(!f)
+ return NULL;
+
+ f->video = video;
+ f->frame_num = frame_num;
+
+ f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
+ if(!f->header_pool) {
+ printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
+ kfree(f);
+ return NULL;
+ }
+
+ debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
+ (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
+
+ f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
+ /* make it an even # of pages */
+ f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
+
+ f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
+ f->descriptor_pool_size,
+ &f->descriptor_pool_dma);
+ if(!f->descriptor_pool) {
+ pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
+ kfree(f);
+ return NULL;
+ }
+
+ debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
+ (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
+
+ f->data = 0;
+ frame_reset(f);
+
+ return f;
+}
+
+static void frame_delete(struct frame *f)
+{
+ pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
+ pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
+ kfree(f);
+}
+
+
+
+
+/*
+ frame_prepare() - build the DMA program for transmitting
+
+ Frame_prepare() must be called OUTSIDE the video->spinlock.
+ However, frame_prepare() must still be serialized, so
+ it should be called WITH the video->sem taken.
+ */
+
+static void frame_prepare(struct video_card *video, unsigned int this_frame)
+{
+ struct frame *f = video->frames[this_frame];
+ int last_frame;
+
+ struct DMA_descriptor_block *block;
+ dma_addr_t block_dma;
+ struct CIP_header *cip;
+ dma_addr_t cip_dma;
+
+ unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
+
+ /* these flags denote packets that need special attention */
+ int empty_packet, first_packet, last_packet, mid_packet;
+
+ u32 *branch_address, *last_branch_address = NULL;
+ unsigned long data_p;
+ int first_packet_empty = 0;
+ u32 cycleTimer, ct_sec, ct_cyc, ct_off;
+ unsigned long irq_flags;
+
+ irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
+
+ full_packets = 0;
+
+
+
+ if(video->pal_or_ntsc == DV1394_PAL)
+ packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
+ else
+ packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
+
+ while( full_packets < packets_per_frame ) {
+ empty_packet = first_packet = last_packet = mid_packet = 0;
+
+ data_p = f->data + full_packets * 480;
+
+ /************************************************/
+ /* allocate a descriptor block and a CIP header */
+ /************************************************/
+
+ /* note: these should NOT cross a page boundary (DMA restriction) */
+
+ if(f->n_packets >= MAX_PACKETS) {
+ printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
+ return;
+ }
+
+ /* the block surely won't cross a page boundary,
+ since an even number of descriptor_blocks fit on a page */
+ block = &(f->descriptor_pool[f->n_packets]);
+
+ /* DMA address of the block = offset of block relative
+ to the kernel base address of the descriptor pool
+ + DMA base address of the descriptor pool */
+ block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+
+
+ /* the whole CIP pool fits on one page, so no worries about boundaries */
+ if( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool)
+ > PAGE_SIZE) {
+ printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
+ return;
+ }
+
+ cip = &(f->header_pool[f->n_packets]);
+
+ /* DMA address of the CIP header = offset of cip
+ relative to kernel base address of the header pool
+ + DMA base address of the header pool */
+ cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
+
+ /* is this an empty packet? */
+
+ if(video->cip_accum > video->cip_d) {
+ empty_packet = 1;
+ payload_size = 8;
+ video->cip_accum -= video->cip_d;
+ } else {
+ payload_size = 488;
+ video->cip_accum += video->cip_n;
+ }
+
+ /* there are three important packets each frame:
+
+ the first packet in the frame - we ask the card to record the timestamp when
+ this packet is actually sent, so we can monitor
+ how accurate our timestamps are. Also, the first
+ packet serves as a semaphore to let us know that
+ it's OK to free the *previous* frame's DMA buffer
+
+ the last packet in the frame - this packet is used to detect buffer underflows.
+ if this is the last ready frame, the last DMA block
+ will have a branch back to the beginning of the frame
+ (so that the card will re-send the frame on underflow).
+ if this branch gets taken, we know that at least one
+ frame has been dropped. When the next frame is ready,
+ the branch is pointed to its first packet, and the
+ semaphore is disabled.
+
+ a "mid" packet slightly before the end of the frame - this packet should trigger
+ an interrupt so we can go and assign a timestamp to the first packet
+ in the next frame. We don't use the very last packet in the frame
+ for this purpose, because that would leave very little time to set
+ the timestamp before DMA starts on the next frame.
+ */
+
+ if(f->n_packets == 0) {
+ first_packet = 1;
+ } else if ( full_packets == (packets_per_frame-1) ) {
+ last_packet = 1;
+ } else if (f->n_packets == packets_per_frame) {
+ mid_packet = 1;
+ }
+
+
+ /********************/
+ /* setup CIP header */
+ /********************/
+
+ /* the timestamp will be written later from the
+ mid-frame interrupt handler. For now we just
+ store the address of the CIP header(s) that
+ need a timestamp. */
+
+ /* first packet in the frame needs a timestamp */
+ if(first_packet) {
+ f->cip_syt1 = cip;
+ if(empty_packet)
+ first_packet_empty = 1;
+
+ } else if(first_packet_empty && (f->n_packets == 1) ) {
+ /* if the first packet was empty, the second
+ packet's CIP header also needs a timestamp */
+ f->cip_syt2 = cip;
+ }
+
+ fill_cip_header(cip,
+ /* the node ID number of the OHCI card */
+ reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
+ video->continuity_counter,
+ video->pal_or_ntsc,
+ 0xFFFF /* the timestamp is filled in later */);
+
+ /* advance counter, only for full packets */
+ if( ! empty_packet )
+ video->continuity_counter++;
+
+ /******************************/
+ /* setup DMA descriptor block */
+ /******************************/
+
+ /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
+ fill_output_more_immediate( &(block->u.out.omi),
+ /* tag - what is this??? */ 1,
+ video->channel,
+ /* sync tag - what is this??? */ 0,
+ payload_size);
+
+ if(empty_packet) {
+ /* second descriptor - OUTPUT_LAST for CIP header */
+ fill_output_last( &(block->u.out.u.empty.ol),
+
+ /* want completion status on all interesting packets */
+ (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+ /* want interrupts on all interesting packets */
+ (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+ sizeof(struct CIP_header), /* data size */
+ cip_dma);
+
+ if(first_packet)
+ f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
+ else if(mid_packet)
+ f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
+ else if(last_packet) {
+ f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
+ f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
+ }
+
+ branch_address = &(block->u.out.u.empty.ol.q[2]);
+ n_descriptors = 3;
+ if(first_packet)
+ f->first_n_descriptors = n_descriptors;
+
+ } else { /* full packet */
+
+ /* second descriptor - OUTPUT_MORE for CIP header */
+ fill_output_more( &(block->u.out.u.full.om),
+ sizeof(struct CIP_header), /* data size */
+ cip_dma);
+
+
+ /* third (and possibly fourth) descriptor - for DV data */
+ /* the 480-byte payload can cross a page boundary; if so,
+ we need to split it into two DMA descriptors */
+
+ /* does the 480-byte data payload cross a page boundary? */
+ if( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
+
+ /* page boundary crossed */
+
+ fill_output_more( &(block->u.out.u.full.u.cross.om),
+ /* data size - how much of data_p fits on the first page */
+ PAGE_SIZE - (data_p % PAGE_SIZE),
+
+ /* DMA address of data_p */
+ dma_offset_to_bus(&f->video->user_dma,
+ data_p - (unsigned long) f->video->user_buf));
+
+ fill_output_last( &(block->u.out.u.full.u.cross.ol),
+
+ /* want completion status on all interesting packets */
+ (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+ /* want interrupt on all interesting packets */
+ (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+ /* data size - remaining portion of data_p */
+ 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
+
+ /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
+ dma_offset_to_bus(&f->video->user_dma,
+ data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+
+ if(first_packet)
+ f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+ else if(mid_packet)
+ f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+ else if(last_packet) {
+ f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+ f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
+ }
+
+ branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
+
+ n_descriptors = 5;
+ if(first_packet)
+ f->first_n_descriptors = n_descriptors;
+
+ full_packets++;
+
+ } else {
+ /* fits on one page */
+
+ fill_output_last( &(block->u.out.u.full.u.nocross.ol),
+
+ /* want completion status on all interesting packets */
+ (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+ /* want interrupt on all interesting packets */
+ (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+ 480, /* data size (480 bytes of DV data) */
+
+
+ /* DMA address of data_p */
+ dma_offset_to_bus(&f->video->user_dma,
+ data_p - (unsigned long) f->video->user_buf));
+
+ if(first_packet)
+ f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+ else if(mid_packet)
+ f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+ else if(last_packet) {
+ f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+ f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
+ }
+
+ branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
+
+ n_descriptors = 4;
+ if(first_packet)
+ f->first_n_descriptors = n_descriptors;
+
+ full_packets++;
+ }
+ }
+
+ /* link this descriptor block into the DMA program by filling in
+ the branch address of the previous block */
+
+ /* note: we are not linked into the active DMA chain yet */
+
+ if(last_branch_address) {
+ *(last_branch_address) = block_dma | n_descriptors;
+ }
+
+ last_branch_address = branch_address;
+
+
+ f->n_packets++;
+
+ }
+
+ /* when we first assemble a new frame, set the final branch
+ to loop back up to the top */
+ *(f->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors;
+
+
+ /* make the latest version of the frame buffer visible to the PCI card */
+ /* could optimize this by only syncing the pages associated with this frame */
+ pci_dma_sync_sg(video->ohci->dev,
+ &video->user_dma.sglist[0],
+ video->user_dma.n_dma_pages,
+ PCI_DMA_TODEVICE);
+
+ /* lock against DMA interrupt */
+ spin_lock_irqsave(&video->spinlock, irq_flags);
+
+ f->state = FRAME_READY;
+
+ video->n_clear_frames--;
+
+ last_frame = video->first_clear_frame - 1;
+ if(last_frame == -1)
+ last_frame = video->n_frames-1;
+
+ video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+
+ irq_printk(" frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
+ this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
+
+ irq_printk(" begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
+ (unsigned long) f->frame_begin_timestamp,
+ (unsigned long) f->mid_frame_timestamp,
+ (unsigned long) f->frame_end_timestamp,
+ (unsigned long) f->frame_end_branch);
+
+ if(video->active_frame != -1) {
+
+ /* if DMA is already active, we are almost done */
+ /* just link us onto the active DMA chain */
+ if(video->frames[last_frame]->frame_end_branch) {
+
+ /* point the previous frame's tail to this frame's head */
+ *(video->frames[last_frame]->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors;
+
+ /* this write MUST precede the next one, or we could silently drop frames */
+ wmb();
+
+ /* disable the want_status semaphore on the last packet */
+ *(video->frames[last_frame]->frame_end_branch - 2) &= 0xF7CFFFFF;
+
+ /* flush these writes to memory ASAP */
+ flush_pci_write(video->ohci);
+
+ /* NOTE:
+ ideally the writes should be "atomic": if
+ the OHCI card reads the want_status flag in
+ between them, we'll falsely report a
+ dropped frame. Hopefully this window is too
+ small to really matter, and the consequence
+ is rather harmless. */
+
+
+ irq_printk(" new frame %d linked onto DMA chain\n", this_frame);
+
+ } else {
+ printk(KERN_ERR "dv1394: last frame not ready???\n");
+ }
+
+ } else {
+
+ u32 transmit_sec, transmit_cyc;
+ u32 ts_cyc, ts_off;
+
+ /* DMA is stopped, so this is the very first frame */
+ video->active_frame = this_frame;
+
+ /* set CommandPtr to address and size of first descriptor block */
+ reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
+ video->frames[video->active_frame]->descriptor_pool_dma |
+ f->first_n_descriptors);
+
+ /* assign a timestamp based on the current cycle time...
+ We'll tell the card to begin DMA 100 cycles from now,
+ and assign a timestamp 103 cycles from now */
+
+ cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
+
+ ct_sec = cycleTimer >> 25;
+ ct_cyc = (cycleTimer >> 12) & 0x1FFF;
+ ct_off = cycleTimer & 0xFFF;
+
+ transmit_sec = ct_sec;
+ transmit_cyc = ct_cyc + 100;
+
+ transmit_sec += transmit_cyc/8000;
+ transmit_cyc %= 8000;
+
+ ts_off = ct_off;
+ ts_cyc = transmit_cyc + 3;
+ ts_cyc %= 8000;
+
+ f->assigned_timestamp = (ts_cyc&0xF) << 12;
+
+ /* now actually write the timestamp into the appropriate CIP headers */
+ if(f->cip_syt1) {
+ f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
+ f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
+ }
+ if(f->cip_syt2) {
+ f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
+ f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
+ }
+
+ /* --- start DMA --- */
+
+ /* clear all bits in ContextControl register */
+
+ reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
+ wmb();
+
+ /* the OHCI card has the ability to start ISO transmission on a
+ particular cycle (start-on-cycle). This way we can ensure that
+ the first DV frame will have an accurate timestamp.
+
+ However, start-on-cycle only appears to work if the OHCI card
+ is cycle master! Since the consequences of messing up the first
+ timestamp are minimal*, just disable start-on-cycle for now.
+
+ * my DV deck drops the first few frames before it "locks in;"
+ so the first frame having an incorrect timestamp is inconsequential.
+ */
+
+#if 0
+ reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
+ (1 << 31) /* enable start-on-cycle */
+ | ( (transmit_sec & 0x3) << 29)
+ | (transmit_cyc << 16));
+ wmb();
+#endif
+
+
+
+ /* set the 'run' bit */
+ reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
+ flush_pci_write(video->ohci);
+
+ /* --- DMA should be running now --- */
+
+ debug_printk(" Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
+ (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
+ reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+ reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
+
+ debug_printk(" DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
+ ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
+
+#if DV1394_DEBUG_LEVEL >= 2
+ {
+ /* check if DMA is really running */
+ int i = 0;
+ while(i < 20) {
+ mb();
+ mdelay(1);
+ if(reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
+ printk("DMA ACTIVE after %d msec\n", i);
+ break;
+ }
+ i++;
+ }
+
+ printk("set = %08x, cmdPtr = %08x\n",
+ reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+ reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
+ );
+
+ if( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
+ printk("DMA did NOT go active after 20ms, event = %x\n",
+ reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
+ } else
+ printk("DMA is RUNNING!\n");
+ }
+#endif
+
+ }
+
+
+ spin_unlock_irqrestore(&video->spinlock, irq_flags);
+}
+
+
+
+/*** RECEIVE FUNCTIONS *****************************************************/
+
+/*
+ frame method put_packet
+
+ map and copy the packet data to its location in the frame
+ based upon DIF section and sequence
+*/
+
+static void inline
+frame_put_packet (struct frame *f, struct packet *p)
+{
+ int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */
+ int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */
+ int dif_block = p->data[2];
+
+ switch (section_type) {
+ case 0: /* 1 Header block */
+ memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
+ break;
+
+ case 1: /* 2 Subcode blocks */
+ memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
+ break;
+
+ case 2: /* 3 VAUX blocks */
+ memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
+ break;
+
+ case 3: /* 9 Audio blocks interleaved with video */
+ memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
+ break;
+
+ case 4: /* 135 Video blocks interleaved with audio */
+ memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
+ break;
+
+ default: /* we can not handle any other data */
+ break;
+ }
+}
+
+
+static void start_dma_receive(struct video_card *video, struct frame *frame)
+{
+ /* reset iso recv control register */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+ wmb();
+
+ /* clear bufferFill, set isochHeader and speed (0=100) */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+
+ /* match on all tags, listen on channel */
+ reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+
+ /* address and first descriptor block + Z=1 */
+ reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
+ frame->descriptor_pool_dma | 1); /* Z=1 */
+ wmb();
+
+ /* run */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+ flush_pci_write(video->ohci);
+
+ debug_printk("dv1394: DMA started\n");
+
+#if DV1394_DEBUG_LEVEL >= 2
+ {
+ int i;
+
+ for(i = 0; i < 1000; ++i) {
+ mdelay(1);
+ if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+ printk("DMA ACTIVE after %d msec\n", i);
+ break;
+ }
+ }
+ if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
+ printk("DEAD, event = %x\n",
+ reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+ } else
+ printk("RUNNING!\n");
+ }
+#endif
+}
+
+
+/*
+ receive_packets() - build the DMA program for receiving
+*/
+
+static void receive_packets(struct video_card *video, struct frame *f)
+{
+ struct DMA_descriptor_block *block = NULL;
+ dma_addr_t block_dma = 0;
+ struct packet *data = NULL;
+ dma_addr_t data_dma = 0;
+ u32 *last_branch_address = NULL;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&video->spinlock, irq_flags);
+
+ video->n_clear_frames = 0;
+ video->first_clear_frame = -1;
+
+ for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
+ /* locate a descriptor block and packet from the buffer */
+ block = &(f->descriptor_pool[video->current_packet]);
+ block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+
+ data = &(video->packet_buffer[video->current_packet]);
+ data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
+
+ /* setup DMA descriptor block */
+ fill_input_last( &(block->u.in.il), 512, data_dma);
+
+ /* link descriptors */
+ last_branch_address = f->frame_end_branch;
+
+ if (last_branch_address)
+ *(last_branch_address) = block_dma | 1; /* set Z=1 */
+
+ f->frame_end_branch = &(block->u.in.il.q[2]);
+ }
+
+ /* loop tail to head */
+ if (f->frame_end_branch)
+ *(f->frame_end_branch) = f->descriptor_pool_dma | 1; /* set Z=1 */
+
+ spin_unlock_irqrestore(&video->spinlock, irq_flags);
+
+ if (video->first_run) {
+ /* start DMA once all of the frames are READY */
+ video->first_run = 0;
+ video->current_packet = 0;
+ video->active_frame = f->frame_num;
+ start_dma_receive(video, f);
+ }
+ else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
+ debug_printk("DEAD, event = %x\n",
+ reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+ /* wake */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+ }
+}
+
+
+
+/*** MANAGEMENT FUNCTIONS **************************************************/
+
+static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
+{
+ unsigned long flags, new_buf_size;
+ int i;
+ u64 chan_mask;
+ int retval = -EINVAL;
+
+ if(init->api_version != DV1394_API_VERSION)
+ goto err;
+
+ /* first sanitize all the parameters */
+ if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
+ goto err;
+
+ if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
+ goto err;
+
+ if( (init->syt_offset == 0) || (init->syt_offset > 50) )
+ /* default SYT offset is 3 cycles */
+ init->syt_offset = 3;
+
+ if( (init->channel > 63) || (init->channel < 0) )
+ init->channel = 63;
+
+ chan_mask = (u64)1 << init->channel;
+
+ /* calculate what size DMA buffer is needed */
+ if(init->format == DV1394_NTSC)
+ new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
+ else
+ new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
+
+ /* round up to PAGE_SIZE */
+ if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
+
+ /* don't allow the user to allocate the DMA buffer more than once */
+ if( (video->user_buf) &&
+ (video->user_buf_size != new_buf_size) ) {
+ goto err;
+ }
+
+ /* shutdown the card if it's currently active */
+ /* (the card should not be reset if the parameters are screwy) */
+ if( video_card_initialized(video) )
+ do_dv1394_shutdown(video, 0);
+
+
+ /* try to claim the ISO channel */
+ spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+ if(video->ohci->ISO_channel_usage & chan_mask) {
+ spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+ retval = -EBUSY;
+ goto err;
+ }
+ video->ohci->ISO_channel_usage |= chan_mask;
+ spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+
+ video->channel = init->channel;
+
+
+ /* find and claim DMA contexts on the OHCI card */
+
+ if(video->ohci_it_ctx == -1) {
+
+ for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) {
+
+ if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) {
+ video->ohci_it_ctx = i;
+ debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+ break;
+ }
+ }
+
+ if(i == video->ohci->nb_iso_xmit_ctx) {
+ printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
+ retval = -EBUSY;
+ goto err_ctx;
+ }
+ }
+
+
+ if(video->ohci_ir_ctx == -1) {
+ for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) {
+
+ if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) {
+ video->ohci_ir_ctx = i;
+ debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+ break;
+ }
+ }
+
+ if(i == video->ohci->nb_iso_rcv_ctx) {
+ printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
+ retval = -EBUSY;
+ goto err_ctx;
+ }
+ }
+
+
+ /* allocate struct frames */
+ for(i = 0; i < init->n_frames; i++) {
+ video->frames[i] = frame_new(i, video);
+
+ if(!video->frames[i]) {
+ printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
+ retval = -ENOMEM;
+ goto err_frames;
+ }
+ }
+
+ /* initialize misc. fields of video */
+ video->n_frames = init->n_frames;
+ video->pal_or_ntsc = init->format;
+
+
+ video->cip_accum = 0;
+ video->continuity_counter = 0;
+
+ video->active_frame = -1;
+ video->first_clear_frame = 0;
+ video->n_clear_frames = video->n_frames;
+ video->dropped_frames = 0;
+
+ video->write_off = 0;
+
+ video->first_run = 1;
+ video->current_packet = -1;
+ video->first_frame = 0;
+
+
+ if(video->pal_or_ntsc == DV1394_NTSC) {
+ video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
+ video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
+ video->frame_size = DV1394_NTSC_FRAME_SIZE;
+ } else {
+ video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
+ video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
+ video->frame_size = DV1394_PAL_FRAME_SIZE;
+ }
+
+ video->syt_offset = init->syt_offset;
+
+ if(video->user_buf == NULL) {
+ unsigned int i;
+
+ /* allocate the ringbuffer */
+ video->user_buf = rvmalloc(new_buf_size);
+ if(!video->user_buf) {
+ printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
+ goto err_frames;
+ }
+ video->user_buf_size = new_buf_size;
+
+ /* allocate the sglist to hold the DMA addresses */
+ video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
+ video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
+ if(!video->user_dma.sglist) {
+ printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
+ goto err_user_buf;
+ }
+
+ /* initialize all fields of all sglist entries to zero
+ (new requirement due to PCI changes in 2.4.13) */
+
+ memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+
+
+ /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
+ for(i = 0; i < video->user_dma.n_pages; i++) {
+ unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE );
+
+ video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va);
+ video->user_dma.sglist[i].length = PAGE_SIZE;
+ }
+
+ /* map the buffer in the IOMMU */
+ /* the user_data buffer only allows DMA *to* the card for transmission;
+ incoming DV data comes through the packet_buffer first, and then is copied to user_data */
+ video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
+ &video->user_dma.sglist[0],
+ video->user_dma.n_pages,
+ PCI_DMA_TODEVICE);
+ if(video->user_dma.n_dma_pages == 0) {
+ printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
+ goto err_user_buf;
+ }
+
+ debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n",
+ video->n_frames, video->user_dma.n_pages,
+ video->user_dma.n_dma_pages, video->user_buf_size);
+ }
+
+ /* set up the frame->data pointers */
+ for(i = 0; i < video->n_frames; i++)
+ video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+
+ /* allocate packet buffers */
+ video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
+ if (video->packet_buffer_size % PAGE_SIZE)
+ video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
+
+
+ video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
+
+ if(!video->packet_buffer) {
+ printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
+ retval = -ENOMEM;
+ goto err_user_buf;
+ }
+
+ /* map the packet buffer into the IOMMU */
+ video->packet_buffer_dma = pci_map_single(video->ohci->dev,
+ video->packet_buffer,
+ video->packet_buffer_size,
+ PCI_DMA_FROMDEVICE);
+ if(!video->packet_buffer_dma) {
+ printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
+ kfree(video->packet_buffer);
+ video->packet_buffer = NULL;
+ retval = -ENOMEM;
+ goto err_user_buf;
+ }
+
+ debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n",
+ MAX_PACKET_BUFFER, video->packet_buffer_size);
+
+
+ /* set up register offsets for IT context */
+ /* IT DMA context registers are spaced 16 bytes apart */
+ video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
+ video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
+ video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
+
+ /* enable interrupts for IT context */
+ reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
+ debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
+
+ /* set up register offsets for IR context */
+ /* IR DMA context registers are spaced 32 bytes apart */
+ video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
+ video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
+ video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
+ video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
+
+ /* enable interrupts for IR context */
+ reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
+ debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
+
+ return 0;
+
+ err_user_buf:
+ if(video->user_buf) {
+ if(video->user_dma.sglist) {
+ if(video->user_dma.n_dma_pages > 0) {
+ /* unmap it from the IOMMU */
+ pci_unmap_sg(video->ohci->dev,
+ video->user_dma.sglist,
+ video->user_dma.n_pages,
+ PCI_DMA_TODEVICE);
+ video->user_dma.n_dma_pages = 0;
+ }
+ kfree(video->user_dma.sglist);
+ video->user_dma.sglist = NULL;
+ video->user_dma.n_pages = 0;
+ }
+ rvfree(video->user_buf, video->user_buf_size);
+ video->user_buf = NULL;
+ video->user_buf_size = 0;
+ }
+
+ err_frames:
+ for(i = 0; i < DV1394_MAX_FRAMES; i++) {
+ if(video->frames[i])
+ frame_delete(video->frames[i]);
+ }
+ video->n_frames = 0;
+
+ err_ctx:
+ if(video->ohci_it_ctx != -1) {
+ clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+ video->ohci_it_ctx = -1;
+ }
+ if(video->ohci_ir_ctx != -1) {
+ clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+ video->ohci_ir_ctx = -1;
+ }
+
+ spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+ video->ohci->ISO_channel_usage &= ~chan_mask;
+ spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+ err:
+ return retval;
+}
+
+/* if the user doesn't bother to call ioctl(INIT) before starting
+ mmap() or read()/write(), just give him some default values */
+
+static int do_dv1394_init_default(struct video_card *video)
+{
+ struct dv1394_init init;
+
+ init.api_version = DV1394_API_VERSION;
+ init.channel = 63;
+ init.n_frames = 2;
+ /* the following are now set via proc_fs */
+ init.format = video->pal_or_ntsc;
+ init.cip_n = video->cip_n;
+ init.cip_d = video->cip_d;
+ init.syt_offset = video->syt_offset;
+
+ return do_dv1394_init(video, &init);
+}
+
+/* do NOT call from interrupt context */
+static void stop_dma(struct video_card *video)
+{
+ unsigned long flags;
+ int i;
+
+ /* no interrupts */
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ /* stop DMA if in progress */
+ if( (video->active_frame != -1) ||
+ (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
+ (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
+
+ /* clear the .run bits */
+ reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
+ flush_pci_write(video->ohci);
+
+ video->active_frame = -1;
+ video->first_run = 1;
+
+
+ /* wait until DMA really stops */
+ i = 0;
+ while(i < 1000) {
+
+ /* wait 0.1 millisecond */
+ udelay(100);
+
+ if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
+ (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
+ /* still active */
+ mb();
+ } else {
+ debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
+ break;
+ }
+
+ i++;
+ }
+
+ if(i == 1000) {
+ printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
+ }
+ }
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+}
+
+
+
+static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
+{
+ int i;
+
+ debug_printk("dv1394: shutdown...\n");
+
+ /* stop DMA if in progress */
+ stop_dma(video);
+
+ /* release the ISO channel */
+ if(video->channel != -1) {
+ u64 chan_mask;
+ unsigned long flags;
+
+ chan_mask = (u64)1 << video->channel;
+
+ spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+ video->ohci->ISO_channel_usage &= ~(chan_mask);
+ spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+
+ video->channel = -1;
+ }
+
+ /* release the DMA contexts */
+ if(video->ohci_it_ctx != -1) {
+ video->ohci_IsoXmitContextControlSet = 0;
+ video->ohci_IsoXmitContextControlClear = 0;
+ video->ohci_IsoXmitCommandPtr = 0;
+
+ /* disable interrupts for IT context */
+ reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
+
+ clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+ debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
+ video->ohci_it_ctx = -1;
+ }
+
+ if(video->ohci_ir_ctx != -1) {
+ video->ohci_IsoRcvContextControlSet = 0;
+ video->ohci_IsoRcvContextControlClear = 0;
+ video->ohci_IsoRcvCommandPtr = 0;
+ video->ohci_IsoRcvContextMatch = 0;
+
+ /* disable interrupts for IR context */
+ reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
+
+ clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+ debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
+ video->ohci_ir_ctx = -1;
+ }
+
+ /* free the frame structs */
+ for(i = 0; i < DV1394_MAX_FRAMES; i++) {
+ if(video->frames[i])
+ frame_delete(video->frames[i]);
+ video->frames[i] = NULL;
+ }
+
+ video->n_frames = 0;
+
+ /* we can't free the DMA buffer unless it is guaranteed that
+ no more user-space mappings exist */
+
+ if(free_user_buf && video->user_buf) {
+ if(video->user_dma.sglist) {
+ if(video->user_dma.n_dma_pages > 0) {
+ /* unmap it from the IOMMU */
+ pci_unmap_sg(video->ohci->dev,
+ video->user_dma.sglist,
+ video->user_dma.n_pages,
+ PCI_DMA_TODEVICE);
+ video->user_dma.n_dma_pages = 0;
+ }
+ kfree(video->user_dma.sglist);
+ video->user_dma.sglist = NULL;
+ video->user_dma.n_pages = 0;
+ }
+ rvfree(video->user_buf, video->user_buf_size);
+ video->user_buf = NULL;
+ video->user_buf_size = 0;
+ }
+
+ if (video->packet_buffer) {
+ pci_unmap_single(video->ohci->dev,
+ video->packet_buffer_dma,
+ video->packet_buffer_size,
+ PCI_DMA_FROMDEVICE);
+ kfree(video->packet_buffer);
+ video->packet_buffer = NULL;
+ video->packet_buffer_size = 0;
+ }
+
+ debug_printk("dv1394: shutdown complete\n");
+
+ return 0;
+}
+
+
+
+/*
+ **********************************
+ *** MMAP() THEORY OF OPERATION ***
+ **********************************
+
+ The ringbuffer cannot be re-allocated or freed while
+ a user program maintains a mapping of it. (note that a mapping
+ can persist even after the device fd is closed!)
+
+ So, only let the user process allocate the DMA buffer once.
+ To resize or deallocate it, you must close the device file
+ and open it again.
+
+ Previously Dan M. hacked out a scheme that allowed the DMA
+ buffer to change by forcefully unmapping it from the user's
+ address space. It was prone to error because it's very hard to
+ track all the places the buffer could have been mapped (we
+ would have had to walk the vma list of every process in the
+ system to be sure we found all the mappings!). Instead, we
+ force the user to choose one buffer size and stick with
+ it. This small sacrifice is worth the huge reduction in
+ error-prone code in dv1394.
+
+ Note: dv1394_mmap does no page table manipulation. The page
+ table entries are created by the dv1394_nopage() handler as
+ page faults are taken by the user.
+*/
+
+static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
+{
+ unsigned long offset;
+ unsigned long page, kernel_virt_addr;
+ struct page *ret = NOPAGE_SIGBUS;
+
+ struct video_card *video = (struct video_card*) area->vm_private_data;
+
+ /* guard against process-context operations and the interrupt */
+ /* (by definition page faults are taken in interrupt context) */
+ spin_lock(&video->spinlock);
+
+ if(!video->user_buf)
+ goto out;
+
+ if( (address < (unsigned long) area->vm_start) ||
+ (address > (unsigned long) area->vm_start + video->user_buf_size) )
+ goto out;
+
+ offset = address - area->vm_start;
+ kernel_virt_addr = (unsigned long) video->user_buf + offset;
+
+ page = kvirt_to_pa(kernel_virt_addr);
+
+ ret = virt_to_page(__va(page));
+ get_page(ret);
+
+ out:
+ spin_unlock(&video->spinlock);
+ return ret;
+}
+
+static struct vm_operations_struct dv1394_vm_ops = {
+ nopage: dv1394_nopage
+};
+
+/*
+ dv1394_mmap does no page table manipulation. The page table entries
+ are created by the dv1394_nopage() handler as page faults are taken
+ by the user.
+*/
+
+int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_card *video = file_to_video_card(file);
+ unsigned long size;
+ int res = -EINVAL;
+
+ /* serialize mmap */
+ down(&video->sem);
+
+ if( ! video_card_initialized(video) ) {
+ res = do_dv1394_init_default(video);
+ if(res)
+ goto err;
+ }
+
+ /* region must be page-aligned */
+ if(vma->vm_pgoff != 0)
+ goto err;
+
+ /* check the size the user is trying to map */
+ size = vma->vm_end - vma->vm_start;
+ if(size > video->user_buf_size)
+ goto err;
+
+ /*
+ we don't actually mess with the page tables here.
+ (nopage() takes care of that from the page fault handler)
+ Just set up the vma->vm_ops.
+ */
+
+ vma->vm_ops = &dv1394_vm_ops;
+ vma->vm_private_data = video;
+ vma->vm_file = file;
+
+ /* don't try to swap this out =) */
+ vma->vm_flags |= VM_RESERVED;
+
+ up(&video->sem);
+ return 0;
+ err:
+ up(&video->sem);
+ return res;
+}
+
+
+/*** DEVICE FILE INTERFACE *************************************************/
+
+/* no need to serialize, multiple threads OK */
+static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct video_card *video = file_to_video_card(file);
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(file, &video->waitq, wait);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+ if( video->n_frames == 0 ) {
+
+ } else if( video->active_frame == -1 ) {
+ /* nothing going on */
+ mask |= POLLOUT;
+ } else {
+ /* any clear/ready buffers? */
+ if(video->n_clear_frames >0)
+ mask |= POLLOUT | POLLIN;
+ }
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ return mask;
+}
+
+static int dv1394_fasync(int fd, struct file *file, int on)
+{
+ /* I just copied this code verbatim from Alan Cox's mouse driver example
+ (linux/Documentation/DocBook/) */
+
+ struct video_card *video = file_to_video_card(file);
+
+ int retval = fasync_helper(fd, file, on, &video->fasync);
+
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static ssize_t dv1394_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct video_card *video = file_to_video_card(file);
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t ret;
+ size_t cnt;
+ unsigned long flags;
+ int target_frame;
+
+ /* serialize this to prevent multi-threaded mayhem */
+ if(file->f_flags & O_NONBLOCK) {
+ if(down_trylock(&video->sem))
+ return -EAGAIN;
+ } else {
+ if(down_interruptible(&video->sem))
+ return -ERESTARTSYS;
+ }
+
+ if( !video_card_initialized(video) ) {
+ ret = do_dv1394_init_default(video);
+ if(ret) {
+ up(&video->sem);
+ return ret;
+ }
+ }
+
+ ret = 0;
+ add_wait_queue(&video->waitq, &wait);
+
+ while(count > 0) {
+
+ /* must set TASK_INTERRUPTIBLE *before* checking for free
+ buffers; otherwise we could miss a wakeup if the interrupt
+ fires between the check and the schedule() */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ target_frame = video->first_clear_frame;
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ if(video->frames[target_frame]->state == FRAME_CLEAR) {
+
+ /* how much room is left in the target frame buffer */
+ cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
+
+ } else {
+ /* buffer is already used */
+ cnt = 0;
+ }
+
+ if(cnt > count)
+ cnt = count;
+
+ if (cnt <= 0) {
+ /* no room left, gotta wait */
+ if(file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ schedule();
+
+ continue; /* start over from 'while(count > 0)...' */
+ }
+
+ if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) {
+ if(!ret)
+ ret = -EFAULT;
+ break;
+ }
+
+ video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
+
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+
+ if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
+ frame_prepare(video, target_frame);
+ }
+
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+ up(&video->sem);
+ return ret;
+}
+
+
+static ssize_t dv1394_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct video_card *video = file_to_video_card(file);
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t ret;
+ size_t cnt;
+ unsigned long flags;
+ int target_frame;
+
+ /* serialize this to prevent multi-threaded mayhem */
+ if(file->f_flags & O_NONBLOCK) {
+ if(down_trylock(&video->sem))
+ return -EAGAIN;
+ } else {
+ if(down_interruptible(&video->sem))
+ return -ERESTARTSYS;
+ }
+
+ if( !video_card_initialized(video) ) {
+ ret = do_dv1394_init_default(video);
+ if(ret) {
+ up(&video->sem);
+ return ret;
+ }
+ receive_packets(video, video->frames[video->first_clear_frame]);
+ }
+
+ ret = 0;
+ add_wait_queue(&video->waitq, &wait);
+
+ while(count > 0) {
+
+ /* must set TASK_INTERRUPTIBLE *before* checking for free
+ buffers; otherwise we could miss a wakeup if the interrupt
+ fires between the check and the schedule() */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ target_frame = video->first_clear_frame;
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ if(target_frame >= 0 &&
+ video->n_clear_frames > 0 &&
+ video->frames[target_frame]->state == FRAME_CLEAR) {
+
+ /* how much room is left in the target frame buffer */
+ cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
+
+ } else {
+ /* buffer is already used */
+ cnt = 0;
+ }
+
+ if(cnt > count)
+ cnt = count;
+
+ if (cnt <= 0) {
+ /* no room left, gotta wait */
+ if(file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ schedule();
+
+ continue; /* start over from 'while(count > 0)...' */
+ }
+
+ if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) {
+ if(!ret)
+ ret = -EFAULT;
+ break;
+ }
+
+ video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
+
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+
+ if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
+ spin_lock_irqsave(&video->spinlock, flags);
+ video->n_clear_frames--;
+ video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+ spin_unlock_irqrestore(&video->spinlock, flags);
+ }
+ }
+
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+ up(&video->sem);
+ return ret;
+}
+
+
+/*** DEVICE IOCTL INTERFACE ************************************************/
+
+/* I *think* the VFS serializes ioctl() for us, so we don't have to worry
+ about situations like having two threads in here at once... */
+
+static int dv1394_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_card *video = file_to_video_card(file);
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* serialize this to prevent multi-threaded mayhem */
+ if(file->f_flags & O_NONBLOCK) {
+ if(down_trylock(&video->sem))
+ return -EAGAIN;
+ } else {
+ if(down_interruptible(&video->sem))
+ return -ERESTARTSYS;
+ }
+
+ switch(cmd)
+ {
+ case DV1394_SUBMIT_FRAMES: {
+ unsigned int n_submit;
+
+ if( !video_card_initialized(video) ) {
+ ret = do_dv1394_init_default(video);
+ if(ret)
+ goto out;
+ }
+
+ n_submit = (unsigned int) arg;
+
+ if(n_submit > video->n_frames) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ while(n_submit > 0) {
+
+ add_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ /* wait until video->first_clear_frame is really CLEAR */
+ while(video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ if(signal_pending(current)) {
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+ ret = -EINTR;
+ goto out;
+ }
+
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+ }
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ frame_prepare(video, video->first_clear_frame);
+
+ n_submit--;
+ }
+
+ ret = 0;
+ break;
+ }
+
+ case DV1394_WAIT_FRAMES: {
+ unsigned int n_wait;
+
+ if( !video_card_initialized(video) ) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ n_wait = (unsigned int) arg;
+
+ /* since we re-run the last frame on underflow, we will
+ never actually have n_frames clear frames; at most only
+ n_frames - 1 */
+
+ if(n_wait > (video->n_frames-1) ) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ add_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ while(video->n_clear_frames < n_wait) {
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ if(signal_pending(current)) {
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+ ret = -EINTR;
+ goto out;
+ }
+
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&video->spinlock, flags);
+ }
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ remove_wait_queue(&video->waitq, &wait);
+ set_current_state(TASK_RUNNING);
+ ret = 0;
+ break;
+ }
+
+ case DV1394_RECEIVE_FRAMES: {
+ unsigned int n_recv;
+
+ if( !video_card_initialized(video) ) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ n_recv = (unsigned int) arg;
+
+ /* at least one frame must be active */
+ if(n_recv > (video->n_frames-1) ) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ /* release the clear frames */
+ video->n_clear_frames -= n_recv;
+
+ /* advance the clear frame cursor */
+ video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
+
+ /* reset dropped_frames */
+ video->dropped_frames = 0;
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ ret = 0;
+ break;
+ }
+
+ case DV1394_START_RECEIVE: {
+
+ if( !video_card_initialized(video) ) {
+ ret = do_dv1394_init_default(video);
+ if(ret)
+ goto out;
+ }
+
+ receive_packets(video, video->frames[video->first_clear_frame]);
+
+ ret = 0;
+ break;
+ }
+
+ case DV1394_INIT: {
+ struct dv1394_init init;
+ if(arg == (unsigned long) NULL) {
+ ret = do_dv1394_init_default(video);
+ } else {
+ if(copy_from_user(&init, (void*)arg, sizeof(init))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = do_dv1394_init(video, &init);
+ }
+ break;
+ }
+
+ case DV1394_SHUTDOWN:
+ ret = do_dv1394_shutdown(video, 0);
+ break;
+
+
+ case DV1394_GET_STATUS: {
+ struct dv1394_status status;
+
+ if( !video_card_initialized(video) ) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ status.init.api_version = DV1394_API_VERSION;
+ status.init.channel = video->channel;
+ status.init.n_frames = video->n_frames;
+ status.init.format = video->pal_or_ntsc;
+ status.init.cip_n = video->cip_n;
+ status.init.cip_d = video->cip_d;
+ status.init.syt_offset = video->syt_offset;
+
+ status.first_clear_frame = video->first_clear_frame;
+
+ /* the rest of the fields need to be locked against the interrupt */
+ spin_lock_irqsave(&video->spinlock, flags);
+
+ status.active_frame = video->active_frame;
+ status.n_clear_frames = video->n_clear_frames;
+
+ status.dropped_frames = video->dropped_frames;
+
+ /* reset dropped_frames */
+ video->dropped_frames = 0;
+
+ spin_unlock_irqrestore(&video->spinlock, flags);
+
+ if(copy_to_user((void*)arg, &status, sizeof(status))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = 0;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ out:
+ up(&video->sem);
+ return ret;
+}
+
+
+
+/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
+
+static int dv1394_open(struct inode *inode, struct file *file)
+{
+ struct video_card *video = NULL;
+
+ /* if the device was opened through devfs, then file->private_data
+ has already been set to video by devfs */
+ if(file->private_data) {
+ video = (struct video_card*) file->private_data;
+
+ } else {
+ /* look up the card by ID */
+
+ struct list_head *lh;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dv1394_cards_lock, flags);
+ if(!list_empty(&dv1394_cards)) {
+ struct video_card *p;
+ list_for_each(lh, &dv1394_cards) {
+ p = list_entry(lh, struct video_card, list);
+ if(p->id == ieee1394_file_to_instance(file)) {
+ video = p;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+ if(!video) {
+ debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file));
+ return -ENODEV;
+ }
+
+ file->private_data = (void*) video;
+ }
+
+#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
+
+ if( test_and_set_bit(0, &video->open) ) {
+ /* video is already open by someone else */
+ return -EBUSY;
+ }
+
+#endif
+
+ V22_COMPAT_MOD_INC_USE_COUNT;
+ return 0;
+}
+
+
+static int dv1394_release(struct inode *inode, struct file *file)
+{
+ struct video_card *video = file_to_video_card(file);
+
+ /* OK to free the DMA buffer, no more mappings can exist */
+ do_dv1394_shutdown(video, 1);
+
+ /* clean up async I/O users */
+ dv1394_fasync(-1, file, 0);
+
+ /* give someone else a turn */
+ clear_bit(0, &video->open);
+
+ V22_COMPAT_MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+/*** PROC_FS INTERFACE ******************************************************/
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *dv1394_procfs_entry;
+
+static int dv1394_procfs_read( char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct video_card *video = (struct video_card*) data;
+
+ V22_COMPAT_MOD_INC_USE_COUNT;
+ snprintf( page, count,
+ "\
+dv1394 settings for host %d:\n\
+----------------------------\n\
+format=%s\n\
+cip_n=%lu\n\
+cip_d=%lu\n\
+syt_offset=%u\n",
+ video->id,
+ (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+ video->cip_n, video->cip_d, video->syt_offset );
+ V22_COMPAT_MOD_DEC_USE_COUNT;
+ return strlen(page);
+}
+#endif /* CONFIG_PROC_FS */
+
+/* lifted from the stallion.c driver */
+#undef TOLOWER
+#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
+static unsigned long atol(char *str)
+{
+ unsigned long val;
+ int base, c;
+ char *sp;
+
+ val = 0;
+ sp = str;
+ if ((*sp == '0') && (*(sp+1) == 'x')) {
+ base = 16;
+ sp += 2;
+ } else if (*sp == '0') {
+ base = 8;
+ sp++;
+ } else {
+ base = 10;
+ }
+
+ for (; (*sp != 0); sp++) {
+ c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
+ if ((c < 0) || (c >= base)) {
+ printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str);
+ val = 0;
+ break;
+ }
+ val = (val * base) + c;
+ }
+ return(val);
+}
+
+#ifdef CONFIG_PROC_FS
+static int dv1394_procfs_write( struct file *file,
+ const char *buffer, unsigned long count, void *data)
+{
+ int len = 0;
+ char new_value[64];
+ char *pos;
+ struct video_card *video = (struct video_card*) data;
+
+ V22_COMPAT_MOD_INC_USE_COUNT;
+
+ if (count > 64)
+ len = 64;
+ else
+ len = count;
+
+ if (copy_from_user( new_value, buffer, len)) {
+ V22_COMPAT_MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+
+ pos = strchr(new_value, '=');
+ if (pos != NULL) {
+ int val_len = len - (pos-new_value) - 1;
+ char buf[64];
+ memset(buf, 0, 64);
+ strncpy(buf, pos+1, val_len);
+ if (buf[val_len-1] == '\n') buf[val_len-1] = 0;
+
+ if (strnicmp( new_value, "format", (pos-new_value)) == 0) {
+ if (strnicmp( buf, "NTSC", val_len) == 0)
+ video->pal_or_ntsc = DV1394_NTSC;
+ else if (strnicmp( buf, "PAL", val_len) == 0)
+ video->pal_or_ntsc = DV1394_PAL;
+
+ } else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) {
+ video->cip_n = atol(buf);
+ } else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) {
+ video->cip_d = atol(buf);
+ } else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) {
+ video->syt_offset = atol(buf);
+ }
+ }
+
+ V22_COMPAT_MOD_DEC_USE_COUNT;
+ return len;
+}
+
+static int dv1394_procfs_add_entry(struct video_card *video)
+{
+ struct proc_dir_entry *procfs_entry = NULL;
+ char buf[16];
+
+ snprintf(buf, sizeof(buf), "%d", video->id);
+
+ procfs_entry = create_proc_entry( buf, 0666, dv1394_procfs_entry);
+ if (procfs_entry == NULL) {
+ printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv/X\n");
+ return -ENOMEM;
+ }
+ procfs_entry->owner = THIS_MODULE;
+ procfs_entry->data = video;
+ procfs_entry->read_proc = dv1394_procfs_read;
+ procfs_entry->write_proc = dv1394_procfs_write;
+
+ return 0;
+}
+#endif /* CONFIG_PROC_FS */
+
+/*** DEVICE DRIVER HANDLERS ************************************************/
+
+static void irq_handler(int card, quadlet_t isoRecvIntEvent,
+ quadlet_t isoXmitIntEvent, void *data)
+{
+ int wake = 0;
+ struct video_card *video = (struct video_card*) data;
+
+ irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
+ (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
+ irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
+ reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+ reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
+ );
+
+
+ if( (video->ohci_it_ctx != -1) &&
+ (isoXmitIntEvent & (1 << video->ohci_it_ctx)) &&
+ (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
+
+ struct frame *f;
+ unsigned int frame, i;
+
+ spin_lock(&video->spinlock);
+ if(video->active_frame == -1)
+ frame = 0;
+ else
+ frame = video->active_frame;
+
+ /* check all the DMA-able frames */
+ for(i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
+
+ irq_printk("IRQ checking frame %d...", frame);
+ f = video->frames[frame];
+ if(f->state != FRAME_READY) {
+ irq_printk("clear, skipping\n");
+ /* we don't own this frame */
+ continue;
+ }
+
+ irq_printk("DMA\n");
+
+ /* check the frame begin semaphore to see if we can free the previous frame */
+ if( *(f->frame_begin_timestamp) ) {
+ int prev_frame;
+ struct frame *prev_f;
+
+
+
+ /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
+ irq_printk(" BEGIN\n");
+
+ prev_frame = frame - 1;
+ if(prev_frame == -1)
+ prev_frame += video->n_frames;
+ prev_f = video->frames[prev_frame];
+
+ /* make sure we can actually garbage collect
+ this frame */
+ if( (prev_f->state == FRAME_READY) &&
+ prev_f->done && (!f->done) )
+ {
+ frame_reset(prev_f);
+ video->n_clear_frames++;
+ wake = 1;
+ video->active_frame = frame;
+
+ irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
+ } else {
+ irq_printk(" BEGIN - can't free yet\n");
+ }
+
+ f->done = 1;
+ }
+
+
+ /* see if we need to set the timestamp for the next frame */
+ if( *(f->mid_frame_timestamp) ) {
+ struct frame *next_frame;
+ u32 ts_cyc, ts_off;
+
+ *(f->mid_frame_timestamp) = 0;
+
+ irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
+ *(f->frame_begin_timestamp) & 0x1FFF, *(f->frame_begin_timestamp) & 0xF,
+ f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
+
+ /* prepare next frame and assign timestamp */
+ next_frame = video->frames[ (frame+1) % video->n_frames ];
+
+ if(next_frame->state == FRAME_READY) {
+ irq_printk(" MIDDLE - next frame is ready, good\n");
+ } else {
+ debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
+ next_frame = f;
+ }
+
+ /* set the timestamp to the timestamp of the last frame sent,
+ plus the length of the last frame sent, plus the syt latency */
+ ts_cyc = *(f->frame_begin_timestamp) & 0xF;
+ /* advance one frame, plus syt latency (typically 2-3) */
+ ts_cyc += f->n_packets + video->syt_offset ;
+
+ ts_off = 0;
+
+ ts_cyc += ts_off/3072;
+ ts_off %= 3072;
+
+ next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
+ if(next_frame->cip_syt1) {
+ next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
+ next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
+ }
+ if(next_frame->cip_syt2) {
+ next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
+ next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
+ }
+
+ }
+
+ /* see if the frame looped */
+ if( *(f->frame_end_timestamp) ) {
+
+ *(f->frame_end_timestamp) = 0;
+
+ debug_printk(" END - the frame looped at least once\n");
+
+ video->dropped_frames++;
+ }
+
+
+
+ } /* for(each frame) */
+
+ spin_unlock(&video->spinlock);
+
+ } /* end XMIT portion */
+
+ /***** RECEIVE INTERRUPT and DMA ACTIVE *****/
+
+ else if( (video->ohci_ir_ctx != -1) &&
+ (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) &&
+ (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {
+
+ int sof=0; /* start-of-frame flag */
+ struct frame *f;
+
+ spin_lock(&video->spinlock);
+
+ irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
+ video->packet_buffer[video->current_packet].timestamp, video->packet_buffer[video->current_packet].data_length,
+ video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
+
+ f = video->frames[video->active_frame];
+
+ /* exclude empty packet */
+ if (video->packet_buffer[video->current_packet].data_length > 8) {
+
+ /* check for start of frame */
+ sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
+ video->packet_buffer[video->current_packet].data[1] == 0x07);
+
+ if (!video->first_frame) {
+ if (sof) {
+ video->first_frame = 1;
+ }
+
+ } else if (sof) {
+ /* close current frame */
+ frame_reset(f); /* f->state = STATE_CLEAR */
+ video->n_clear_frames++;
+ if (video->n_clear_frames > video->n_frames) {
+ video->n_clear_frames = video->n_frames;
+ video->dropped_frames++;
+ }
+ if (video->first_clear_frame == -1)
+ video->first_clear_frame = video->active_frame;
+
+ /* get the next frame */
+ video->active_frame = (video->active_frame + 1) % video->n_frames;
+ f = video->frames[video->active_frame];
+
+ irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
+ video->active_frame, video->n_clear_frames, video->first_clear_frame);
+ }
+ if (video->first_frame) {
+ if (sof) {
+ /* open next frame */
+ f->state = FRAME_READY;
+ }
+
+ /* copy to buffer */
+ if (f->n_packets > (video->frame_size / 480)) {
+ printk(KERN_ERR "frame buffer overflow during receive\n");
+ }
+
+ /* make sure we are seeing the latest changes to packet_buffer */
+ pci_dma_sync_single(video->ohci->dev,
+ video->packet_buffer_dma,
+ video->packet_buffer_size,
+ PCI_DMA_FROMDEVICE);
+
+ frame_put_packet( f, &video->packet_buffer[video->current_packet]);
+
+ } /* first_frame */
+
+ } /* not empty packet */
+
+ /* advance packet_buffer cursor */
+ video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
+
+ spin_unlock(&video->spinlock);
+
+ wake = 1; /* why the hell not? */
+
+ } /* receive interrupt */
+
+ if(wake) {
+
+ /* send SIGIO */
+
+ if(isoRecvIntEvent & (1))
+ kill_fasync(&video->fasync, SIGIO, POLL_IN);
+
+ if(isoXmitIntEvent & (1))
+ kill_fasync(&video->fasync, SIGIO, POLL_OUT);
+
+ /* wake readers/writers/ioctl'ers */
+ wake_up_interruptible(&video->waitq);
+ }
+}
+
+static struct file_operations dv1394_fops=
+{
+ OWNER_THIS_MODULE
+ poll: dv1394_poll,
+ ioctl: dv1394_ioctl,
+ mmap: dv1394_mmap,
+ open: dv1394_open,
+ write: dv1394_write,
+ read: dv1394_read,
+ release: dv1394_release,
+ fasync: dv1394_fasync,
+};
+
+
+static int dv1394_init(struct ti_ohci *ohci)
+{
+ struct video_card *video;
+ unsigned long flags;
+ char buf[16];
+ int i;
+
+ video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
+ if(!video) {
+ printk(KERN_ERR "dv1394: cannot allocate video_card\n");
+ goto err;
+ }
+
+ memset(video, 0, sizeof(struct video_card));
+
+ if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
+ printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n");
+ goto err_free;
+ }
+
+
+ video->ohci = ohci;
+ video->id = ohci->id;
+
+ if ( dv1394_procfs_add_entry(video) < 0 )
+ goto err_free;
+
+ video->ohci_it_ctx = -1;
+ video->ohci_ir_ctx = -1;
+
+ video->ohci_IsoXmitContextControlSet = 0;
+ video->ohci_IsoXmitContextControlClear = 0;
+ video->ohci_IsoXmitCommandPtr = 0;
+
+ video->ohci_IsoRcvContextControlSet = 0;
+ video->ohci_IsoRcvContextControlClear = 0;
+ video->ohci_IsoRcvCommandPtr = 0;
+ video->ohci_IsoRcvContextMatch = 0;
+
+ video->n_frames = 0; /* flag that video is not initialized */
+ video->channel = -1;
+ video->active_frame = -1;
+
+ /* initialize the following for proc_fs */
+ video->pal_or_ntsc = DV1394_NTSC;
+ video->cip_n = 0; /* 0 = use builtin default */
+ video->cip_d = 0;
+ video->syt_offset = 0;
+
+ for(i = 0; i < DV1394_MAX_FRAMES; i++)
+ video->frames[i] = NULL;
+
+ video->user_buf = NULL;
+ video->user_buf_size = 0;
+
+ clear_bit(0, &video->open);
+ spin_lock_init(&video->spinlock);
+ init_MUTEX(&video->sem);
+ init_waitqueue_head(&video->waitq);
+ video->fasync = NULL;
+
+ spin_lock_irqsave(&dv1394_cards_lock, flags);
+ INIT_LIST_HEAD(&video->list);
+ list_add_tail(&video->list, &dv1394_cards);
+ spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+ snprintf(buf, sizeof(buf), "%d", video->id);
+
+ video->devfs_handle = devfs_register(dv1394_devfs_handle,
+ buf, DEVFS_FL_NONE,
+ IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ &dv1394_fops,
+ (void*) video);
+
+ debug_printk("dv1394: dv1394_init() OK on ID %d\n", ohci->id);
+
+ return 0;
+
+ err_free:
+ kfree(video);
+ err:
+ return -1;
+}
+
+static void dv1394_un_init(struct video_card *video)
+{
+ unsigned long flags;
+
+ /* obviously nobody has the driver open at this point */
+ do_dv1394_shutdown(video, 1);
+ ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
+ if(video->devfs_handle)
+ devfs_unregister(video->devfs_handle);
+
+ spin_lock_irqsave(&dv1394_cards_lock, flags);
+ list_del(&video->list);
+ spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+ kfree(video);
+}
+
+
+static void dv1394_remove_host (struct hpsb_host *host)
+{
+ struct ti_ohci *ohci;
+ struct video_card *video = NULL;
+ unsigned long flags;
+ struct list_head *lh;
+
+ /* We only work with the OHCI-1394 driver */
+ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+ return;
+
+ ohci = (struct ti_ohci *)host->hostdata;
+
+
+ /* find the corresponding video_card */
+ spin_lock_irqsave(&dv1394_cards_lock, flags);
+ if(!list_empty(&dv1394_cards)) {
+ struct video_card *p;
+ list_for_each(lh, &dv1394_cards) {
+ p = list_entry(lh, struct video_card, list);
+ if(p->id == ohci->id) {
+ video = p;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+ if(video) {
+ char buf[16];
+ dv1394_un_init(video);
+ snprintf( buf, sizeof(buf), "%i", video->id);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry( buf, dv1394_procfs_entry);
+#endif
+ }
+}
+
+static void dv1394_add_host (struct hpsb_host *host)
+{
+ struct ti_ohci *ohci;
+
+ /* We only work with the OHCI-1394 driver */
+ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+ return;
+
+ ohci = (struct ti_ohci *)host->hostdata;
+
+ dv1394_init(ohci);
+}
+
+static struct hpsb_highlevel_ops hl_ops = {
+ add_host: dv1394_add_host,
+ remove_host: dv1394_remove_host,
+};
+
+
+/*** KERNEL MODULE HANDLERS ************************************************/
+
+MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
+MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
+MODULE_SUPPORTED_DEVICE("dv1394");
+MODULE_LICENSE("GPL");
+
+static void __exit dv1394_exit_module(void)
+{
+ hpsb_unregister_highlevel (hl_handle);
+ ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+ devfs_unregister(dv1394_devfs_handle);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry( "dv", ieee1394_procfs_entry);
+#endif
+}
+
+static int __init dv1394_init_module(void)
+{
+ if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
+ THIS_MODULE, &dv1394_fops)) {
+ printk(KERN_ERR "dv1394: unable to register character device\n");
+ return -EIO;
+ }
+
+ dv1394_devfs_handle = devfs_mk_dir(ieee1394_devfs_handle, "dv", NULL);
+
+#ifdef CONFIG_PROC_FS
+ dv1394_procfs_entry = proc_mkdir( "dv", ieee1394_procfs_entry);
+ if (dv1394_procfs_entry == NULL) {
+ printk(KERN_ERR "dv1394: unable to create /proc/ieee1394/dv\n");
+ ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+ devfs_unregister(dv1394_devfs_handle);
+ return -ENOMEM;
+ }
+ dv1394_procfs_entry->owner = THIS_MODULE;
+#endif
+
+ hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops);
+ if (hl_handle == NULL) {
+ printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n");
+ ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+ devfs_unregister(dv1394_devfs_handle);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry( "dv", ieee1394_procfs_entry);
+#endif
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+module_init(dv1394_init_module);
+module_exit(dv1394_exit_module);
+
diff --git a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h
new file mode 100644
index 000000000..d427cfde6
--- /dev/null
+++ b/drivers/ieee1394/dv1394.h
@@ -0,0 +1,277 @@
+/*
+ * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
+ * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ * receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ * video1394.h - driver for OHCI 1394 boards
+ * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ * Peter Schlaile <udbz@rz.uni-karlsruhe.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 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.
+ */
+
+#ifndef _DV_1394_H
+#define _DV_1394_H
+
+/* This is the public user-space interface. Try not to break it. */
+
+#define DV1394_API_VERSION 0x20011127
+
+/* ********************
+ ** **
+ ** DV1394 API **
+ ** **
+ ********************
+
+ There are two methods of operating the DV1394 DV output device.
+
+ 1)
+
+ The simplest is an interface based on write(): simply write
+ full DV frames of data to the device, and they will be transmitted
+ as quickly as possible. The FD may be set for non-blocking I/O,
+ in which case you can use select() or poll() to wait for output
+ buffer space.
+
+ To set the DV output parameters (e.g. whether you want NTSC or PAL
+ video), use the DV1394_INIT ioctl, passing in the parameters you
+ want in a struct dv1394_init.
+
+ Example 1:
+ To play a raw .DV file: cat foo.DV > /dev/dv1394
+ (cat will use write() internally)
+
+ Example 2:
+ static struct dv1394_init init = {
+ 0x63, (broadcast channel)
+ 4, (four-frame ringbuffer)
+ DV1394_NTSC, (send NTSC video)
+ 0, 0 (default empty packet rate)
+ }
+
+ ioctl(fd, DV1394_INIT, &init);
+
+ while(1) {
+ read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
+ write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
+ }
+
+ 2)
+
+ For more control over buffering, and to avoid unnecessary copies
+ of the DV data, you can use the more sophisticated the mmap() interface.
+ First, call the DV1394_INIT ioctl to specify your parameters,
+ including the number of frames in the ringbuffer. Then, calling mmap()
+ on the dv1394 device will give you direct access to the ringbuffer
+ from which the DV card reads your frame data.
+
+ The ringbuffer is simply one large, contiguous region of memory
+ containing two or more frames of packed DV data. Each frame of DV data
+ is 120000 bytes (NTSC) or 144000 bytes (PAL).
+
+ Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
+ ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
+ or select()/poll() to wait until the frames are transmitted. Next, you'll
+ need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
+ frames are clear (ready to be filled with new DV data). Finally, use
+ DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
+
+
+ Example: here is what a four-frame ringbuffer might look like
+ during DV transmission:
+
+
+ frame 0 frame 1 frame 2 frame 3
+
+ *--------------------------------------*
+ | CLEAR | DV data | DV data | CLEAR |
+ *--------------------------------------*
+ <ACTIVE>
+
+ transmission goes in this direction --->>>
+
+
+ The DV hardware is currently transmitting the data in frame 1.
+ Once frame 1 is finished, it will automatically transmit frame 2.
+ (if frame 2 finishes before frame 3 is submitted, the device
+ will continue to transmit frame 2, and will increase the dropped_frames
+ counter each time it repeats the transmission).
+
+
+ If you called DV1394_GET_STATUS at this instant, you would
+ receive the following values:
+
+ n_frames = 4
+ active_frame = 1
+ first_clear_frame = 3
+ n_clear_frames = 2
+
+ At this point, you should write new DV data into frame 3 and optionally
+ frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
+ it may transmit the new frames.
+
+*/
+
+
+/* maximum number of frames in the ringbuffer */
+#define DV1394_MAX_FRAMES 32
+
+/* number of *full* isochronous packets per DV frame */
+#define DV1394_NTSC_PACKETS_PER_FRAME 250
+#define DV1394_PAL_PACKETS_PER_FRAME 300
+
+/* size of one frame's worth of DV data, in bytes */
+#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
+#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME)
+
+
+/* ioctl() commands */
+
+enum {
+ /* I don't like using 0 as a valid ioctl() */
+ DV1394_INVALID = 0,
+
+
+ /* get the driver ready to transmit video.
+ pass a struct dv1394_init* as the parameter (see below),
+ or NULL to get default parameters */
+ DV1394_INIT,
+
+
+ /* stop transmitting video and free the ringbuffer */
+ DV1394_SHUTDOWN,
+
+
+ /* submit N new frames to be transmitted, where
+ the index of the first new frame is first_clear_buffer,
+ and the index of the last new frame is
+ (first_clear_buffer + N) % n_frames */
+ DV1394_SUBMIT_FRAMES,
+
+
+ /* block until N buffers are clear (pass N as the parameter)
+ Because we re-transmit the last frame on underrun, there
+ will at most be n_frames - 1 clear frames at any time */
+ DV1394_WAIT_FRAMES,
+
+ /* capture new frames that have been received, where
+ the index of the first new frame is first_clear_buffer,
+ and the index of the last new frame is
+ (first_clear_buffer + N) % n_frames */
+ DV1394_RECEIVE_FRAMES,
+
+
+ DV1394_START_RECEIVE,
+
+
+ /* pass a struct dv1394_status* as the parameter (see below) */
+ DV1394_GET_STATUS,
+};
+
+
+
+enum pal_or_ntsc {
+ DV1394_NTSC = 0,
+ DV1394_PAL
+};
+
+
+
+
+/* this is the argument to DV1394_INIT */
+struct dv1394_init {
+ /* DV1394_API_VERSION */
+ unsigned int api_version;
+
+ /* isochronous transmission channel to use */
+ unsigned int channel;
+
+ /* number of frames in the ringbuffer. Must be at least 2
+ and at most DV1394_MAX_FRAMES. */
+ unsigned int n_frames;
+
+ /* send/receive PAL or NTSC video format */
+ enum pal_or_ntsc format;
+
+ /* the following are used only for transmission */
+
+ /* set these to zero unless you want a
+ non-default empty packet rate (see below) */
+ unsigned long cip_n;
+ unsigned long cip_d;
+
+ /* set this to zero unless you want a
+ non-default SYT cycle offset (default = 3 cycles) */
+ unsigned int syt_offset;
+};
+
+/* Q: What are cip_n and cip_d? */
+
+/*
+ A: DV video streams do not utilize 100% of the potential bandwidth offered
+ by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
+ DV devices must periodically insert empty packets into the 1394 data stream.
+ Typically there is one empty packet per 14-16 data-carrying packets.
+
+ Some DV devices will accept a wide range of empty packet rates, while others
+ require a precise rate. If the dv1394 driver produces empty packets at
+ a rate that your device does not accept, you may see ugly patterns on the
+ DV output, or even no output at all.
+
+ The default empty packet insertion rate seems to work for many people; if
+ your DV output is stable, you can simply ignore this discussion. However,
+ we have exposed the empty packet rate as a parameter to support devices that
+ do not work with the default rate.
+
+ The decision to insert an empty packet is made with a numerator/denominator
+ algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
+ You can alter the empty packet rate by passing non-zero values for cip_n
+ and cip_d to the INIT ioctl.
+
+ */
+
+
+
+struct dv1394_status {
+ /* this embedded init struct returns the current dv1394
+ parameters in use */
+ struct dv1394_init init;
+
+ /* the ringbuffer frame that is currently being
+ displayed. (-1 if the device is not transmitting anything) */
+ int active_frame;
+
+ /* index of the first buffer (ahead of active_frame) that
+ is ready to be filled with data */
+ unsigned int first_clear_frame;
+
+ /* how many buffers, including first_clear_buffer, are
+ ready to be filled with data */
+ unsigned int n_clear_frames;
+
+ /* how many times the DV output has underflowed
+ since the last call to DV1394_GET_STATUS */
+ unsigned int dropped_frames;
+
+ /* N.B. The dropped_frames counter is only a lower bound on the actual
+ number of dropped frames, with the special case that if dropped_frames
+ is zero, then it is guaranteed that NO frames have been dropped
+ since the last call to DV1394_GET_STATUS.
+ */
+};
+
+
+#endif /* _DV_1394_H */
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 3f337eb5d..8520403cf 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -44,10 +44,11 @@ struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
hl->op = ops;
write_lock_irq(&hl_drivers_lock);
- hl_all_hosts(hl, 1);
list_add_tail(&hl->hl_list, &hl_drivers);
write_unlock_irq(&hl_drivers_lock);
+ hl_all_hosts(hl->op->add_host);
+
return hl;
}
@@ -73,9 +74,11 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
write_lock_irq(&hl_drivers_lock);
list_del(&hl->hl_list);
- hl_all_hosts(hl, 0);
write_unlock_irq(&hl_drivers_lock);
+ if (hl->op->remove_host)
+ hl_all_hosts(hl->op->remove_host);
+
kfree(hl);
}
@@ -87,7 +90,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
int retval = 0;
if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
- HPSB_ERR(__FUNCTION__ " called with invalid addresses");
+ HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
return 0;
}
@@ -131,12 +134,12 @@ void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel)
{
if (channel > 63) {
- HPSB_ERR(__FUNCTION__ " called with invalid channel");
+ HPSB_ERR("%s called with invalid channel", __FUNCTION__);
return;
}
if (host->iso_listen_count[channel]++ == 0) {
- host->template->devctl(host, ISO_LISTEN_CHANNEL, channel);
+ host->ops->devctl(host, ISO_LISTEN_CHANNEL, channel);
}
}
@@ -144,46 +147,58 @@ void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel)
{
if (channel > 63) {
- HPSB_ERR(__FUNCTION__ " called with invalid channel");
+ HPSB_ERR("%s called with invalid channel", __FUNCTION__);
return;
}
if (--host->iso_listen_count[channel] == 0) {
- host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
+ host->ops->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
}
}
-#define DEFINE_MULTIPLEXER(Function) \
-void highlevel_##Function(struct hpsb_host *host) \
-{ \
- struct list_head *lh; \
- void (*funcptr)(struct hpsb_host*); \
- read_lock(&hl_drivers_lock); \
- list_for_each(lh, &hl_drivers) { \
- funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) \
- ->op->Function; \
- if (funcptr) funcptr(host); \
- } \
- read_unlock(&hl_drivers_lock); \
+void highlevel_add_host(struct hpsb_host *host)
+{
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
+
+ read_lock(&hl_drivers_lock);
+ list_for_each(entry, &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+ hl->op->add_host(host);
+ }
+ read_unlock(&hl_drivers_lock);
}
-DEFINE_MULTIPLEXER(add_host)
-DEFINE_MULTIPLEXER(remove_host)
-DEFINE_MULTIPLEXER(host_reset)
-#undef DEFINE_MULTIPLEXER
+void highlevel_remove_host(struct hpsb_host *host)
+{
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
-/* Add one host to our list */
-void highlevel_add_one_host (struct hpsb_host *host)
+ write_lock_irq(&hl_drivers_lock);
+ list_for_each(entry, &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+ if (hl->op->remove_host)
+ hl->op->remove_host(host);
+ }
+ write_unlock_irq(&hl_drivers_lock);
+}
+
+void highlevel_host_reset(struct hpsb_host *host)
{
- if (host->template->initialize_host)
- if (!host->template->initialize_host(host))
- goto fail;
- host->initialized = 1;
- highlevel_add_host (host);
- hpsb_reset_bus (host, LONG_RESET);
-fail:
- host->template->number_of_hosts++;
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
+
+ read_lock(&hl_drivers_lock);
+ list_for_each(entry, &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+ if (hl->op->host_reset)
+ hl->op->host_reset(host);
+ }
+ read_unlock(&hl_drivers_lock);
}
void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
@@ -242,12 +257,11 @@ int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
while (as->start <= addr) {
if (as->end > addr) {
- partlength = MIN((unsigned int)(as->end - addr),
- length);
+ partlength = min(as->end - addr, (u64) length);
if (as->op->read != NULL) {
- rcode = as->op->read(host, nodeid, buffer, addr,
- partlength);
+ rcode = as->op->read(host, nodeid, buffer,
+ addr, partlength);
} else {
rcode = RCODE_TYPE_ERROR;
}
@@ -288,12 +302,11 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
while (as->start <= addr) {
if (as->end > addr) {
- partlength = MIN((unsigned int)(as->end - addr),
- length);
+ partlength = min(as->end - addr, (u64) length);
if (as->op->write != NULL) {
- rcode = as->op->write(host, nodeid, destid, data,
- addr, partlength);
+ rcode = as->op->write(host, nodeid, destid,
+ data, addr, partlength);
} else {
rcode = RCODE_TYPE_ERROR;
}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index f650a300f..84f927925 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -91,7 +91,6 @@ struct hpsb_address_ops {
void init_hpsb_highlevel(void);
void highlevel_add_host(struct hpsb_host *host);
-void highlevel_add_one_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index f33d5dfd8..074db620a 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -11,101 +11,86 @@
*/
#include <linux/config.h>
-
#include <linux/types.h>
+#include <linux/list.h>
#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
+#include <linux/slab.h>
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394_core.h"
#include "highlevel.h"
+static struct list_head hosts = LIST_HEAD_INIT(hosts);
+static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers);
-static LIST_HEAD(templates);
-static spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED;
-/*
- * This function calls the add_host/remove_host hooks for every host currently
- * registered. Init == TRUE means add_host.
- */
-void hl_all_hosts(struct hpsb_highlevel *hl, int init)
-{
- struct list_head *tlh, *hlh;
- struct hpsb_host_template *tmpl;
- struct hpsb_host *host;
- spin_lock(&templates_lock);
-
- list_for_each(tlh, &templates) {
- tmpl = list_entry(tlh, struct hpsb_host_template, list);
- list_for_each(hlh, &tmpl->hosts) {
- host = list_entry(hlh, struct hpsb_host, list);
- if (host->initialized) {
- if (init) {
- if (hl->op->add_host) {
- hl->op->add_host(host);
- }
- } else {
- if (hl->op->remove_host) {
- hl->op->remove_host(host);
- }
- }
- }
- }
- }
+static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
+{
+ return 0;
+}
- spin_unlock(&templates_lock);
+static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
+{
+ return -1;
}
-int hpsb_inc_host_usage(struct hpsb_host *host)
+static struct hpsb_host_operations dummy_ops = {
+ transmit_packet: dummy_transmit_packet,
+ devctl: dummy_devctl
+};
+
+
+int hpsb_ref_host(struct hpsb_host *host)
{
- struct list_head *tlh, *hlh;
- struct hpsb_host_template *tmpl;
- int retval = 0;
+ struct list_head *lh;
unsigned long flags;
+ int retval = 0;
- spin_lock_irqsave(&templates_lock, flags);
-
- list_for_each(tlh, &templates) {
- tmpl = list_entry(tlh, struct hpsb_host_template, list);
- list_for_each(hlh, &tmpl->hosts) {
- if (host == list_entry(hlh, struct hpsb_host, list)) {
- tmpl->devctl(host, MODIFY_USAGE, 1);
+ spin_lock_irqsave(&hosts_lock, flags);
+ list_for_each(lh, &hosts) {
+ if (host == list_entry(lh, struct hpsb_host, host_list)) {
+ if (host->ops->devctl(host, MODIFY_USAGE, 1)) {
+ host->refcount++;
retval = 1;
- break;
- }
}
- if (retval)
break;
}
-
- spin_unlock_irqrestore(&templates_lock, flags);
+ }
+ spin_unlock_irqrestore(&hosts_lock, flags);
return retval;
}
-void hpsb_dec_host_usage(struct hpsb_host *host)
+void hpsb_unref_host(struct hpsb_host *host)
{
- host->template->devctl(host, MODIFY_USAGE, 0);
+ unsigned long flags;
+
+ host->ops->devctl(host, MODIFY_USAGE, 0);
+
+ spin_lock_irqsave(&hosts_lock, flags);
+ host->refcount--;
+
+ if (!host->refcount && !host->is_shutdown)
+ kfree(host);
+ spin_unlock_irqrestore(&hosts_lock, flags);
}
-/*
- * The following function is exported for module usage. It will be called from
- * the detect function of a adapter driver.
- */
-struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
- size_t hd_size)
+struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
{
struct hpsb_host *h;
- h = vmalloc(sizeof(struct hpsb_host) + hd_size);
+ h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
if (!h) return NULL;
- memset(h, 0, sizeof(struct hpsb_host) + hd_size);
+ memset(h, 0, sizeof(struct hpsb_host) + extra);
- atomic_set(&h->generation, 0);
+ h->driver = drv;
+ h->ops = drv->ops;
+ h->hostdata = h + 1;
INIT_LIST_HEAD(&h->pending_packets);
spin_lock_init(&h->pending_pkt_lock);
@@ -113,113 +98,92 @@ struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
sema_init(&h->tlabel_count, 64);
spin_lock_init(&h->tlabel_lock);
+ atomic_set(&h->generation, 0);
+
INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
h->topology_map = h->csr.topology_map + 3;
h->speed_map = (u8 *)(h->csr.speed_map + 2);
- h->template = tmpl;
- if (hd_size)
- h->hostdata = &h->embedded_hostdata[0];
+ return h;
+}
+
+void hpsb_add_host(struct hpsb_host *host)
+{
+ unsigned long flags;
- list_add_tail(&h->list, &tmpl->hosts);
+ spin_lock_irqsave(&hosts_lock, flags);
+ host->driver->number_of_hosts++;
+ list_add_tail(&host->driver_list, &host->driver->hosts);
+ list_add_tail(&host->host_list, &hosts);
+ spin_unlock_irqrestore(&hosts_lock, flags);
- return h;
+ highlevel_add_host(host);
+ host->ops->devctl(host, RESET_BUS, 0);
}
-static void free_all_hosts(struct hpsb_host_template *tmpl)
+void hpsb_remove_host(struct hpsb_host *host)
{
- struct list_head *hlh, *next;
- struct hpsb_host *host;
+ struct hpsb_host_driver *drv = host->driver;
+ unsigned long flags;
- list_for_each_safe(hlh, next, &tmpl->hosts) {
- host = list_entry(hlh, struct hpsb_host, list);
- vfree(host);
- }
+ host->is_shutdown = 1;
+ host->ops = &dummy_ops;
+ highlevel_remove_host(host);
+
+ spin_lock_irqsave(&hosts_lock, flags);
+ list_del(&host->driver_list);
+ list_del(&host->host_list);
+
+ drv->number_of_hosts--;
+ if (!host->refcount) kfree(host);
+ spin_unlock_irqrestore(&hosts_lock, flags);
}
-static void init_hosts(struct hpsb_host_template *tmpl)
+struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
+ const char *name)
{
- int count;
- struct list_head *hlh;
- struct hpsb_host *host;
+ struct hpsb_host_driver *drv;
- count = tmpl->detect_hosts(tmpl);
+ drv = kmalloc(sizeof(struct hpsb_host_driver), SLAB_KERNEL);
+ if (!drv) return NULL;
- list_for_each(hlh, &tmpl->hosts) {
- host = list_entry(hlh, struct hpsb_host, list);
- if (tmpl->initialize_host(host)) {
- host->initialized = 1;
+ INIT_LIST_HEAD(&drv->list);
+ INIT_LIST_HEAD(&drv->hosts);
+ drv->number_of_hosts = 0;
+ drv->name = name;
+ drv->ops = op;
- highlevel_add_host(host);
- hpsb_reset_bus(host, LONG_RESET);
- }
- }
+ spin_lock(&host_drivers_lock);
+ list_add_tail(&drv->list, &host_drivers);
+ spin_unlock(&host_drivers_lock);
- tmpl->number_of_hosts = count;
- HPSB_INFO("detected %d %s adapter%s", count, tmpl->name,
- (count != 1 ? "s" : ""));
+ return drv;
}
-static void shutdown_hosts(struct hpsb_host_template *tmpl)
+void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv)
{
- struct list_head *hlh;
- struct hpsb_host *host;
+ spin_lock(&host_drivers_lock);
+ list_del(&drv->list);
+ spin_unlock(&host_drivers_lock);
- list_for_each(hlh, &tmpl->hosts) {
- host = list_entry(hlh, struct hpsb_host, list);
- if (host->initialized) {
- highlevel_remove_host(host);
-
- host->initialized = 0;
- abort_requests(host);
-
- tmpl->release_host(host);
- while (test_bit(0, &host->timeout_tq.sync)) {
- schedule();
- }
- }
- }
- free_all_hosts(tmpl);
- tmpl->release_host(NULL);
-
- tmpl->number_of_hosts = 0;
+ kfree(drv);
}
/*
- * The following two functions are exported symbols for module usage.
+ * This function calls the given function for every host currently registered.
*/
-int hpsb_register_lowlevel(struct hpsb_host_template *tmpl)
+void hl_all_hosts(void (*function)(struct hpsb_host*))
{
- INIT_LIST_HEAD(&tmpl->hosts);
- tmpl->number_of_hosts = 0;
-
- spin_lock(&templates_lock);
- list_add_tail(&tmpl->list, &templates);
- spin_unlock(&templates_lock);
-
- /* PCI cards should be smart and use the PCI detection layer, and
- * not this one shot deal. detect_hosts() will be obsoleted soon. */
- if (tmpl->detect_hosts != NULL) {
- HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name);
- init_hosts(tmpl);
- }
-
- return 0;
-}
+ struct list_head *lh;
+ struct hpsb_host *host;
-void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl)
-{
- shutdown_hosts(tmpl);
-
- if (tmpl->number_of_hosts)
- HPSB_PANIC("attempted to remove busy host template "
- "of %s at address 0x%p", tmpl->name, tmpl);
- else {
- spin_lock(&templates_lock);
- list_del(&tmpl->list);
- spin_unlock(&templates_lock);
+ spin_lock_irq(&hosts_lock);
+ list_for_each (lh, &hosts) {
+ host = list_entry(lh, struct hpsb_host, host_list);
+ function(host);
}
+ spin_unlock_irq(&hosts_lock);
}
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index a58d415ab..cd4ebe574 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -13,11 +13,15 @@
struct hpsb_packet;
struct hpsb_host {
-/* private fields (hosts, do not use them) */
- struct list_head list;
+ struct list_head host_list;
+
+ struct hpsb_host_operations *ops;
+ void *hostdata;
atomic_t generation;
+ int refcount;
+
struct list_head pending_packets;
spinlock_t pending_pkt_lock;
struct tq_struct timeout_tq;
@@ -28,16 +32,8 @@ struct hpsb_host {
struct semaphore tlabel_count;
spinlock_t tlabel_lock;
- int reset_retries;
- quadlet_t *topology_map;
- u8 *speed_map;
- struct csr_control csr;
-
unsigned char iso_listen_count[64];
-/* readonly fields for hosts */
- struct hpsb_host_template *template;
-
int node_count; /* number of identified nodes on this bus */
int selfid_count; /* total number of SelfIDs received */
@@ -45,9 +41,9 @@ struct hpsb_host {
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
nodeid_t busmgr_id; /* ID of this bus' bus manager */
- unsigned initialized:1; /* initialized and usable */
- unsigned in_bus_reset:1; /* in bus reset / SelfID stage */
- unsigned attempt_root:1; /* attempt to become root during next reset */
+ /* this nodes state */
+ unsigned in_bus_reset:1;
+ unsigned is_shutdown:1;
/* this nodes' duties on the bus */
unsigned is_root:1;
@@ -55,11 +51,15 @@ struct hpsb_host {
unsigned is_irm:1;
unsigned is_busmgr:1;
-/* fields readable and writeable by the hosts */
+ int reset_retries;
+ quadlet_t *topology_map;
+ u8 *speed_map;
+ struct csr_control csr;
+
+ struct hpsb_host_driver *driver;
+ struct list_head driver_list;
- void *hostdata;
struct pci_dev *pdev;
- int embedded_hostdata[0];
};
@@ -88,8 +88,10 @@ enum devctl_cmd {
* Return void. */
CANCEL_REQUESTS,
- /* Decrease module usage count if arg == 0, increase otherwise. Return
- * void. */
+ /* Decrease host usage count if arg == 0, increase otherwise. Return
+ * 1 for success, 0 for failure. Increase usage may fail if the driver
+ * is in the process of shutting itself down. Decrease usage can not
+ * fail. */
MODIFY_USAGE,
/* Start or stop receiving isochronous channel in arg. Return void.
@@ -109,37 +111,7 @@ enum reset_types {
SHORT_RESET
};
-struct hpsb_host_template {
- struct list_head list;
-
- struct list_head hosts;
- int number_of_hosts;
-
- /* fields above will be ignored and overwritten after registering */
-
- /* This should be the name of the driver (single word) and must not be
- * NULL. */
- const char *name;
-
- /* This function shall detect all available adapters of this type and
- * call hpsb_get_host for each one. The initialize_host function will
- * be called to actually set up these adapters. The number of detected
- * adapters or zero if there are none must be returned.
- */
- int (*detect_hosts) (struct hpsb_host_template *template);
-
- /* After detecting and registering hosts, this function will be called
- * for every registered host. It shall set up the host to be fully
- * functional for bus operations and return 0 for failure.
- */
- int (*initialize_host) (struct hpsb_host *host);
-
- /* To unload modules, this function is provided. It shall free all
- * resources this host is using (if host is not NULL) or free all
- * resources globally allocated by the driver (if host is NULL).
- */
- void (*release_host) (struct hpsb_host *host);
-
+struct hpsb_host_operations {
/* This function must store a pointer to the configuration ROM into the
* location referenced to by pointer and return the size of the ROM. It
* may not fail. If any allocation is required, it must be done
@@ -175,34 +147,43 @@ struct hpsb_host_template {
quadlet_t data, quadlet_t compare);
};
+struct hpsb_host_driver {
+ struct list_head list;
+ struct list_head hosts;
-/* mid level internal use */
+ int number_of_hosts;
+ const char *name;
+
+ struct hpsb_host_operations *ops;
+};
+
+
+/* core internal use */
void register_builtin_lowlevels(void);
/* high level internal use */
struct hpsb_highlevel;
-void hl_all_hosts(struct hpsb_highlevel *hl, int init);
+void hl_all_hosts(void (*function)(struct hpsb_host*));
-/*
- * These functions are for lowlevel (host) driver use.
- */
-int hpsb_register_lowlevel(struct hpsb_host_template *tmpl);
-void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl);
/*
- * Get a initialized host structure with hostdata_size bytes allocated in
- * embedded_hostdata for free usage. Returns NULL for failure.
+ * In order to prevent hosts from unloading, use hpsb_ref_host(). This prevents
+ * the host from going away (e.g. makes module unloading of the driver
+ * impossible), but still can not guarantee it (e.g. PC-Card being pulled by the
+ * user). hpsb_ref_host() returns false if host could not be locked. If it is
+ * successful, host is valid as a pointer until hpsb_unref_host() (not just
+ * until after remove_host).
*/
-struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
- size_t hostdata_size);
+int hpsb_ref_host(struct hpsb_host *host);
+void hpsb_unref_host(struct hpsb_host *host);
-/*
- * Increase / decrease host usage counter. Increase function will return true
- * only if successful (host still existed). Decrease function expects host to
- * exist.
- */
-int hpsb_inc_host_usage(struct hpsb_host *host);
-void hpsb_dec_host_usage(struct hpsb_host *host);
+struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra);
+void hpsb_add_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *h);
+
+struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
+ const char *name);
+void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv);
#endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
index 485b1657b..c68a2ace6 100644
--- a/drivers/ieee1394/ieee1394.h
+++ b/drivers/ieee1394/ieee1394.h
@@ -39,10 +39,10 @@
#define ACK_TYPE_ERROR 0xe
/* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE -1
-#define ACKX_SEND_ERROR -2
-#define ACKX_ABORTED -3
-#define ACKX_TIMEOUT -4
+#define ACKX_NONE (-1)
+#define ACKX_SEND_ERROR (-2)
+#define ACKX_ABORTED (-3)
+#define ACKX_TIMEOUT (-4)
#define SPEED_100 0x0
@@ -116,7 +116,7 @@ struct ext_selfid {
/*
* Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine.
+ * endian machine. Without swapping.
*/
struct selfid {
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index a642b2468..487bc71fa 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -18,9 +18,11 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/proc_fs.h>
#include <asm/bitops.h>
#include <asm/byteorder.h>
#include <asm/semaphore.h>
+#include <asm/smplock.h>
#include "ieee1394_types.h"
#include "ieee1394.h"
@@ -135,12 +137,8 @@ void free_hpsb_packet(struct hpsb_packet *packet)
int hpsb_reset_bus(struct hpsb_host *host, int type)
{
- if (!host->initialized) {
- return 1;
- }
-
if (!host->in_bus_reset) {
- host->template->devctl(host, RESET_BUS, type);
+ host->ops->devctl(host, RESET_BUS, type);
return 0;
} else {
return 1;
@@ -151,8 +149,8 @@ int hpsb_reset_bus(struct hpsb_host *host, int type)
int hpsb_bus_reset(struct hpsb_host *host)
{
if (host->in_bus_reset) {
- HPSB_NOTICE(__FUNCTION__
- " called while bus reset already in progress");
+ HPSB_NOTICE("%s called while bus reset already in progress",
+ __FUNCTION__);
return 1;
}
@@ -171,10 +169,10 @@ int hpsb_bus_reset(struct hpsb_host *host)
* Verify num_of_selfids SelfIDs and return number of nodes. Return zero in
* case verification failed.
*/
-static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
+static int check_selfids(struct hpsb_host *host)
{
int nodeid = -1;
- int rest_of_selfids = num_of_selfids;
+ int rest_of_selfids = host->selfid_count;
struct selfid *sid = (struct selfid *)host->topology_map;
struct ext_selfid *esid;
int esid_seq = 23;
@@ -318,15 +316,18 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{
+ if (!host->in_bus_reset)
+ HPSB_NOTICE("SelfID completion called outside of bus reset!");
+
host->node_id = LOCAL_BUS | phyid;
- host->in_bus_reset = 0;
host->is_root = isroot;
- host->node_count = check_selfids(host, host->selfid_count);
+ host->node_count = check_selfids(host);
if (!host->node_count) {
if (host->reset_retries++ < 20) {
/* selfid stage did not complete without error */
HPSB_NOTICE("Error in SelfID stage, resetting");
+ host->in_bus_reset = 0;
hpsb_reset_bus(host, LONG_RESET);
return;
} else {
@@ -346,8 +347,9 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
}
host->reset_retries = 0;
- atomic_inc(&host->generation);
- if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1);
+ if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1);
+ atomic_inc(&host->generation);
+ host->in_bus_reset = 0;
highlevel_host_reset(host);
}
@@ -402,7 +404,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
{
struct hpsb_host *host = packet->host;
- if (!host->initialized || host->in_bus_reset
+ if (host->is_shutdown || host->in_bus_reset
|| (packet->generation != get_hpsb_generation(host))) {
return 0;
}
@@ -431,7 +433,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
}
#endif
- return host->template->transmit_packet(host, packet);
+ return host->ops->transmit_packet(host, packet);
}
static void send_packet_nocare(struct hpsb_packet *packet)
@@ -727,7 +729,7 @@ void abort_requests(struct hpsb_host *host)
struct list_head *lh;
LIST_HEAD(llist);
- host->template->devctl(host, CANCEL_REQUESTS, 0);
+ host->ops->devctl(host, CANCEL_REQUESTS, 0);
spin_lock_irqsave(&host->pending_pkt_lock, flags);
list_splice(&host->pending_packets, &llist);
@@ -786,10 +788,228 @@ void abort_timedouts(struct hpsb_host *host)
}
+/*
+ * character device dispatching (see ieee1394_core.h)
+ * Dan Maas <dmaas@dcine.com>
+ */
+
+static struct {
+ struct file_operations *file_ops;
+ struct module *module;
+} ieee1394_chardevs[16];
+
+static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
+
+static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
+
+static struct file_operations ieee1394_chardev_ops = {
+ OWNER_THIS_MODULE
+ open: ieee1394_dispatch_open,
+};
+
+devfs_handle_t ieee1394_devfs_handle;
+
+
+/* claim a block of minor numbers */
+int ieee1394_register_chardev(int blocknum,
+ struct module *module,
+ struct file_operations *file_ops)
+{
+ int retval;
+
+ if( (blocknum < 0) || (blocknum > 15) )
+ return -EINVAL;
+
+ write_lock(&ieee1394_chardevs_lock);
+
+ if(ieee1394_chardevs[blocknum].file_ops == NULL) {
+ /* grab the minor block */
+ ieee1394_chardevs[blocknum].file_ops = file_ops;
+ ieee1394_chardevs[blocknum].module = module;
+
+ retval = 0;
+
+ V22_COMPAT_MOD_INC_USE_COUNT;
+ } else {
+ /* block already taken */
+ retval = -EBUSY;
+ }
+
+ write_unlock(&ieee1394_chardevs_lock);
+
+ return retval;
+}
+
+/* release a block of minor numbers */
+void ieee1394_unregister_chardev(int blocknum)
+{
+ if( (blocknum < 0) || (blocknum > 15) )
+ return;
+
+ write_lock(&ieee1394_chardevs_lock);
+
+ if(ieee1394_chardevs[blocknum].file_ops) {
+ ieee1394_chardevs[blocknum].file_ops = NULL;
+ ieee1394_chardevs[blocknum].module = NULL;
+ V22_COMPAT_MOD_DEC_USE_COUNT;
+ }
+
+ write_unlock(&ieee1394_chardevs_lock);
+}
+
+/* the point of entry for open() on any ieee1394 character device */
+static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
+{
+ struct file_operations *file_ops;
+ struct module *module;
+ int blocknum;
+ int retval = -ENODEV;
+
+ /*
+ Maintaining correct module reference counts is tricky here!
+
+ For Linux v2.2:
+
+ The task-specific driver is expected to maintain its own
+ reference count via V22_COMPAT_MOD_[INC,DEC]_USE_COUNT.
+ We don't need to do anything special.
+
+ For Linux v2.4 and later:
+
+ The key thing to remember is that the VFS increments the
+ reference count of ieee1394 before it calls
+ ieee1394_dispatch_open().
+
+ If the open() succeeds, then we need to transfer this extra
+ reference to the task-specific driver module (e.g. raw1394).
+ The VFS will deref the driver module automatically when the
+ file is later released.
+
+ If the open() fails, then the VFS will drop the
+ reference count of whatever module file->f_op->owner points
+ to, immediately after this function returns.
+
+ The comments below refer to the 2.4 case, since the 2.2
+ case is trivial.
+
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+ /* 2.2 */
+#define INCREF(mod) do {} while (0)
+#define DECREF(mod) do {} while (0)
+#else
+ /* 2.4 */
+#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
+ if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
+#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
+ if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
+#endif
+
+ /* shift away lower four bits of the minor
+ to get the index of the ieee1394_driver
+ we want */
+
+ blocknum = (minor(inode->i_rdev) >> 4) & 0xF;
+
+ /* printk("ieee1394_dispatch_open(%d)", blocknum); */
+
+ /* lock the whole kernel here, to prevent a driver from
+ being unloaded between the file_ops lookup and the open */
+
+ lock_kernel();
+
+ read_lock(&ieee1394_chardevs_lock);
+ file_ops = ieee1394_chardevs[blocknum].file_ops;
+ module = ieee1394_chardevs[blocknum].module;
+ read_unlock(&ieee1394_chardevs_lock);
+
+ if(file_ops == NULL) {
+ goto out_fail;
+ }
+
+ /* redirect all subsequent requests to the driver's
+ own file_operations */
+ file->f_op = file_ops;
+
+ /* bump the reference count of the driver that
+ will receive the open() */
+ INCREF(module);
+
+ /* at this point BOTH ieee1394 and the task-specific driver have
+ an extra reference */
+
+ /* follow through with the open() */
+ retval = file_ops->open(inode, file);
+
+ if(retval) {
+
+ /* if the open() failed, then we need to drop the
+ extra reference we gave to the task-specific
+ driver */
+
+ DECREF(module);
+ goto out_fail;
+
+ } else {
+
+ /* if the open() succeeded, then ieee1394 will be left
+ with an extra module reference, so we discard it here.*/
+
+ DECREF(THIS_MODULE);
+
+ /* the task-specific driver still has the extra
+ reference we gave it. This extra reference prevents
+ the module from unloading while the file is open,
+ and will be dropped by the VFS when the file is
+ released. */
+
+ unlock_kernel();
+ return 0;
+ }
+
+out_fail:
+ /* point the file's f_ops back to ieee1394. The VFS will then
+ decrement ieee1394's reference count immediately after this
+ function returns. */
+
+ file->f_op = &ieee1394_chardev_ops;
+ unlock_kernel();
+ return retval;
+
+#undef INCREF
+#undef DECREF
+
+}
+
+struct proc_dir_entry *ieee1394_procfs_entry;
+
static int __init ieee1394_init(void)
{
hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
0, 0, NULL, NULL);
+
+ ieee1394_devfs_handle = devfs_mk_dir(NULL, "ieee1394", NULL);
+
+ if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
+ HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
+ devfs_unregister(ieee1394_devfs_handle);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_PROC_FS
+ /* Must be done before we start everything else, since the drivers
+ * may use it. */
+ ieee1394_procfs_entry = proc_mkdir( "ieee1394", proc_bus);
+ if (ieee1394_procfs_entry == NULL) {
+ HPSB_ERR("unable to create /proc/bus/ieee1394\n");
+ unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+ devfs_unregister(ieee1394_devfs_handle);
+ return -ENOMEM;
+ }
+ ieee1394_procfs_entry->owner = THIS_MODULE;
+#endif
+
init_hpsb_highlevel();
init_csr();
if (!disable_nodemgr)
@@ -807,6 +1027,13 @@ static void __exit ieee1394_cleanup(void)
cleanup_csr();
kmem_cache_destroy(hpsb_packet_cache);
+
+ unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+
+ /* it's ok to pass a NULL devfs_handle to devfs_unregister */
+ devfs_unregister(ieee1394_devfs_handle);
+
+ remove_proc_entry("ieee1394", proc_bus);
}
module_init(ieee1394_init);
@@ -815,9 +1042,11 @@ module_exit(ieee1394_cleanup);
/* Exported symbols */
EXPORT_SYMBOL(hpsb_register_lowlevel);
EXPORT_SYMBOL(hpsb_unregister_lowlevel);
-EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_inc_host_usage);
-EXPORT_SYMBOL(hpsb_dec_host_usage);
+EXPORT_SYMBOL(hpsb_alloc_host);
+EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_remove_host);
+EXPORT_SYMBOL(hpsb_ref_host);
+EXPORT_SYMBOL(hpsb_unref_host);
EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(alloc_hpsb_packet);
@@ -867,7 +1096,6 @@ EXPORT_SYMBOL(highlevel_lock64);
EXPORT_SYMBOL(highlevel_add_host);
EXPORT_SYMBOL(highlevel_remove_host);
EXPORT_SYMBOL(highlevel_host_reset);
-EXPORT_SYMBOL(highlevel_add_one_host);
EXPORT_SYMBOL(hpsb_guid_get_entry);
EXPORT_SYMBOL(hpsb_nodeid_get_entry);
@@ -876,3 +1104,9 @@ EXPORT_SYMBOL(hpsb_guid_fill_packet);
EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
EXPORT_SYMBOL(hpsb_release_unit_directory);
+
+EXPORT_SYMBOL(ieee1394_register_chardev);
+EXPORT_SYMBOL(ieee1394_unregister_chardev);
+EXPORT_SYMBOL(ieee1394_devfs_handle);
+
+EXPORT_SYMBOL(ieee1394_procfs_entry);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index fa5d65fb7..e3d1975d9 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -4,6 +4,8 @@
#include <linux/tqueue.h>
#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/proc_fs.h>
#include <asm/semaphore.h>
#include "hosts.h"
@@ -96,7 +98,6 @@ static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
return atomic_read(&host->generation);
}
-
/*
* Queue packet for transmitting, return 0 for failure.
*/
@@ -152,4 +153,65 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
int write_acked);
+
+/*
+ * CHARACTER DEVICE DISPATCHING
+ *
+ * All ieee1394 character device drivers share the same major number
+ * (major 171). The 256 minor numbers are allocated to the various
+ * task-specific interfaces (raw1394, video1394, dv1394, etc) in
+ * blocks of 16.
+ *
+ * The core ieee1394.o modules handles the initial open() for all
+ * character devices on major 171; it then dispatches to the
+ * appropriate task-specific driver.
+ *
+ * Minor device number block allocations:
+ *
+ * Block 0 ( 0- 15) raw1394
+ * Block 1 ( 16- 31) video1394
+ * Block 2 ( 32- 47) dv1394
+ *
+ * Blocks 3-14 free for future allocation
+ *
+ * Block 15 (240-255) reserved for drivers under development, etc.
+ */
+
+#define IEEE1394_MAJOR 171
+
+#define IEEE1394_MINOR_BLOCK_RAW1394 0
+#define IEEE1394_MINOR_BLOCK_VIDEO1394 1
+#define IEEE1394_MINOR_BLOCK_DV1394 2
+#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
+
+/* return the index (within a minor number block) of a file */
+static inline unsigned char ieee1394_file_to_instance(struct file *file)
+{
+ unsigned char minor = minor(file->f_dentry->d_inode->i_rdev);
+
+ /* return lower 4 bits */
+ return minor & 0xF;
+}
+
+/*
+ * Task-specific drivers should call ieee1394_register_chardev() to
+ * request a block of 16 minor numbers.
+ *
+ * Returns 0 if the request was successful, -EBUSY if the block was
+ * already taken.
+ */
+
+int ieee1394_register_chardev(int blocknum, /* 0-15 */
+ struct module *module, /* THIS_MODULE */
+ struct file_operations *file_ops);
+
+/* release a block of minor numbers */
+void ieee1394_unregister_chardev(int blocknum);
+
+/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */
+extern devfs_handle_t ieee1394_devfs_handle;
+
+/* the proc_fs entry for /proc/ieee1394 */
+extern struct proc_dir_entry *ieee1394_procfs_entry;
+
#endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index 7086bc7e2..ca4c26fa8 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -246,7 +246,7 @@ int hpsb_packet_success(struct hpsb_packet *packet)
packet->node_id);
return -EAGAIN;
}
- HPSB_PANIC("reached unreachable code 1 in " __FUNCTION__);
+ HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__);
case ACK_BUSY_X:
case ACK_BUSY_A:
@@ -290,7 +290,7 @@ int hpsb_packet_success(struct hpsb_packet *packet)
return -EAGAIN;
}
- HPSB_PANIC("reached unreachable code 2 in " __FUNCTION__);
+ HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
}
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
index cbeaf4395..5a77d1792 100644
--- a/drivers/ieee1394/ieee1394_types.h
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/version.h>
#include <linux/list.h>
+#include <linux/init.h>
#include <asm/byteorder.h>
@@ -20,6 +21,16 @@
#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
#endif
+/* The great kdev_t changeover in 2.5.x */
+#include <linux/kdev_t.h>
+#ifndef minor
+#define minor(dev) MINOR(dev)
+#endif
+
+#ifndef __devexit_p
+#define __devexit_p(x) x
+#endif
+
/* This showed up around this time */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index d9b293e7d..0dcb0621a 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -16,6 +16,10 @@
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kmod.h>
+#include <linux/completion.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
#include "ieee1394_types.h"
#include "ieee1394.h"
@@ -59,13 +63,200 @@ static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
struct host_info {
struct hpsb_host *host;
- struct tq_struct task;
struct list_head list;
+ struct completion started;
+ struct completion exited;
+ wait_queue_head_t wait;
+ int pid;
};
+#ifdef CONFIG_PROC_FS
+
+static int raw1394_read_proc(char *buffer, char **start, off_t offset,
+ int size, int *eof, void *data )
+{
+ struct list_head *lh;
+ struct node_entry *ne;
+ int disp_size = 0;
+ char display_str[1024];
+
+#define PUTF(fmt, args...) disp_size += sprintf(display_str, fmt, ## args); strcat(buffer,display_str)
+ buffer[0] = '\0';
+ list_for_each(lh, &node_list) {
+ ne = list_entry(lh, struct node_entry, list);
+ if (!ne)
+ continue;
+ PUTF("Node[" NODE_BUS_FMT "] GUID[%016Lx]:\n",
+ NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+ if (ne->host != NULL && ne->host->node_id == ne->nodeid) {
+ PUTF("\tNodes connected : %d\n", ne->host->node_count);
+ PUTF("\tSelfIDs received: %d\n", ne->host->selfid_count);
+ PUTF("\tOwn ID : 0x%08x\n",ne->host->node_id);
+ PUTF("\tIrm ID : 0x%08x\n",ne->host->irm_id);
+ PUTF("\tBusMgr ID : 0x%08x\n",ne->host->busmgr_id);
+ PUTF("\tBR IR IC II IB\n");
+ PUTF("\t%02d %02d %02d %02d %02d\n",
+ ne->host->in_bus_reset, ne->host->is_root,
+ ne->host->is_cycmst, ne->host->is_irm,
+ ne->host->is_busmgr);
+ }
+ PUTF("\tVendor ID: %s [0x%06x]\n",
+ ne->vendor_name ?: "Unknown", ne->vendor_id);
+ PUTF("\tCapabilities: 0x%06x\n", ne->capabilities);
+ PUTF("\tirmc=%d cmc=%d isc=%d bmc=%d pmc=%d cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d\n",
+ ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
+ ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
+ ne->busopt.generation, ne->busopt.lnkspd);
+ }
+#undef PUTF
+ return disp_size;
+}
+#endif /* CONFIG_PROC_FS */
+
static void nodemgr_process_config_rom(struct node_entry *ne,
quadlet_t busoptions);
+static int nodemgr_read_quadlet(struct hpsb_host *host,
+ nodeid_t nodeid, octlet_t address,
+ quadlet_t *quad)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < 3; i++) {
+ ret = hpsb_read(host, nodeid, address, quad, 4);
+ if (ret != -EAGAIN)
+ break;
+ }
+ *quad = be32_to_cpu(*quad);
+
+ return ret;
+}
+
+static int nodemgr_size_text_leaf(struct hpsb_host *host,
+ nodeid_t nodeid,
+ octlet_t address)
+{
+ quadlet_t quad;
+ int size = 0;
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+ return -1;
+ if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {
+ /* This is the offset. */
+ address += 4 * CONFIG_ROM_VALUE(quad);
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+ return -1;
+ /* Now we got the size of the text descriptor leaf. */
+ size = CONFIG_ROM_LEAF_LENGTH(quad);
+ }
+ return size;
+}
+
+static int nodemgr_read_text_leaf(struct hpsb_host *host,
+ nodeid_t nodeid,
+ octlet_t address,
+ quadlet_t *quadp)
+{
+ quadlet_t quad;
+ int i, size, ret;
+
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad)
+ && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
+ return -1;
+
+ /* This is the offset. */
+ address += 4 * CONFIG_ROM_VALUE(quad);
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+ return -1;
+
+ /* Now we got the size of the text descriptor leaf. */
+ size = CONFIG_ROM_LEAF_LENGTH(quad) - 2;
+ if (size <= 0)
+ return -1;
+
+ address += 4;
+ for (i = 0; i < 2; i++, address += 4, quadp++) {
+ if (nodemgr_read_quadlet(host, nodeid, address, quadp))
+ return -1;
+ }
+
+ /* Now read the text string. */
+ ret = -ENXIO;
+ for (; size > 0; size--, address += 4, quadp++) {
+ for (i = 0; i < 3; i++) {
+ ret = hpsb_read(host, nodeid, address, quadp, 4);
+ if (ret != -EAGAIN)
+ break;
+ }
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static struct node_entry *nodemgr_scan_root_directory
+ (struct hpsb_host *host, nodeid_t nodeid)
+{
+ octlet_t address;
+ quadlet_t quad;
+ int length;
+ int code, size, total_size;
+ struct node_entry *ne;
+
+ address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
+
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+ return NULL;
+ address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
+
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+ return NULL;
+ length = CONFIG_ROM_ROOT_LENGTH(quad);
+ address += 4;
+
+ size = 0;
+ total_size = sizeof(struct node_entry);
+ for (; length > 0; length--, address += 4) {
+ if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+ return NULL;
+ code = CONFIG_ROM_KEY(quad);
+
+ if (code == CONFIG_ROM_VENDOR_ID) {
+ /* Check if there is a text descriptor leaf
+ immediately after this. */
+ length--;
+ if (length <= 0)
+ break;
+ address += 4;
+ size = nodemgr_size_text_leaf(host, nodeid,
+ address);
+ switch (size) {
+ case -1:
+ return NULL;
+ break;
+ case 0:
+ break;
+ default:
+ total_size += (size + 1) * sizeof (quadlet_t);
+ break;
+ }
+ break;
+ }
+ }
+ ne = kmalloc(total_size, SLAB_ATOMIC);
+ if (ne != NULL) {
+ if (size != 0) {
+ ne->vendor_name
+ = (const char *) &(ne->quadlets[2]);
+ ne->quadlets[size] = 0;
+ }
+ else {
+ ne->vendor_name = NULL;
+ }
+ }
+ return ne;
+}
static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
struct hpsb_host *host, nodeid_t nodeid)
@@ -73,7 +264,7 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoption
struct node_entry *ne;
unsigned long flags;
- ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
+ ne = nodemgr_scan_root_directory (host, nodeid);
if (!ne) return NULL;
INIT_LIST_HEAD(&ne->list);
@@ -89,9 +280,10 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoption
nodemgr_process_config_rom (ne, busoptions);
- HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx",
+ HPSB_DEBUG("%s added: Node[" NODE_BUS_FMT "] GUID[%016Lx] [%s]",
(host->node_id == nodeid) ? "Local host" : "Device",
- NODE_BUS_ARGS(nodeid), (unsigned long long)guid);
+ NODE_BUS_ARGS(nodeid), (unsigned long long)guid,
+ ne->vendor_name ?: "Unknown");
return ne;
}
@@ -122,30 +314,107 @@ static struct node_entry *find_entry_by_nodeid(nodeid_t nodeid)
return NULL;
}
-int nodemgr_read_quadlet(struct node_entry *ne,
- octlet_t address, quadlet_t *quad)
+static struct unit_directory *nodemgr_scan_unit_directory
+ (struct node_entry *ne, octlet_t address)
{
- int i;
- int ret = 0;
+ struct unit_directory *ud;
+ quadlet_t quad;
+ u8 flags, todo;
+ int length, size, total_size, count;
+ int vendor_name_size, model_name_size;
- for (i = 0; i < 3; i++) {
- ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4);
- if (ret != -EAGAIN)
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+ return NULL;
+ length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
+ address += 4;
+
+ size = 0;
+ total_size = sizeof (struct unit_directory);
+ flags = 0;
+ count = 0;
+ vendor_name_size = 0;
+ model_name_size = 0;
+ for (; length > 0; length--, address += 4) {
+ int code;
+ quadlet_t value;
+
+retry:
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+ return NULL;
+ code = CONFIG_ROM_KEY(quad);
+ value = CONFIG_ROM_VALUE(quad);
+
+ todo = 0;
+ switch (code) {
+ case CONFIG_ROM_VENDOR_ID:
+ todo = UNIT_DIRECTORY_VENDOR_TEXT;
break;
- }
- *quad = be32_to_cpu(*quad);
- return ret;
-}
+ case CONFIG_ROM_MODEL_ID:
+ todo = UNIT_DIRECTORY_MODEL_TEXT;
+ break;
-#define CONFIG_ROM_VENDOR_ID 0x03
-#define CONFIG_ROM_MODEL_ID 0x17
-#define CONFIG_ROM_NODE_CAPABILITES 0x0C
-#define CONFIG_ROM_UNIT_DIRECTORY 0xd1
-#define CONFIG_ROM_SPECIFIER_ID 0x12
-#define CONFIG_ROM_VERSION 0x13
-#define CONFIG_ROM_DESCRIPTOR_LEAF 0x81
-#define CONFIG_ROM_DESCRIPTOR_DIRECTORY 0xc1
+ case CONFIG_ROM_SPECIFIER_ID:
+ case CONFIG_ROM_UNIT_SW_VERSION:
+ break;
+
+ case CONFIG_ROM_DESCRIPTOR_LEAF:
+ case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
+ /* TODO: read strings... icons? */
+ break;
+
+ default:
+ /* Which types of quadlets do we want to
+ store? Only count immediate values and
+ CSR offsets for now. */
+ code &= CONFIG_ROM_KEY_TYPE_MASK;
+ if ((code & 0x80) == 0)
+ count++;
+ break;
+ }
+
+ if (todo) {
+ /* Check if there is a text descriptor leaf
+ immediately after this. */
+ length--;
+ if (length <= 0)
+ break;
+ address += 4;
+ size = nodemgr_size_text_leaf(ne->host,
+ ne->nodeid,
+ address);
+ if (todo | UNIT_DIRECTORY_VENDOR_TEXT)
+ vendor_name_size = size;
+ else
+ model_name_size = size;
+ switch (size) {
+ case -1:
+ return NULL;
+ break;
+ case 0:
+ goto retry;
+ break;
+ default:
+ flags |= todo;
+ total_size += (size + 1) * sizeof (quadlet_t);
+ break;
+ }
+ }
+ }
+ total_size += count * sizeof (quadlet_t);
+ ud = kmalloc (total_size, GFP_KERNEL);
+ if (ud != NULL) {
+ memset (ud, 0, sizeof *ud);
+ ud->flags = flags;
+ ud->count = count;
+ ud->vendor_name_size = vendor_name_size;
+ ud->model_name_size = model_name_size;
+ /* If there is no vendor name in the unit directory,
+ use the one in the root directory. */
+ ud->vendor_name = ne->vendor_name;
+ }
+ return ud;
+}
/* This implementation currently only scans the config rom and its
* immediate unit directories looking for software_id and
@@ -156,41 +425,75 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
octlet_t address)
{
struct unit_directory *ud;
- octlet_t a;
quadlet_t quad;
- int length, i;
+ quadlet_t *infop;
+ int length;
- if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL)))
+ if (!(ud = nodemgr_scan_unit_directory(ne, address)))
goto unit_directory_error;
- memset (ud, 0, sizeof *ud);
ud->ne = ne;
ud->address = address;
- ud->arb_count = 0;
- if (nodemgr_read_quadlet(ne, address, &quad))
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
goto unit_directory_error;
- length = quad >> 16;
- a = address + 4;
+ length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
+ address += 4;
- for (i = 0; i < length; i++, a += 4) {
+ infop = (quadlet_t *) ud->quadlets;
+ for (; length > 0; length--, address += 4, infop++) {
int code;
quadlet_t value;
+ quadlet_t *quadp;
- if (nodemgr_read_quadlet(ne, a, &quad))
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
goto unit_directory_error;
- code = quad >> 24;
- value = quad & 0xffffff;
+ code = CONFIG_ROM_KEY(quad) ;
+ value = CONFIG_ROM_VALUE(quad);
switch (code) {
case CONFIG_ROM_VENDOR_ID:
ud->vendor_id = value;
ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
+ if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) {
+ length--;
+ address += 4;
+ quadp = &(ud->quadlets[ud->count]);
+ if (nodemgr_read_text_leaf(ne->host,
+ ne->nodeid,
+ address,
+ quadp) == 0
+ && quadp[0] == 0
+ && quadp[1] == 0) {
+ /* We only support minimal
+ ASCII and English. */
+ quadp[ud->vendor_name_size] = 0;
+ ud->vendor_name
+ = (const char *) &(quadp[2]);
+ }
+ }
break;
case CONFIG_ROM_MODEL_ID:
ud->model_id = value;
ud->flags |= UNIT_DIRECTORY_MODEL_ID;
+ if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) {
+ length--;
+ address += 4;
+ quadp = &(ud->quadlets[ud->count + ud->vendor_name_size + 1]);
+ if (nodemgr_read_text_leaf(ne->host,
+ ne->nodeid,
+ address,
+ quadp) == 0
+ && quadp[0] == 0
+ && quadp[1] == 0) {
+ /* We only support minimal
+ ASCII and English. */
+ quadp[ud->model_name_size] = 0;
+ ud->model_name
+ = (const char *) &(quadp[2]);
+ }
+ }
break;
case CONFIG_ROM_SPECIFIER_ID:
@@ -198,7 +501,7 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
break;
- case CONFIG_ROM_VERSION:
+ case CONFIG_ROM_UNIT_SW_VERSION:
ud->version = value;
ud->flags |= UNIT_DIRECTORY_VERSION;
break;
@@ -209,12 +512,13 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
break;
default:
- if (ud->arb_count < 16) {
- /* Place them in the arbitrary pairs */
- ud->arb_keys[ud->arb_count] = code;
- ud->arb_values[ud->arb_count] = value;
- ud->arb_count++;
- }
+ /* Which types of quadlets do we want to
+ store? Only count immediate values and
+ CSR offsets for now. */
+ code &= CONFIG_ROM_KEY_TYPE_MASK;
+ if ((code & 0x80) == 0)
+ *infop = quad;
+ break;
}
}
@@ -233,53 +537,73 @@ static void dump_directories (struct node_entry *ne)
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
struct list_head *l;
- HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x",
- ne->vendor_id, ne->capabilities);
+ HPSB_DEBUG("vendor_id=0x%06x [%s], capabilities=0x%06x",
+ ne->vendor_id, ne->vendor_name ?: "Unknown",
+ ne->capabilities);
list_for_each (l, &ne->unit_directories) {
struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
HPSB_DEBUG("unit directory:");
if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
- HPSB_DEBUG(" vendor_id=0x%06x ", ud->vendor_id);
+ HPSB_DEBUG(" vendor_id=0x%06x [%s]",
+ ud->vendor_id,
+ ud->vendor_name ?: "Unknown");
if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
- HPSB_DEBUG(" model_id=0x%06x ", ud->model_id);
+ HPSB_DEBUG(" model_id=0x%06x [%s]",
+ ud->model_id,
+ ud->model_name ?: "Unknown");
if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
HPSB_DEBUG(" sw_specifier_id=0x%06x ", ud->specifier_id);
if (ud->flags & UNIT_DIRECTORY_VERSION)
HPSB_DEBUG(" sw_version=0x%06x ", ud->version);
}
-#else
- return;
#endif
+ return;
}
static void nodemgr_process_root_directory(struct node_entry *ne)
{
octlet_t address;
quadlet_t quad;
- int length, i;
+ int length;
address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
- if (nodemgr_read_quadlet(ne, address, &quad))
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
return;
- address += 4 + (quad >> 24) * 4;
+ address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
- if (nodemgr_read_quadlet(ne, address, &quad))
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
return;
- length = quad >> 16;
+ length = CONFIG_ROM_ROOT_LENGTH(quad);
address += 4;
- for (i = 0; i < length; i++, address += 4) {
+ for (; length > 0; length--, address += 4) {
int code, value;
- if (nodemgr_read_quadlet(ne, address, &quad))
+ if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
return;
- code = quad >> 24;
- value = quad & 0xffffff;
+ code = CONFIG_ROM_KEY(quad);
+ value = CONFIG_ROM_VALUE(quad);
switch (code) {
case CONFIG_ROM_VENDOR_ID:
ne->vendor_id = value;
+ /* Now check if there is a vendor name text
+ string. */
+ if (ne->vendor_name != NULL) {
+ length--;
+ address += 4;
+ if (nodemgr_read_text_leaf(ne->host,
+ ne->nodeid,
+ address,
+ ne->quadlets)
+ != 0
+ || ne->quadlets [0] != 0
+ || ne->quadlets [1] != 0)
+ /* We only support minimal
+ ASCII and English. */
+ ne->vendor_name = NULL;
+ }
break;
case CONFIG_ROM_NODE_CAPABILITES:
@@ -610,6 +934,7 @@ static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid,
int header_count;
unsigned header_size;
quadlet_t quad;
+ int ret;
retry_configrom:
@@ -633,9 +958,10 @@ retry_configrom:
* to work though, and we are forced to doing quadlet
* sized reads. */
- if (hpsb_read(host, nodeid, base, &quad, 4)) {
- HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT,
- NODE_BUS_ARGS(nodeid));
+ ret = hpsb_read(host, nodeid, base, &quad, 4);
+ if (ret) {
+ HPSB_ERR("ConfigROM quadlet transaction error (%d) for node " NODE_BUS_FMT,
+ ret, NODE_BUS_ARGS(nodeid));
goto retry_configrom;
}
buffer[header_count++] = be32_to_cpu(quad);
@@ -649,9 +975,10 @@ retry_configrom:
}
while (header_count <= header_size && header_count < buffer_length) {
- if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {
- HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT,
- NODE_BUS_ARGS(nodeid));
+ ret = hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4);
+ if (ret) {
+ HPSB_ERR("ConfigROM quadlet transaction error (%d) for " NODE_BUS_FMT,
+ ret, NODE_BUS_ARGS(nodeid));
goto retry_configrom;
}
buffer[header_count++] = be32_to_cpu(quad);
@@ -664,8 +991,10 @@ static void nodemgr_remove_node(struct node_entry *ne)
{
unsigned long flags;
- HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx",
- NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+ HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "] GUID[%016Lx] [%s]",
+ (ne->host->node_id == ne->nodeid) ? "Local host" : "Device",
+ NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid,
+ ne->vendor_name ?: "Unknown");
write_lock_irqsave(&unit_directory_lock, flags);
nodemgr_free_unit_directories(ne);
@@ -676,19 +1005,10 @@ static void nodemgr_remove_node(struct node_entry *ne)
return;
}
-/* Used to schedule each nodes config rom probe */
-struct node_probe_task {
- nodeid_t nodeid;
- struct hpsb_host *host;
- atomic_t *count;
- struct tq_struct task;
-};
-
/* This is where we probe the nodes for their information and provided
* features. */
-static void nodemgr_node_probe_one(void *__npt)
+static void nodemgr_node_probe_one(struct hpsb_host *host, nodeid_t nodeid)
{
- struct node_probe_task *npt = (struct node_probe_task *)__npt;
struct node_entry *ne;
quadlet_t buffer[5];
octlet_t guid;
@@ -696,56 +1016,41 @@ static void nodemgr_node_probe_one(void *__npt)
/* We need to detect when the ConfigROM's generation has changed,
* so we only update the node's info when it needs to be. */
- if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2))
- goto probe_complete;
+ if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2))
+ return;
if (buffer[1] != IEEE1394_BUSID_MAGIC) {
/* This isn't a 1394 device */
HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
- NODE_BUS_ARGS(npt->nodeid));
- goto probe_complete;
+ NODE_BUS_ARGS(nodeid));
+ return;
}
guid = ((u64)buffer[3] << 32) | buffer[4];
ne = hpsb_guid_get_entry(guid);
if (!ne)
- nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid);
+ nodemgr_create_node(guid, buffer[2], host, nodeid);
else
- nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid);
-
-probe_complete:
- atomic_dec(npt->count);
-
- kfree(npt);
+ nodemgr_update_node(ne, buffer[2], host, nodeid);
return;
}
-static void nodemgr_node_probe_cleanup(void *__npt)
+static void nodemgr_node_probe_cleanup(struct hpsb_host *host)
{
- struct node_probe_task *npt = (struct node_probe_task *)__npt;
unsigned long flags;
struct list_head *lh, *next;
struct node_entry *ne;
- /* If things aren't done yet, reschedule ourselves. */
- if (atomic_read(npt->count)) {
- schedule_task(&npt->task);
- return;
- }
-
- kfree(npt->count);
-
/* Now check to see if we have any nodes that aren't referenced
* any longer. */
write_lock_irqsave(&node_lock, flags);
- for (lh = node_list.next; lh != &node_list; lh = next) {
+ list_for_each_safe(lh, next, &node_list) {
ne = list_entry(lh, struct node_entry, list);
- next = lh->next;
/* Only checking this host */
- if (ne->host != npt->host)
+ if (ne->host != host)
continue;
/* If the generation didn't get updated, then either the
@@ -757,69 +1062,58 @@ static void nodemgr_node_probe_cleanup(void *__npt)
}
write_unlock_irqrestore(&node_lock, flags);
- kfree(npt);
-
return;
}
-static void nodemgr_node_probe(void *__host)
+static void nodemgr_node_probe(struct hpsb_host *host)
{
- struct hpsb_host *host = (struct hpsb_host *)__host;
int nodecount = host->node_count;
struct selfid *sid = (struct selfid *)host->topology_map;
nodeid_t nodeid = LOCAL_BUS;
- struct node_probe_task *npt;
- atomic_t *count;
-
- count = kmalloc(sizeof (*count), GFP_KERNEL);
-
- if (count == NULL) {
- HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
- return;
- }
-
- atomic_set(count, 0);
+ /* Scan each node on the bus */
for (; nodecount; nodecount--, nodeid++, sid++) {
while (sid->extended)
sid++;
- if (!sid->link_active || nodeid == host->node_id)
+ if (!sid->link_active)
continue;
- npt = kmalloc(sizeof (*npt), GFP_KERNEL);
+ nodemgr_node_probe_one(host, nodeid);
+ }
- if (npt == NULL) {
- HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
- break;
- }
+ /* Cleanup if needed */
+ nodemgr_node_probe_cleanup(host);
- INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt);
- npt->host = host;
- npt->nodeid = nodeid;
- npt->count = count;
+ return;
+}
- atomic_inc(count);
+static int nodemgr_host_thread(void *__hi)
+{
+ struct host_info *hi = (struct host_info *)__hi;
+ lock_kernel();
- schedule_task(&npt->task);
- }
+ /* No userlevel access needed */
+ daemonize();
- /* Now schedule a task to clean things up after the node probes
- * are done. */
- npt = kmalloc (sizeof (*npt), GFP_KERNEL);
+ strcpy(current->comm, "NodeMgr");
- if (npt == NULL) {
- HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
- return;
- }
+ complete(&hi->started);
- INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt);
- npt->host = host;
- npt->nodeid = 0;
- npt->count = count;
+ /* Sit and wait for a signal to probe the nodes on the bus. This
+ * happens when we get a bus reset. */
+ do {
+ interruptible_sleep_on(&hi->wait);
+ if (!signal_pending(current))
+ nodemgr_node_probe(hi->host);
+ } while (!signal_pending(current));
- schedule_task(&npt->task);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+ HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);
+#endif
- return;
+ unlock_kernel();
+
+ complete_and_exit(&hi->exited, 0);
}
struct node_entry *hpsb_guid_get_entry(u64 guid)
@@ -879,7 +1173,18 @@ static void nodemgr_add_host(struct hpsb_host *host)
* until the first bus reset. */
hi->host = host;
INIT_LIST_HEAD(&hi->list);
- INIT_TQUEUE(&hi->task, nodemgr_node_probe, host);
+ init_completion(&hi->started);
+ init_completion(&hi->exited);
+ init_waitqueue_head(&hi->wait);
+
+ hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
+ if (hi->pid < 0) {
+ HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s", host->driver->name);
+ return;
+ }
+
+ wait_for_completion(&hi->started);
spin_lock_irqsave (&host_info_lock, flags);
list_add_tail (&hi->list, &host_info_list);
@@ -908,7 +1213,11 @@ static void nodemgr_host_reset(struct hpsb_host *host)
goto done_reset_host;
}
- schedule_task(&hi->task);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+ HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
+#endif
+
+ wake_up(&hi->wait);
done_reset_host:
spin_unlock_irqrestore (&host_info_lock, flags);
@@ -921,40 +1230,42 @@ static void nodemgr_remove_host(struct hpsb_host *host)
struct list_head *lh, *next;
struct node_entry *ne;
unsigned long flags;
+ struct host_info *hi = NULL;
+
+ spin_lock_irqsave (&host_info_lock, flags);
+ list_for_each_safe(lh, next, &host_info_list) {
+ struct host_info *myhi = list_entry(lh, struct host_info, list);
+ if (myhi->host == host) {
+ list_del(&myhi->list);
+ hi = myhi;
+ break;
+ }
+ }
- /* Make sure we have no active scans */
- flush_scheduled_tasks();
+ if (!hi)
+ HPSB_ERR ("NodeMgr: host %s does not exist, cannot remove",
+ host->driver->name);
+ spin_unlock_irqrestore (&host_info_lock, flags);
- /* First remove all node entries for this host */
+ /* Even if we fail the host_info part, remove all the node
+ * entries. */
write_lock_irqsave(&node_lock, flags);
-
- for (lh = node_list.next; lh != &node_list; lh = next) {
+ list_for_each_safe(lh, next, &node_list) {
ne = list_entry(lh, struct node_entry, list);
- next = lh->next;
-
- /* Only checking this host */
- if (ne->host != host)
- continue;
+ if (ne->host == host)
nodemgr_remove_node(ne);
}
write_unlock_irqrestore(&node_lock, flags);
- spin_lock_irqsave (&host_info_lock, flags);
- list_for_each_safe(lh, next, &host_info_list) {
- struct host_info *hi = list_entry(lh, struct host_info, list);
- if (hi->host == host) {
- list_del(&hi->list);
- kfree (hi);
- break;
+ if (hi) {
+ if (hi->pid >= 0) {
+ kill_proc(hi->pid, SIGTERM, 1);
+ wait_for_completion(&hi->exited);
}
+ kfree(hi);
}
- if (lh == host_info_list.next)
- HPSB_ERR ("NodeMgr: could not remove non-existent host");
-
- spin_unlock_irqrestore (&host_info_lock, flags);
-
return;
}
@@ -966,8 +1277,14 @@ static struct hpsb_highlevel_ops nodemgr_ops = {
static struct hpsb_highlevel *hl;
+#define PROC_ENTRY "devices"
+
void init_ieee1394_nodemgr(void)
{
+#ifdef CONFIG_PROC_FS
+ if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL))
+ HPSB_ERR("Can't create devices procfs entry");
+#endif
hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
if (!hl) {
HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
@@ -977,4 +1294,7 @@ void init_ieee1394_nodemgr(void)
void cleanup_ieee1394_nodemgr(void)
{
hpsb_unregister_highlevel(hl);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry);
+#endif
}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index 46f574e64..7d67add26 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -20,6 +20,44 @@
#ifndef _IEEE1394_NODEMGR_H
#define _IEEE1394_NODEMGR_H
+#define CONFIG_ROM_BUS_INFO_LENGTH(q) ((q) >> 24)
+#define CONFIG_ROM_BUS_CRC_LENGTH(q) (((q) >> 16) & 0xff)
+#define CONFIG_ROM_BUS_CRC(q) ((q) & 0xffff)
+
+#define CONFIG_ROM_ROOT_LENGTH(q) ((q) >> 16)
+#define CONFIG_ROM_ROOT_CRC(q) ((q) & 0xffff)
+
+#define CONFIG_ROM_DIRECTORY_LENGTH(q) ((q) >> 16)
+#define CONFIG_ROM_DIRECTORY_CRC(q) ((q) & 0xffff)
+
+#define CONFIG_ROM_LEAF_LENGTH(q) ((q) >> 16)
+#define CONFIG_ROM_LEAF_CRC(q) ((q) & 0xffff)
+
+#define CONFIG_ROM_DESCRIPTOR_TYPE(q) ((q) >> 24)
+#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q) ((q) & 0xffffff)
+#define CONFIG_ROM_DESCRIPTOR_WIDTH(q) ((q) >> 28)
+#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q) (((q) >> 16) & 0xfff)
+#define CONFIG_ROM_DESCRIPTOR_LANG(q) ((q) & 0xffff)
+
+#define CONFIG_ROM_KEY_ID_MASK 0x3f
+#define CONFIG_ROM_KEY_TYPE_MASK 0xc0
+#define CONFIG_ROM_KEY_TYPE_IMMEDIATE 0x00
+#define CONFIG_ROM_KEY_TYPE_OFFSET 0x40
+#define CONFIG_ROM_KEY_TYPE_LEAF 0x80
+#define CONFIG_ROM_KEY_TYPE_DIRECTORY 0xc0
+
+#define CONFIG_ROM_KEY(q) ((q) >> 24)
+#define CONFIG_ROM_VALUE(q) ((q) & 0xffffff)
+
+#define CONFIG_ROM_VENDOR_ID 0x03
+#define CONFIG_ROM_MODEL_ID 0x17
+#define CONFIG_ROM_NODE_CAPABILITES 0x0C
+#define CONFIG_ROM_UNIT_DIRECTORY 0xd1
+#define CONFIG_ROM_SPECIFIER_ID 0x12
+#define CONFIG_ROM_UNIT_SW_VERSION 0x13
+#define CONFIG_ROM_DESCRIPTOR_LEAF 0x81
+#define CONFIG_ROM_DESCRIPTOR_DIRECTORY 0xc1
+
/* '1' '3' '9' '4' in ASCII */
#define IEEE1394_BUSID_MAGIC 0x31333934
@@ -42,6 +80,8 @@ struct bus_options {
#define UNIT_DIRECTORY_MODEL_ID 0x02
#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
#define UNIT_DIRECTORY_VERSION 0x08
+#define UNIT_DIRECTORY_VENDOR_TEXT 0x10
+#define UNIT_DIRECTORY_MODEL_TEXT 0x20
/*
* A unit directory corresponds to a protocol supported by the
@@ -58,17 +98,14 @@ struct unit_directory {
octlet_t address; /* Address of the unit directory on the node */
u8 flags; /* Indicates which entries were read */
quadlet_t vendor_id;
- char *vendor_name;
+ const char *vendor_name;
+ int vendor_name_size;
quadlet_t model_id;
- char *model_name;
+ const char *model_name;
+ int model_name_size;
quadlet_t specifier_id;
quadlet_t version;
- /* Groupings for arbitrary key/value pairs */
- int arb_count; /* Number of arbitrary key/values */
- char arb_keys[16]; /* Up to 16 keys */
- quadlet_t arb_values[16]; /* Same for values */
-
struct hpsb_protocol_driver *driver;
void *driver_data;
@@ -77,6 +114,9 @@ struct unit_directory {
/* For linking directories belonging to a node */
struct list_head node_list;
+
+ int count; /* Number of quadlets */
+ quadlet_t quadlets[0];
};
struct node_entry {
@@ -91,6 +131,9 @@ struct node_entry {
u32 vendor_id;
u32 capabilities;
struct list_head unit_directories;
+
+ const char *vendor_name;
+ quadlet_t quadlets[0];
};
static inline int hpsb_node_entry_valid(struct node_entry *ne)
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 9b55ff5fd..7838f495f 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -77,6 +77,12 @@
* . Config ROM generation
*/
+/* Issues:
+ *
+ * - devctl BUS_RESET should treat arg as reset type
+ *
+ */
+
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -135,10 +141,10 @@ printk(KERN_INFO "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
#define OHCI_DMA_ALLOC(fmt, args...) \
- HPSB_ERR("%s("__FUNCTION__")alloc(%d): "fmt, OHCI1394_DRIVER_NAME, \
+ HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
++global_outstanding_dmas, ## args)
#define OHCI_DMA_FREE(fmt, args...) \
- HPSB_ERR("%s("__FUNCTION__")free(%d): "fmt, OHCI1394_DRIVER_NAME, \
+ HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
--global_outstanding_dmas, ## args)
u32 global_outstanding_dmas = 0;
#else
@@ -154,35 +160,23 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
#define PRINT(level, card, fmt, args...) \
printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
-#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
-static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
- {
- class: PCI_CLASS_FIREWIRE_OHCI,
- class_mask: 0x00ffffff,
- vendor: PCI_ANY_ID,
- device: PCI_ANY_ID,
- subvendor: PCI_ANY_ID,
- subdevice: PCI_ANY_ID,
- },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
static char version[] __devinitdata =
- "$Revision: 1.80 $ Ben Collins <bcollins@debian.org>";
+ "$Revision: 1.91 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
MODULE_PARM(attempt_root,"i");
MODULE_PARM_DESC(attempt_root, "Attempt to make the host root.");
static int attempt_root = 0;
-static unsigned int card_id_counter = 0;
-
static void dma_trm_tasklet(unsigned long data);
-static void remove_card(struct ti_ohci *ohci);
static void dma_trm_reset(struct dma_trm_ctx *d);
+static void __devexit ohci1394_pci_remove(struct pci_dev *pdev);
+
+static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
+ quadlet_t isoRecvEvent,
+ quadlet_t isoXmitEvent);
+
#ifndef __LITTLE_ENDIAN
/* Swap a series of quads inplace. */
static __inline__ void block_swab32(quadlet_t *data, size_t size) {
@@ -310,8 +304,8 @@ static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
if ((self_id_count & 0x80000000) ||
((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
PRINT(KERN_ERR, ohci->id,
- "Error in reception of SelfID packets [0x%08x/0x%08x]",
- self_id_count, q0);
+ "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
+ self_id_count, q0, ohci->self_id_errors);
/* Tip by James Goodwin <jamesg@Filanet.com>:
* We had an error, generate another bus reset in response. */
@@ -324,6 +318,9 @@ static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
}
return;
}
+
+ /* SelfID Ok, reset error counter. */
+ ohci->self_id_errors = 0;
size = ((self_id_count & 0x00001FFC) >> 2) - 1;
q++;
@@ -357,7 +354,7 @@ static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
return;
}
-static int ohci_soft_reset(struct ti_ohci *ohci) {
+static void ohci_soft_reset(struct ti_ohci *ohci) {
int i;
reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
@@ -368,9 +365,13 @@ static int ohci_soft_reset(struct ti_ohci *ohci) {
mdelay(1);
}
- DBGMSG (ohci->id, "Soft reset finished");
+ /* Now reenable LPS, since that's usually what we want after a
+ * softreset anyway. Wait 50msec to make sure we have full link
+ * enabled. */
+ reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+ mdelay(50);
- return 0;
+ DBGMSG (ohci->id, "Soft reset finished");
}
static int run_context(struct ti_ohci *ohci, int reg, char *msg)
@@ -411,8 +412,7 @@ static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
for (i=0; i<d->num_desc; i++) {
u32 c;
- c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH;
+ c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
if (generate_irq)
c |= DMA_CTL_IRQ;
@@ -485,19 +485,14 @@ static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
static void ohci_init_config_rom(struct ti_ohci *ohci);
/* Global initialization */
-static int ohci_initialize(struct hpsb_host *host)
+static void ohci_initialize(struct ti_ohci *ohci)
{
- struct ti_ohci *ohci=host->hostdata;
- int retval, i;
+ int i;
quadlet_t buf;
spin_lock_init(&ohci->phy_reg_lock);
spin_lock_init(&ohci->event_lock);
- /* Soft reset */
- if ((retval = ohci_soft_reset(ohci)) < 0)
- return retval;
-
/* Put some defaults to these undefined bus options */
buf = reg_read(ohci, OHCI1394_BusOptions);
buf |= 0x60000000; /* Enable CMC and ISC */
@@ -505,16 +500,6 @@ static int ohci_initialize(struct hpsb_host *host)
buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */
reg_write(ohci, OHCI1394_BusOptions, buf);
- /* Set Link Power Status (LPS) */
- reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
-
- /* After enabling LPS, we need to wait for the connection
- * between phy and link to be established. This should be
- * signaled by the LPS bit becoming 1, but this happens
- * immediately. There seems to be no consistent way to wait
- * for this, but 50ms seems to be enough. */
- mdelay(50);
-
/* Set the bus number */
reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
@@ -551,10 +536,6 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
/* Initialize IR dma */
- ohci->nb_iso_rcv_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
- DBGMSG(ohci->id, "%d iso receive contexts available",
- ohci->nb_iso_rcv_ctx);
for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
0xffffffff);
@@ -573,10 +554,6 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
/* Initialize IT dma */
- ohci->nb_iso_xmit_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
- DBGMSG(ohci->id, "%d iso transmit contexts available",
- ohci->nb_iso_xmit_ctx);
for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
0xffffffff);
@@ -638,32 +615,19 @@ static int ohci_initialize(struct hpsb_host *host)
OHCI1394_respTxComplete |
OHCI1394_reqTxComplete |
OHCI1394_isochRx |
- OHCI1394_isochTx |
- OHCI1394_unrecoverableError
- );
+ OHCI1394_isochTx);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
buf = reg_read(ohci, OHCI1394_Version);
- PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] MMIO=[%lx-%lx]"
- " Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
+ PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] "
+ "MMIO=[%lx-%lx] Max Packet=[%d]",
+ ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
pci_resource_start(ohci->dev, 0),
pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),
ohci->max_packet_size);
-
- return 1;
-}
-
-static void ohci_remove(struct hpsb_host *host)
-{
- struct ti_ohci *ohci;
-
- if (host != NULL) {
- ohci = host->hostdata;
- remove_card(ohci);
- }
}
/*
@@ -685,7 +649,7 @@ static void insert_packet(struct ti_ohci *ohci,
d->prg_cpu[idx]->begin.address = 0;
d->prg_cpu[idx]->begin.branchAddress = 0;
- if (d->ctx==1) {
+ if (d->type == DMA_CTX_ASYNC_RESP) {
/*
* For response packets, we need to put a timeout value in
* the 16 lower bits of the status... let's try 1 sec timeout
@@ -734,9 +698,9 @@ static void insert_packet(struct ti_ohci *ohci,
if (cross_bound((unsigned long)packet->data,
packet->data_size)>0) {
/* FIXME: do something about it */
- PRINT(KERN_ERR, ohci->id, __FUNCTION__
- ": packet data addr: %p size %Zd bytes "
- "cross page boundary",
+ PRINT(KERN_ERR, ohci->id,
+ "%s: packet data addr: %p size %Zd bytes "
+ "cross page boundary", __FUNCTION__,
packet->data, packet->data_size);
}
@@ -926,10 +890,8 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
switch (cmd) {
case RESET_BUS:
DBGMSG(ohci->id, "devctl: Bus reset requested%s",
- ((host->attempt_root || attempt_root) ?
- " and attempting to become root" : ""));
- set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?
- 0x80 : 0));
+ attempt_root ? " and attempting to become root" : "");
+ set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0));
break;
case GET_CYCLE_COUNTER:
@@ -981,9 +943,9 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
u64 mask;
if (arg<0 || arg>63) {
- PRINT(KERN_ERR, ohci->id, __FUNCTION__
- "IS0 listen channel %d is out of range",
- arg);
+ PRINT(KERN_ERR, ohci->id,
+ "%s: IS0 listen channel %d is out of range",
+ __FUNCTION__, arg);
return -EFAULT;
}
@@ -992,9 +954,9 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
spin_lock_irqsave(&ohci->IR_channel_lock, flags);
if (ohci->ISO_channel_usage & mask) {
- PRINT(KERN_ERR, ohci->id, __FUNCTION__
- "IS0 listen channel %d is already used",
- arg);
+ PRINT(KERN_ERR, ohci->id,
+ "%s: IS0 listen channel %d is already used",
+ __FUNCTION__, arg);
spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
return -EFAULT;
}
@@ -1017,9 +979,9 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
u64 mask;
if (arg<0 || arg>63) {
- PRINT(KERN_ERR, ohci->id, __FUNCTION__
- "IS0 unlisten channel %d is out of range",
- arg);
+ PRINT(KERN_ERR, ohci->id,
+ "%s: IS0 unlisten channel %d is out of range",
+ __FUNCTION__, arg);
return -EFAULT;
}
@@ -1028,9 +990,9 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
spin_lock_irqsave(&ohci->IR_channel_lock, flags);
if (!(ohci->ISO_channel_usage & mask)) {
- PRINT(KERN_ERR, ohci->id, __FUNCTION__
- "IS0 unlisten channel %d is not used",
- arg);
+ PRINT(KERN_ERR, ohci->id,
+ "%s: IS0 unlisten channel %d is not used",
+ __FUNCTION__, arg);
spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
return -EFAULT;
}
@@ -1133,7 +1095,6 @@ static void ohci_irq_handler(int irq, void *dev_id,
/* Die right here an now */
if (event & OHCI1394_unrecoverableError) {
PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!");
- remove_card(ohci);
return;
}
@@ -1156,8 +1117,8 @@ static void ohci_irq_handler(int irq, void *dev_id,
spin_unlock_irqrestore(&ohci->event_lock, flags);
if (!host->in_bus_reset) {
DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",
- ((host->attempt_root || attempt_root) ?
- " and attempting to become root" : ""));
+ (attempt_root) ? " and attempting to become root"
+ : "");
/* Subsystem call */
hpsb_bus_reset(ohci->host);
@@ -1228,9 +1189,9 @@ static void ohci_irq_handler(int irq, void *dev_id,
else
tasklet_schedule(&d->task);
}
- if (ohci->video_tmpl)
- ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent,
- 0);
+
+ ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0);
+
event &= ~OHCI1394_isochRx;
}
if (event & OHCI1394_isochTx) {
@@ -1243,9 +1204,9 @@ static void ohci_irq_handler(int irq, void *dev_id,
DBGMSG(ohci->id, "Got isochTx interrupt "
"status=0x%08x isoXmitIntEvent=%08x",
reg_read(ohci, d->ctrlSet), isoXmitIntEvent);
- if (ohci->video_tmpl)
- ohci->video_tmpl->irq_handler(ohci->id, 0,
- isoXmitIntEvent);
+
+ ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent);
+
if (isoXmitIntEvent & 0x1) {
if (reg_read(ohci, d->ctrlSet) & 0x800)
ohci1394_stop_context(ohci, d->ctrlClear, "isochTx");
@@ -1352,7 +1313,7 @@ static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *b
{
int length = -1;
- if (d->ctx < 2) { /* Async Receive Response/Request */
+ if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
length = TCODE_SIZE[tcode];
if (length == 0) {
if (offset + 12 >= d->buf_size) {
@@ -1363,7 +1324,7 @@ static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *b
}
length += 20;
}
- } else if (d->ctx == 2) { /* Iso receive */
+ } else if (d->type == DMA_CTX_ISO) {
/* Assumption: buffer fill mode with header/trailer */
length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
}
@@ -1393,11 +1354,8 @@ static void dma_rcv_tasklet (unsigned long data)
offset = d->buf_offset;
buf_ptr = d->buf_cpu[idx] + offset/4;
- dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status));
rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
bytes_left = d->buf_size - rescount - offset;
- dma_cache_wback_inv(buf_ptr, bytes_left);
while (bytes_left > 0) {
tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
@@ -1449,7 +1407,6 @@ static void dma_rcv_tasklet (unsigned long data)
insert_dma_buffer(d, idx);
idx = (idx+1) % d->num_desc;
buf_ptr = d->buf_cpu[idx];
- dma_cache_wback_inv(buf_ptr, d->buf_size);
offset=0;
while (split_left >= d->buf_size) {
@@ -1459,7 +1416,6 @@ static void dma_rcv_tasklet (unsigned long data)
insert_dma_buffer(d, idx);
idx = (idx+1) % d->num_desc;
buf_ptr = d->buf_cpu[idx];
- dma_cache_wback_inv(buf_ptr, d->buf_size);
}
if (split_left > 0) {
@@ -1506,8 +1462,6 @@ static void dma_rcv_tasklet (unsigned long data)
d->ctx);
#endif
- dma_cache_wback_inv(&(d->prg_cpu[idx]->status),
- sizeof(d->prg_cpu[idx]->status));
rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
bytes_left = d->buf_size - rescount - offset;
@@ -1646,6 +1600,11 @@ static int free_dma_rcv_ctx(struct dma_rcv_ctx **d)
}
if ((*d)->spb) kfree((*d)->spb);
+ /* clear ISO context usage bit */
+ if ((*d)->type == DMA_CTX_ISO) {
+ clear_bit((*d)->ctx, &ohci->ir_ctx_usage);
+ }
+
kfree(*d);
*d = NULL;
@@ -1653,15 +1612,21 @@ static int free_dma_rcv_ctx(struct dma_rcv_ctx **d)
}
static struct dma_rcv_ctx *
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
- int buf_size, int split_buf_size,
- int ctrlSet, int ctrlClear, int cmdPtr)
+alloc_dma_rcv_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+ int buf_size, int split_buf_size, int context_base)
{
- struct dma_rcv_ctx *d=NULL;
+ struct dma_rcv_ctx *d;
int i;
- d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx),
- GFP_KERNEL);
+ if (type == DMA_CTX_ISO) {
+ /* try to claim the ISO context usage bit */
+ if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) {
+ PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx);
+ return NULL;
+ }
+ }
+
+ d = kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL);
if (d == NULL) {
PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx");
@@ -1670,21 +1635,17 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
memset (d, 0, sizeof (struct dma_rcv_ctx));
- d->ohci = (void *)ohci;
+ d->ohci = ohci;
+ d->type = type;
d->ctx = ctx;
d->num_desc = num_desc;
d->buf_size = buf_size;
d->split_buf_size = split_buf_size;
- d->ctrlSet = ctrlSet;
- d->ctrlClear = ctrlClear;
- d->cmdPtr = cmdPtr;
- d->buf_cpu = NULL;
- d->buf_bus = NULL;
- d->prg_cpu = NULL;
- d->prg_bus = NULL;
- d->spb = NULL;
+ d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+ d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+ d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
@@ -1783,36 +1744,47 @@ static int free_dma_trm_ctx(struct dma_trm_ctx **d)
kfree((*d)->prg_bus);
}
+ /* clear the ISO context usage bit */
+ if ((*d)->type == DMA_CTX_ISO) {
+ clear_bit((*d)->ctx, &ohci->it_ctx_usage);
+ }
+
kfree(*d);
*d = NULL;
return 0;
}
static struct dma_trm_ctx *
-alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
- int ctrlSet, int ctrlClear, int cmdPtr)
+alloc_dma_trm_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+ int context_base)
{
- struct dma_trm_ctx *d=NULL;
+ struct dma_trm_ctx *d;
int i;
- d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx),
- GFP_KERNEL);
+ if (type == DMA_CTX_ISO) {
+ /* try to claim the ISO context usage bit */
+ if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) {
+ PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx);
+ return NULL;
+ }
+ }
+
+ d = kmalloc(sizeof(struct dma_trm_ctx), GFP_KERNEL);
- if (d==NULL) {
+ if (d == NULL) {
PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx");
return NULL;
}
memset (d, 0, sizeof (struct dma_trm_ctx));
- d->ohci = (void *)ohci;
+ d->ohci = ohci;
+ d->type = type;
d->ctx = ctx;
d->num_desc = num_desc;
- d->ctrlSet = ctrlSet;
- d->ctrlClear = ctrlClear;
- d->cmdPtr = cmdPtr;
- d->prg_cpu = NULL;
- d->prg_bus = NULL;
+ d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+ d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+ d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*),
GFP_KERNEL);
@@ -1826,7 +1798,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
- for (i=0; i<d->num_desc; i++) {
+ for (i = 0; i < d->num_desc; i++) {
d->prg_cpu[i] = pci_alloc_consistent(ohci->dev,
sizeof(struct at_dma_prg),
d->prg_bus+i);
@@ -1889,6 +1861,21 @@ struct config_rom_ptr {
#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))
+static inline void cf_put_str(struct config_rom_ptr *cr, const char *str)
+{
+ int t;
+ char fourb[4];
+
+ while (str[0]) {
+ memset(fourb, 0, 4);
+ for (t = 0; t < 4 && str[t]; t++)
+ fourb[t] = str[t];
+ cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]);
+ str += strlen(str) < 4 ? strlen(str) : 4;
+ }
+ return;
+}
+
static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit)
{
*cr->unitdir[unit].start =
@@ -1965,9 +1952,7 @@ static void ohci_init_config_rom(struct ti_ohci *ohci)
cf_unit_begin(&cr, 2);
cf_put_keyval(&cr, 0, 0);
cf_put_1quad(&cr, 0);
- cf_put_4bytes(&cr, 'L', 'i', 'n', 'u');
- cf_put_4bytes(&cr, 'x', ' ', '1', '3');
- cf_put_4bytes(&cr, '9', '4', 0x0, 0x0);
+ cf_put_str(&cr, "Linux OHCI-1394");
cf_unit_end(&cr);
ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
@@ -1985,13 +1970,15 @@ static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr)
return ohci->csr_config_rom_length * 4;
}
-int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,
- quadlet_t compare, int sel)
+static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
+ quadlet_t data, quadlet_t compare)
{
+ struct ti_ohci *ohci = host->hostdata;
int i;
- reg_write(ohci, OHCI1394_CSRData, *data);
+
+ reg_write(ohci, OHCI1394_CSRData, data);
reg_write(ohci, OHCI1394_CSRCompareData, compare);
- reg_write(ohci, OHCI1394_CSRControl, sel & 0x3);
+ reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
for (i = 0; i < OHCI_LOOP_COUNT; i++) {
if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
@@ -2000,68 +1987,58 @@ int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,
mdelay(1);
}
- *data = reg_read(ohci, OHCI1394_CSRData);
- return 0;
-}
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
- quadlet_t data, quadlet_t compare)
-{
- struct ti_ohci *ohci=host->hostdata;
-
- ohci_compare_swap (ohci, &data, compare, reg);
-
- return data;
+ return reg_read(ohci, OHCI1394_CSRData);
}
-static struct hpsb_host_template ohci_template = {
- name: OHCI1394_DRIVER_NAME,
- initialize_host: ohci_initialize,
- release_host: ohci_remove,
+static struct hpsb_host_operations ohci1394_ops = {
get_rom: ohci_get_rom,
transmit_packet: ohci_transmit,
devctl: ohci_devctl,
hw_csr_reg: ohci_hw_csr_reg,
};
+static struct hpsb_host_driver *ohci1394_driver;
+
+
+
+/***********************************
+ * PCI Driver Interface functions *
+ ***********************************/
-#define FAIL(fmt, args...) \
+#define FAIL(err, fmt, args...) \
do { \
PRINT_G(KERN_ERR, fmt , ## args); \
- remove_card(ohci); \
- return 1; \
+ ohci1394_pci_remove(dev); \
+ return err; \
} while(0)
-static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
+static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- struct ti_ohci *ohci; /* shortcut to currently handled device */
- struct hpsb_host *host;
- unsigned long ohci_base, ohci_len;
+ static unsigned int card_id_counter = 0;
static int version_printed = 0;
+ struct hpsb_host *host;
+ struct ti_ohci *ohci; /* shortcut to currently handled device */
+ unsigned long ohci_base, ohci_len;
+ int i;
+
if (version_printed++ == 0)
PRINT_G(KERN_INFO, "%s", version);
- if (pci_enable_device(dev)) {
- /* Skip ID's that fail */
- PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d",
- card_id_counter++);
- return -ENXIO;
- }
+ if (pci_enable_device(dev))
+ FAIL(-ENXIO, "Failed to enable OHCI hardware %d",
+ card_id_counter++);
pci_set_master(dev);
- host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci));
- if (!host) {
- PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");
- return -ENOMEM;
- }
+ host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci));
+ if (!host) FAIL(-ENOMEM, "Failed to allocate host structure");
+
ohci = host->hostdata;
- ohci->host = host;
- INIT_LIST_HEAD(&ohci->list);
ohci->id = card_id_counter++;
ohci->dev = dev;
- host->pdev = dev;
ohci->host = host;
+ host->pdev = dev;
pci_set_drvdata(dev, ohci);
/* We don't want hardware swapping */
@@ -2089,8 +2066,54 @@ static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_devi
&ohci->csr_config_rom_bus);
OHCI_DMA_ALLOC("consistent csr_config_rom");
if (ohci->csr_config_rom_cpu == NULL)
- FAIL("Failed to allocate buffer config rom");
+ FAIL(-ENOMEM, "Failed to allocate buffer config rom");
+
+ ohci_base = pci_resource_start(dev, 0);
+ ohci_len = pci_resource_len(dev, 0);
+
+ if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME))
+ FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
+ ohci_base, ohci_len);
+
+ ohci->registers = ioremap(ohci_base, ohci_len);
+
+ if (ohci->registers == NULL)
+ FAIL(-ENXIO, "Failed to remap registers - card not accessible");
+
+ DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers);
+
+
+ /* Start off with a softreset, to clear everything to a sane
+ * state. This will also set Link Power State (LPS), which we
+ * need in order to start accessing most of the registers. */
+ ohci_soft_reset(ohci);
+
+ /* determinte the number of available IR and IT contexts right away,
+ because they need to be known for alloc_dma_*_ctx() */
+ ohci->nb_iso_rcv_ctx =
+ get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
+ DBGMSG(ohci->id, "%d iso receive contexts available",
+ ohci->nb_iso_rcv_ctx);
+
+ ohci->ir_ctx_usage = 0;
+
+ /* set the usage bits for non-existent contexts so they can't be allocated */
+ for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++)
+ __set_bit(i, &ohci->ir_ctx_usage);
+
+ ohci->nb_iso_xmit_ctx =
+ get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
+ DBGMSG(ohci->id, "%d iso transmit contexts available",
+ ohci->nb_iso_xmit_ctx);
+
+ ohci->it_ctx_usage = 0;
+
+ /* set the usage bits for non-existent contexts so they can't be allocated */
+ for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++)
+ __set_bit(i, &ohci->it_ctx_usage);
+
+
/*
* self-id dma buffer allocation
*/
@@ -2099,103 +2122,101 @@ static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_devi
&ohci->selfid_buf_bus);
OHCI_DMA_ALLOC("consistent selfid_buf");
if (ohci->selfid_buf_cpu == NULL)
- FAIL("Failed to allocate DMA buffer for self-id packets");
+ FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "
"8Kb boundary... may cause problems on some CXD3222 chip",
ohci->selfid_buf_cpu);
- ohci->it_context =
- alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC,
- OHCI1394_IsoXmitContextControlSet,
- OHCI1394_IsoXmitContextControlClear,
- OHCI1394_IsoXmitCommandPtr);
-
- if (ohci->it_context == NULL)
- FAIL("Failed to allocate IT context");
-
- ohci_base = pci_resource_start(dev, 0);
- ohci_len = pci_resource_len(dev, 0);
-
- if (!request_mem_region (ohci_base, ohci_len, host->template->name))
- FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
- ohci_base, ohci_len);
-
- ohci->registers = ioremap(ohci_base, ohci_len);
-
- if (ohci->registers == NULL)
- FAIL("Failed to remap registers - card not accessible");
-
- DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p",
- ohci->registers);
+ /* No self-id errors at startup */
+ ohci->self_id_errors = 0;
+ /* AR DMA request context allocation */
ohci->ar_req_context =
- alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
+ alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
- OHCI1394_AsReqRcvContextControlSet,
- OHCI1394_AsReqRcvContextControlClear,
- OHCI1394_AsReqRcvCommandPtr);
+ OHCI1394_AsReqRcvContextBase);
if (ohci->ar_req_context == NULL)
- FAIL("Failed to allocate AR Req context");
+ FAIL(-ENOMEM, "Failed to allocate AR Req context");
+ /* AR DMA response context allocation */
ohci->ar_resp_context =
- alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,
+ alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
- OHCI1394_AsRspRcvContextControlSet,
- OHCI1394_AsRspRcvContextControlClear,
- OHCI1394_AsRspRcvCommandPtr);
+ OHCI1394_AsRspRcvContextBase);
if (ohci->ar_resp_context == NULL)
- FAIL("Failed to allocate AR Resp context");
+ FAIL(-ENOMEM, "Failed to allocate AR Resp context");
+ /* AT DMA request context */
ohci->at_req_context =
- alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,
- OHCI1394_AsReqTrContextControlSet,
- OHCI1394_AsReqTrContextControlClear,
- OHCI1394_AsReqTrCommandPtr);
+ alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
+ OHCI1394_AsReqTrContextBase);
if (ohci->at_req_context == NULL)
- FAIL("Failed to allocate AT Req context");
+ FAIL(-ENOMEM, "Failed to allocate AT Req context");
+ /* AT DMA response context */
ohci->at_resp_context =
- alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,
- OHCI1394_AsRspTrContextControlSet,
- OHCI1394_AsRspTrContextControlClear,
- OHCI1394_AsRspTrCommandPtr);
+ alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
+ OHCI1394_AsRspTrContextBase);
if (ohci->at_resp_context == NULL)
- FAIL("Failed to allocate AT Resp context");
+ FAIL(-ENOMEM, "Failed to allocate AT Resp context");
+ /* IR DMA context */
ohci->ir_context =
- alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
+ alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC,
IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
- OHCI1394_IsoRcvContextControlSet,
- OHCI1394_IsoRcvContextControlClear,
- OHCI1394_IsoRcvCommandPtr);
+ OHCI1394_IsoRcvContextBase);
if (ohci->ir_context == NULL)
- FAIL("Failed to allocate IR context");
+ FAIL(-ENOMEM, "Failed to allocate IR context");
+
+
+ /* IT DMA context allocation */
+ ohci->it_context =
+ alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC,
+ OHCI1394_IsoXmitContextBase);
+
+ if (ohci->it_context == NULL)
+ FAIL(-ENOMEM, "Failed to allocate IT context");
ohci->ISO_channel_usage = 0;
spin_lock_init(&ohci->IR_channel_lock);
+ for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+ ohci->irq_hooks[i].irq_handler = NULL;
+ ohci->irq_hooks[i].data = NULL;
+ }
+
if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
OHCI1394_DRIVER_NAME, ohci))
- FAIL("Failed to allocate shared interrupt %d", dev->irq);
+ FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
+
+ ohci_initialize(ohci);
/* Tell the highlevel this host is ready */
- highlevel_add_one_host (host);
+ hpsb_add_host(host);
return 0;
#undef FAIL
}
-static void remove_card(struct ti_ohci *ohci)
+static void __devexit ohci1394_pci_remove(struct pci_dev *pdev)
{
+ struct ti_ohci *ohci;
quadlet_t buf;
+ ohci = pci_get_drvdata(pdev);
+ if (!ohci)
+ return;
+
+ if (ohci->host)
+ hpsb_remove_host(ohci->host);
+
/* Soft reset before we start */
ohci_soft_reset(ohci);
@@ -2266,8 +2287,41 @@ static void remove_card(struct ti_ohci *ohci)
#endif /* CONFIG_ALL_PPC */
pci_set_drvdata(ohci->dev, NULL);
+ kfree(ohci);
}
+#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
+
+static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
+ {
+ class: PCI_CLASS_FIREWIRE_OHCI,
+ class_mask: 0x00ffffff,
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+ },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
+
+static struct pci_driver ohci1394_pci_driver = {
+ name: OHCI1394_DRIVER_NAME,
+ id_table: ohci1394_pci_tbl,
+ probe: ohci1394_pci_probe,
+ remove: __devexit_p(ohci1394_pci_remove),
+};
+
+
+
+/***********************************
+ * OHCI1394 Video Interface *
+ ***********************************/
+
+/* essentially the only purpose of this code is to allow another
+ module to hook into ohci's interrupt handler */
+
void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
{
int i=0;
@@ -2287,111 +2341,96 @@ void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg);
}
-int ohci1394_register_video(struct ti_ohci *ohci,
- struct video_template *tmpl)
+static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
+ quadlet_t isoRecvEvent,
+ quadlet_t isoXmitEvent)
{
- if (ohci->video_tmpl)
- return -ENFILE;
- ohci->video_tmpl = tmpl;
- MOD_INC_USE_COUNT;
- return 0;
+ int i;
+ for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+ if(ohci->irq_hooks[i].irq_handler != NULL) {
+ ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent,
+ ohci->irq_hooks[i].data);
+ }
+ }
}
-
-void ohci1394_unregister_video(struct ti_ohci *ohci,
- struct video_template *tmpl)
+
+int ohci1394_hook_irq(struct ti_ohci *ohci,
+ void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+ void *data)
{
- if (ohci->video_tmpl != tmpl) {
- PRINT(KERN_ERR, ohci->id,
- "Trying to unregister wrong video device");
- } else {
- ohci->video_tmpl = NULL;
- MOD_DEC_USE_COUNT;
+ int i;
+
+ /* find a free slot */
+ for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+ if(ohci->irq_hooks[i].irq_handler == NULL)
+ break;
}
+
+ if(i >= OHCI1394_MAX_IRQ_HOOKS)
+ return -EBUSY;
+
+ ohci->irq_hooks[i].irq_handler = irq_handler;
+ ohci->irq_hooks[i].data = data;
+
+ /* ohci1394 will never be unloaded while an IRQ hook is
+ in use, because the user must reference this symbol */
+
+ return 0;
}
-#if 0
-int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
+void ohci1394_unhook_irq(struct ti_ohci *ohci,
+ void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+ void *data)
{
- int csrSel;
- quadlet_t chan, data1=0, data2=0;
- int timeout = 32;
-
- if (channel<32) {
- chan = 1<<channel;
- csrSel = 2;
- }
- else {
- chan = 1<<(channel-32);
- csrSel = 3;
- }
- if (ohci_compare_swap(ohci, &data1, 0, csrSel)<0) {
- PRINT(KERN_INFO, ohci->id, "request_channel timeout");
- return -1;
+ int i;
+
+ for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+ if( (ohci->irq_hooks[i].irq_handler == irq_handler) &&
+ (ohci->irq_hooks[i].data == data) )
+ break;
}
- while (timeout--) {
- if (data1 & chan) {
- PRINT(KERN_INFO, ohci->id,
- "request channel %d failed", channel);
- return -1;
- }
- data2 = data1;
- data1 |= chan;
- if (ohci_compare_swap(ohci, &data1, data2, csrSel)<0) {
- PRINT(KERN_INFO, ohci->id, "request_channel timeout");
- return -1;
- }
- if (data1==data2) {
- PRINT(KERN_INFO, ohci->id,
- "request channel %d succeded", channel);
- return 0;
- }
+
+ if(i < OHCI1394_MAX_IRQ_HOOKS) {
+ ohci->irq_hooks[i].irq_handler = NULL;
+ ohci->irq_hooks[i].data = NULL;
}
- PRINT(KERN_INFO, ohci->id, "request channel %d failed", channel);
- return -1;
}
-#endif
EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_register_video);
-EXPORT_SYMBOL(ohci1394_unregister_video);
+EXPORT_SYMBOL(ohci1394_hook_irq);
+EXPORT_SYMBOL(ohci1394_unhook_irq);
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
-static void __devexit ohci1394_remove_one(struct pci_dev *pdev)
-{
- struct ti_ohci *ohci = pci_get_drvdata(pdev);
- if (ohci) {
- remove_card (ohci);
- pci_set_drvdata(pdev, NULL);
- }
-}
+/***********************************
+ * General module initialization *
+ ***********************************/
-static struct pci_driver ohci1394_driver = {
- name: OHCI1394_DRIVER_NAME,
- id_table: ohci1394_pci_tbl,
- probe: ohci1394_add_one,
- remove: ohci1394_remove_one,
-};
+MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
+MODULE_LICENSE("GPL");
static void __exit ohci1394_cleanup (void)
{
- hpsb_unregister_lowlevel(&ohci_template);
- pci_unregister_driver(&ohci1394_driver);
+ pci_unregister_driver(&ohci1394_pci_driver);
+ hpsb_unregister_lowlevel(ohci1394_driver);
}
static int __init ohci1394_init(void)
{
int ret;
- if (hpsb_register_lowlevel(&ohci_template)) {
- PRINT_G(KERN_ERR, "Registering failed");
- return -ENXIO;
+
+ ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops,
+ OHCI1394_DRIVER_NAME);
+ if (!ohci1394_driver) {
+ PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed");
+ return -ENOMEM;
}
- if ((ret = pci_module_init(&ohci1394_driver))) {
- PRINT_G(KERN_ERR, "PCI module init failed");
- hpsb_unregister_lowlevel(&ohci_template);
+
+ ret = pci_module_init(&ohci1394_pci_driver);
+ if (ret < 0) {
+ PRINT_G(KERN_ERR, "pci_module_init failed");
+ hpsb_unregister_lowlevel(ohci1394_driver);
return ret;
}
return ret;
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index 3ab491270..141f485e2 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -76,9 +76,13 @@ struct at_dma_prg {
quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
};
+/* identify whether a DMA context is asynchronous or isochronous */
+enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
+
/* DMA receive context */
struct dma_rcv_ctx {
- void *ohci;
+ struct ti_ohci *ohci;
+ enum context_type type;
int ctx;
unsigned int num_desc;
@@ -105,7 +109,8 @@ struct dma_rcv_ctx {
/* DMA transmit context */
struct dma_trm_ctx {
- void *ohci;
+ struct ti_ohci *ohci;
+ enum context_type type;
int ctx;
unsigned int num_desc;
@@ -133,18 +138,9 @@ struct dma_trm_ctx {
int cmdPtr;
};
-/* video device template */
-struct video_template {
- void (*irq_handler) (int card, quadlet_t isoRecvEvent,
- quadlet_t isoXmitEvent);
-};
-
-
struct ti_ohci {
int id; /* sequential card number */
- struct list_head list;
-
struct pci_dev *dev;
u32 state;
@@ -175,11 +171,13 @@ struct ti_ohci {
struct dma_rcv_ctx *ir_context;
spinlock_t IR_channel_lock;
int nb_iso_rcv_ctx;
-
+ unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
+
/* iso transmit */
struct dma_trm_ctx *it_context;
int nb_iso_xmit_ctx;
-
+ unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
+
u64 ISO_channel_usage;
/* IEEE-1394 part follows */
@@ -192,8 +190,15 @@ struct ti_ohci {
int self_id_errors;
- /* video device */
- struct video_template *video_tmpl;
+ /* IRQ hooks, for video1394 and dv1394 */
+
+#define OHCI1394_MAX_IRQ_HOOKS 4
+
+ struct ohci1394_irq_hook {
+ void (*irq_handler) (int card, quadlet_t isoRecvEvent,
+ quadlet_t isoXmitEvent, void *data);
+ void *data;
+ } irq_hooks[OHCI1394_MAX_IRQ_HOOKS];
/* Swap the selfid buffer? */
unsigned int selfid_swap:1;
@@ -230,6 +235,12 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
/* 2 KiloBytes of register space */
#define OHCI1394_REGISTER_SIZE 0x800
+/* Offsets relative to context bases defined below */
+
+#define OHCI1394_ContextControlSet 0x000
+#define OHCI1394_ContextControlClear 0x004
+#define OHCI1394_ContextCommandPtr 0x00C
+
/* register map */
#define OHCI1394_Version 0x000
#define OHCI1394_GUID_ROM 0x004
@@ -281,27 +292,37 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
#define OHCI1394_PhyReqFilterLoSet 0x118
#define OHCI1394_PhyReqFilterLoClear 0x11C
#define OHCI1394_PhyUpperBound 0x120
+
+#define OHCI1394_AsReqTrContextBase 0x180
#define OHCI1394_AsReqTrContextControlSet 0x180
#define OHCI1394_AsReqTrContextControlClear 0x184
#define OHCI1394_AsReqTrCommandPtr 0x18C
+
+#define OHCI1394_AsRspTrContextBase 0x1A0
#define OHCI1394_AsRspTrContextControlSet 0x1A0
#define OHCI1394_AsRspTrContextControlClear 0x1A4
#define OHCI1394_AsRspTrCommandPtr 0x1AC
+
+#define OHCI1394_AsReqRcvContextBase 0x1C0
#define OHCI1394_AsReqRcvContextControlSet 0x1C0
#define OHCI1394_AsReqRcvContextControlClear 0x1C4
#define OHCI1394_AsReqRcvCommandPtr 0x1CC
+
+#define OHCI1394_AsRspRcvContextBase 0x1E0
#define OHCI1394_AsRspRcvContextControlSet 0x1E0
#define OHCI1394_AsRspRcvContextControlClear 0x1E4
#define OHCI1394_AsRspRcvCommandPtr 0x1EC
/* Isochronous transmit registers */
/* Add (32 * n) for context n */
+#define OHCI1394_IsoXmitContextBase 0x200
#define OHCI1394_IsoXmitContextControlSet 0x200
#define OHCI1394_IsoXmitContextControlClear 0x204
#define OHCI1394_IsoXmitCommandPtr 0x20C
/* Isochronous receive registers */
/* Add (32 * n) for context n */
+#define OHCI1394_IsoRcvContextBase 0x400
#define OHCI1394_IsoRcvContextControlSet 0x400
#define OHCI1394_IsoRcvContextControlClear 0x404
#define OHCI1394_IsoRcvCommandPtr 0x40C
@@ -346,10 +367,13 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
struct ti_ohci *ohci1394_get_struct(int card_num);
-int ohci1394_register_video(struct ti_ohci *ohci,
- struct video_template *tmpl);
-void ohci1394_unregister_video(struct ti_ohci *ohci,
- struct video_template *tmpl);
+int ohci1394_hook_irq(struct ti_ohci *ohci,
+ void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+ void *data);
+
+void ohci1394_unhook_irq(struct ti_ohci *ohci,
+ void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+ void *data);
#endif
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 815176c8f..0e6cebd56 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -42,10 +42,6 @@
#include "pcilynx.h"
-#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START
-#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work.
-#endif
-
/* print general (card independent) information */
#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
/* print card specific information */
@@ -60,9 +56,8 @@
#endif
-static struct ti_lynx cards[MAX_PCILYNX_CARDS];
-static int num_of_cards = 0;
-static struct hpsb_host_template lynx_template;
+static struct hpsb_host_driver *lynx_driver;
+static unsigned int card_id;
/*
* PCL handling functions.
@@ -143,10 +138,6 @@ static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid)
#endif
-static int add_card(struct pci_dev *dev, const struct pci_device_id *devid);
-static void remove_card(struct pci_dev *dev);
-
-
/***********************************
* IEEE-1394 functionality section *
@@ -161,8 +152,9 @@ static int get_phy_reg(struct ti_lynx *lynx, int addr)
unsigned long flags;
if (addr > 15) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY register address %d out of range", addr);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY register address %d out of range",
+ __FUNCTION__, addr);
return -1;
}
@@ -173,8 +165,8 @@ static int get_phy_reg(struct ti_lynx *lynx, int addr)
retval = reg_read(lynx, LINK_PHY);
if (i > 10000) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": runaway loop, aborting");
+ PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
+ __FUNCTION__);
retval = -1;
break;
}
@@ -196,14 +188,14 @@ static int set_phy_reg(struct ti_lynx *lynx, int addr, int val)
unsigned long flags;
if (addr > 15) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY register address %d out of range", addr);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY register address %d out of range", __FUNCTION__, addr);
return -1;
}
if (val > 0xff) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY register value %d out of range", val);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY register value %d out of range", __FUNCTION__, val);
return -1;
}
@@ -222,8 +214,8 @@ static int sel_phy_reg_page(struct ti_lynx *lynx, int page)
int reg;
if (page > 7) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY page %d out of range", page);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY page %d out of range", __FUNCTION__, page);
return -1;
}
@@ -244,8 +236,8 @@ static int sel_phy_reg_port(struct ti_lynx *lynx, int port)
int reg;
if (port > 15) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY port %d out of range", port);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY port %d out of range", __FUNCTION__, port);
return -1;
}
@@ -377,7 +369,7 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host)
hpsb_selfid_complete(host, phyid, isroot);
- if (host->in_bus_reset) return;
+ if (host->in_bus_reset) return; /* in bus reset again */
if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER);
reg_set_bits(lynx, LINK_CONTROL,
@@ -440,160 +432,7 @@ static void send_next(struct ti_lynx *lynx, int what)
}
-#if 0
-static int lynx_detect(struct hpsb_host_template *tmpl)
-{
- struct hpsb_host *host;
- int i;
-
- init_driver();
-
- for (i = 0; i < num_of_cards; i++) {
- host = hpsb_get_host(tmpl, 0);
- if (host == NULL) {
- /* simply don't init more after out of mem */
- return i;
- }
- host->hostdata = &cards[i];
- cards[i].host = host;
- }
-
- return num_of_cards;
-}
-#endif
-
-static int lynx_initialize(struct hpsb_host *host)
-{
- struct ti_lynx *lynx = host->hostdata;
- struct ti_pcl pcl;
- int i;
- u32 *pcli;
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
-
- lynx->async.queue = NULL;
-
- pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
- put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
-#ifdef __BIG_ENDIAN
- pcl.buffer[0].control = PCL_CMD_RCV | 16;
- pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#else
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
- pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#endif
- pcl.buffer[0].pointer = lynx->rcv_page_dma;
- pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
- put_pcl(lynx, lynx->rcv_pcl, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->async.pcl);
- pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
- put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
- pcl.async_error_next = PCL_NEXT_INVALID;
- put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- int page = i / ISORCV_PER_PAGE;
- int sec = i % ISORCV_PER_PAGE;
-
- pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
- + sec * MAX_ISORCV_SIZE;
- pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
- put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
- }
-
- pcli = (u32 *)&pcl;
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
- }
- put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
- /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
- reg_write(lynx, FIFO_SIZES, 0x003030a0);
- /* 20 byte threshold before triggering PCI transfer */
- reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
- /* threshold on both send FIFOs before transmitting:
- FIFO size - cache line size - 1 */
- i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
- i = 0x30 - i - 1;
- reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-
- reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
- reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
- | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
- | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
- | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
- | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
- | LINK_INT_ATF_UNDERFLOW);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
- DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
- | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST
- | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
- run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
- run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
- reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
- | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
- | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
- | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX);
-
- if (!lynx->phyic.reg_1394a) {
- /* attempt to enable contender bit -FIXME- would this work
- * elsewhere? */
- reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
- reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
- } else {
- /* set the contender bit in the extended PHY register
- * set. (Should check that bis 0,1,2 (=0xE0) is set
- * in register 2?)
- */
- i = get_phy_reg(lynx, 4);
- if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
- }
-
- return 1;
-}
-
-static void lynx_release(struct hpsb_host *host)
-{
- struct ti_lynx *lynx;
-
- if (host != NULL) {
- lynx = host->hostdata;
- remove_card(lynx->dev);
- } else {
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
- unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
- }
-}
-
+/* called from subsystem core */
static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
{
struct ti_lynx *lynx = host->hostdata;
@@ -642,6 +481,8 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
return 1;
}
+
+/* called from subsystem core */
static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
{
struct ti_lynx *lynx = host->hostdata;
@@ -666,9 +507,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
arg |= (retval == -1 ? 63 : retval);
retval = 0;
- PRINT(KERN_INFO, lynx->id, "resetting bus on request%s",
- (host->attempt_root ? " and attempting to become root"
- : ""));
+ PRINT(KERN_INFO, lynx->id, "resetting bus on request");
lynx->selfid_size = -1;
lynx->phy_reg0 = -1;
@@ -721,6 +560,8 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
} else {
MOD_DEC_USE_COUNT;
}
+
+ retval = 1;
break;
case ISO_LISTEN_CHANNEL:
@@ -1010,8 +851,8 @@ static ssize_t mem_read(struct file *file, char *buffer, size_t count,
membase = md->lynx->aux_port;
break;
default:
- panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__,
- md->lynx->id, md->type);
+ panic("pcilynx%d: unsupported md->type %d in %s",
+ md->lynx->id, md->type, __FUNCTION__);
}
down(&md->lynx->mem_dma_mutex);
@@ -1291,6 +1132,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
}
}
+
static void iso_rcv_bh(struct ti_lynx *lynx)
{
unsigned int idx;
@@ -1335,44 +1177,97 @@ static void iso_rcv_bh(struct ti_lynx *lynx)
}
+static void remove_card(struct pci_dev *dev)
+{
+ struct ti_lynx *lynx;
+ int i;
+
+ lynx = pci_get_drvdata(dev);
+ if (!lynx) return;
+ pci_set_drvdata(dev, NULL);
+
+ switch (lynx->state) {
+ case is_host:
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ hpsb_remove_host(lynx->host);
+ case have_intr:
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ free_irq(lynx->dev->irq, lynx);
+ case have_iomappings:
+ reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ /* Fix buggy cards with autoboot pin not tied low: */
+ reg_write(lynx, DMA0_CHAN_CTRL, 0);
+ iounmap(lynx->registers);
+ iounmap(lynx->local_rom);
+ iounmap(lynx->local_ram);
+ iounmap(lynx->aux_port);
+ case have_1394_buffers:
+ for (i = 0; i < ISORCV_PAGES; i++) {
+ if (lynx->iso_rcv.page[i]) {
+ pci_free_consistent(lynx->dev, PAGE_SIZE,
+ lynx->iso_rcv.page[i],
+ lynx->iso_rcv.page_dma[i]);
+ }
+ }
+ pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
+ lynx->rcv_page_dma);
+ case have_aux_buf:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
+ lynx->mem_dma_buffer_dma);
+#endif
+ case have_pcl_mem:
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
+ lynx->pcl_mem_dma);
+#endif
+ case clear:
+ /* do nothing - already freed */
+ ;
+ }
+
+ tasklet_kill(&lynx->iso_rcv.tq);
+ kfree(lynx);
+}
+
+
static int __devinit add_card(struct pci_dev *dev,
- const struct pci_device_id *devid)
+ const struct pci_device_id *devid_is_unused)
{
#define FAIL(fmt, args...) do { \
PRINT_G(KERN_ERR, fmt , ## args); \
- num_of_cards--; \
remove_card(dev); \
- return -1; \
+ return error; \
} while (0)
+ struct hpsb_host *host;
struct ti_lynx *lynx; /* shortcut to currently handled device */
- unsigned int i;
+ struct ti_pcl pcl;
+ u32 *pcli;
+ int i;
+ int error;
- if (num_of_cards == MAX_PCILYNX_CARDS) {
- PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
- "Adjust MAX_PCILYNX_CARDS in pcilynx.h.",
- MAX_PCILYNX_CARDS);
- return -1;
- }
- lynx = &cards[num_of_cards++];
+ error = -ENXIO;
if (pci_set_dma_mask(dev, 0xffffffff))
- FAIL("DMA address limits not supported for PCILynx hardware %d",
- lynx->id);
+ FAIL("DMA address limits not supported for PCILynx hardware");
if (pci_enable_device(dev))
- FAIL("failed to enable PCILynx hardware %d", lynx->id);
+ FAIL("failed to enable PCILynx hardware");
pci_set_master(dev);
- lynx->host = hpsb_get_host(&lynx_template, 0);
- if (!lynx->host)
- FAIL("failed to allocate host structure");
+ error = -ENOMEM;
+
+ host = hpsb_alloc_host(lynx_driver, sizeof(struct ti_lynx));
+ if (!host) FAIL("failed to allocate control structure memory");
- lynx->state = have_host_struct;
- lynx->host->hostdata = lynx;
- lynx->id = num_of_cards-1;
+ lynx = host->hostdata;
+ lynx->id = card_id++;
lynx->dev = dev;
- lynx->host->pdev = dev;
+ lynx->state = clear;
+ lynx->host = host;
+ host->pdev = dev;
+ pci_set_drvdata(dev, lynx);
lynx->lock = SPIN_LOCK_UNLOCKED;
lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;
@@ -1435,7 +1330,9 @@ static int __devinit add_card(struct pci_dev *dev,
}
#endif
- reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ /* Fix buggy cards with autoboot pin not tied low: */
+ reg_write(lynx, DMA0_CHAN_CTRL, 0);
if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,
PCILYNX_DRIVER_NAME, lynx)) {
@@ -1502,99 +1399,121 @@ static int __devinit add_card(struct pci_dev *dev,
PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
}
- /* Tell the highlevel this host is ready */
- highlevel_add_one_host (lynx->host);
-
- return 0;
-#undef FAIL
-}
+ lynx->selfid_size = -1;
+ lynx->phy_reg0 = -1;
-static void remove_card(struct pci_dev *dev)
-{
- struct ti_lynx *lynx;
- int i;
+ lynx->async.queue = NULL;
- lynx = cards;
- while (lynx->dev != dev) lynx++;
+ pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
+ put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
- switch (lynx->state) {
- case have_intr:
- reg_write(lynx, PCI_INT_ENABLE, 0);
- free_irq(lynx->dev->irq, lynx);
- case have_iomappings:
- reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
- iounmap(lynx->registers);
- iounmap(lynx->local_rom);
- iounmap(lynx->local_ram);
- iounmap(lynx->aux_port);
- case have_1394_buffers:
- for (i = 0; i < ISORCV_PAGES; i++) {
- if (lynx->iso_rcv.page[i]) {
- pci_free_consistent(lynx->dev, PAGE_SIZE,
- lynx->iso_rcv.page[i],
- lynx->iso_rcv.page_dma[i]);
- }
- }
- pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
- lynx->rcv_page_dma);
- case have_aux_buf:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
- pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
- lynx->mem_dma_buffer_dma);
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+#ifdef __BIG_ENDIAN
+ pcl.buffer[0].control = PCL_CMD_RCV | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
+#else
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#endif
- case have_pcl_mem:
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
- pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
- lynx->pcl_mem_dma);
+ pcl.buffer[0].pointer = lynx->rcv_page_dma;
+ pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
+ put_pcl(lynx, lynx->rcv_pcl, &pcl);
+
+ pcl.next = pcl_bus(lynx, lynx->async.pcl);
+ pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
+ put_pcl(lynx, lynx->async.pcl_start, &pcl);
+
+ pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
+ pcl.async_error_next = PCL_NEXT_INVALID;
+ put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
+
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+ pcl.buffer[0].control = PCL_CMD_RCV | 4;
+#ifndef __BIG_ENDIAN
+ pcl.buffer[0].control |= PCL_BIGENDIAN;
#endif
- case have_host_struct:
- /* FIXME - verify host freeing */
- case clear:;
- /* do nothing - already freed */
+ pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
+
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ int page = i / ISORCV_PER_PAGE;
+ int sec = i % ISORCV_PER_PAGE;
+
+ pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
+ + sec * MAX_ISORCV_SIZE;
+ pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
+ put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
}
- tasklet_kill(&lynx->iso_rcv.tq);
+ pcli = (u32 *)&pcl;
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
+ }
+ put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
- lynx->state = clear;
-}
+ /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
+ reg_write(lynx, FIFO_SIZES, 0x003030a0);
+ /* 20 byte threshold before triggering PCI transfer */
+ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
+ /* threshold on both send FIFOs before transmitting:
+ FIFO size - cache line size - 1 */
+ i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
+ i = 0x30 - i - 1;
+ reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-#if 0
-static int init_driver()
-{
- struct pci_dev *dev = NULL;
- int success = 0;
+ reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
- if (num_of_cards) {
- PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
- return 0;
- }
+ reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
+ | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
+ | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
+ | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
+ | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
+ | LINK_INT_ATF_UNDERFLOW);
+
+ reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+ reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
+ reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
+ DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
+ | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST
+ | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
- PRINT_G(KERN_INFO, "looking for PCILynx cards");
+ run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
- while ((dev = pci_find_device(PCI_VENDOR_ID_TI,
- PCI_DEVICE_ID_TI_PCILYNX, dev))
- != NULL) {
- if (add_card(dev) == 0) {
- success = 1;
- }
- }
+ reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+ reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
+ reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
- if (success == 0) {
- PRINT_G(KERN_WARNING, "no operable PCILynx cards found");
- return -ENXIO;
- }
+ run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
- if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
- PRINT_G(KERN_ERR, "allocation of char major number %d failed",
- PCILYNX_MAJOR);
- return -EBUSY;
+ reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
+ | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
+ | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
+ | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX);
+
+ if (!lynx->phyic.reg_1394a) {
+ /* attempt to enable contender bit -FIXME- would this work
+ * elsewhere? */
+ reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
+ reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
+ } else {
+ /* set the contender bit in the extended PHY register
+ * set. (Should check that bis 0,1,2 (=0xE0) is set
+ * in register 2?)
+ */
+ i = get_phy_reg(lynx, 4);
+ if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
}
-#endif
+
+ hpsb_add_host(host);
+ lynx->state = is_host;
return 0;
+#undef FAIL
}
-#endif
+
static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
@@ -1603,15 +1522,6 @@ static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
return sizeof(lynx_csr_rom);
}
-static struct hpsb_host_template lynx_template = {
- name: PCILYNX_DRIVER_NAME,
- initialize_host: lynx_initialize,
- release_host: lynx_release,
- get_rom: get_lynx_rom,
- transmit_packet: lynx_transmit,
- devctl: lynx_devctl
-};
-
static struct pci_device_id pci_table[] __devinitdata = {
{
vendor: PCI_VENDOR_ID_TI,
@@ -1622,11 +1532,17 @@ static struct pci_device_id pci_table[] __devinitdata = {
{ } /* Terminating entry */
};
-static struct pci_driver lynx_pcidriver = {
+static struct pci_driver lynx_pci_driver = {
name: PCILYNX_DRIVER_NAME,
id_table: pci_table,
probe: add_card,
- remove: remove_card,
+ remove: __devexit_p(remove_card),
+};
+
+static struct hpsb_host_operations lynx_ops = {
+ get_rom: get_lynx_rom,
+ transmit_packet: lynx_transmit,
+ devctl: lynx_devctl,
};
MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
@@ -1635,30 +1551,52 @@ MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("pcilynx");
MODULE_DEVICE_TABLE(pci, pci_table);
-static void __exit pcilynx_cleanup(void)
-{
- hpsb_unregister_lowlevel(&lynx_template);
- pci_unregister_driver(&lynx_pcidriver);
- PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
-}
-
static int __init pcilynx_init(void)
{
int ret;
- if (hpsb_register_lowlevel(&lynx_template)) {
- PRINT_G(KERN_ERR, "registering failed");
- return -ENXIO;
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
+ PRINT_G(KERN_ERR, "allocation of char major number %d failed",
+ PCILYNX_MAJOR);
+ return -EBUSY;
+ }
+#endif
+
+ lynx_driver = hpsb_register_lowlevel(&lynx_ops, PCILYNX_DRIVER_NAME);
+ if (!lynx_driver) {
+ ret = -ENOMEM;
+ goto free_char_dev;
}
- ret = pci_module_init(&lynx_pcidriver);
+ ret = pci_module_init(&lynx_pci_driver);
if (ret < 0) {
PRINT_G(KERN_ERR, "PCI module init failed");
- hpsb_unregister_lowlevel(&lynx_template);
+ goto unregister_lowlevel;
}
+ return 0;
+
+ unregister_lowlevel:
+ hpsb_unregister_lowlevel(lynx_driver);
+ free_char_dev:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+
return ret;
}
+static void __exit pcilynx_cleanup(void)
+{
+ pci_unregister_driver(&lynx_pci_driver);
+ hpsb_unregister_lowlevel(lynx_driver);
+
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+}
+
+
module_init(pcilynx_init);
module_exit(pcilynx_cleanup);
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index 58a0703f3..879774645 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -40,8 +40,8 @@ struct ti_lynx {
u32 product;
} phyic;
- enum { clear, have_host_struct, have_intr, have_aux_buf, have_pcl_mem,
- have_1394_buffers, have_iomappings } state;
+ enum { clear, have_intr, have_aux_buf, have_pcl_mem,
+ have_1394_buffers, have_iomappings, is_host } state;
/* remapped memory spaces */
void *registers;
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 4be8872a4..9d975a60f 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -467,7 +467,7 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
hi = list_entry(lh, struct host_info, list);
khl->nodes = hi->host->node_count;
- strcpy(khl->name, hi->host->template->name);
+ strcpy(khl->name, hi->host->driver->name);
khl++;
}
@@ -495,7 +495,7 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
lh = lh->next;
}
hi = list_entry(lh, struct host_info, list);
- hpsb_inc_host_usage(hi->host);
+ hpsb_ref_host(hi->host);
list_add_tail(&fi->list, &hi->file_info_list);
fi->host = hi->host;
fi->state = connected;
@@ -915,7 +915,7 @@ static int raw1394_open(struct inode *inode, struct file *file)
{
struct file_info *fi;
- if (minor(inode->i_rdev)) {
+ if (ieee1394_file_to_instance(file) > 0) {
return -ENXIO;
}
@@ -983,7 +983,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
list_del(&fi->list);
spin_unlock_irq(&host_info_lock);
- hpsb_dec_host_usage(fi->host);
+ hpsb_unref_host(fi->host);
}
kfree(fi);
@@ -1017,14 +1017,18 @@ static int __init init_raw1394(void)
return -ENOMEM;
}
- devfs_handle = devfs_register(NULL, RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
- RAW1394_DEVICE_MAJOR, 0,
+ devfs_handle = devfs_register(NULL,
+ RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+ IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_RAW1394 * 16,
S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
NULL);
- if (devfs_register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME,
- &file_ops)) {
- HPSB_ERR("raw1394 failed to register /dev/raw1394 device");
+ if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
+ THIS_MODULE, &file_ops)) {
+ HPSB_ERR("raw1394 failed to register minor device block");
+ devfs_unregister(devfs_handle);
+ hpsb_unregister_highlevel(hl_handle);
return -EBUSY;
}
printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
@@ -1033,7 +1037,7 @@ static int __init init_raw1394(void)
static void __exit cleanup_raw1394(void)
{
- devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME);
+ ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
devfs_unregister(devfs_handle);
hpsb_unregister_highlevel(hl_handle);
}
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index fc362f7ea..907eba202 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -2,7 +2,7 @@
* sbp2.c - SBP-2 protocol driver for IEEE-1394
*
* Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com
+ * jamesg@filanet.com (JSG)
*
* 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
@@ -80,7 +80,7 @@
*
* The SBP-2 driver is still in an early state, but supports a variety of devices.
* I have read/written many gigabytes of data from/to SBP-2 drives, and have seen
- * performance of more than 16 MBytes/s on individual drives (limit of the media
+ * performance of more than 25 MBytes/s on individual drives (limit of the media
* transfer rate).
*
* Following are the devices that have been tested successfully:
@@ -91,7 +91,7 @@
* - LaCie IEEE-1394 hard drives (several flavors)
* - QPS IEEE-1394 CD-RW/DVD drives and hard drives
* - BusLink IEEE-1394 hard drives
- * - Iomega IEEE-1394 Zip/Jazz drives
+ * - Iomega IEEE-1394 Zip/Jazz/Peerless drives
* - ClubMac IEEE-1394 hard drives
* - FirePower IEEE-1394 hard drives
* - EzQuest IEEE-1394 hard drives and CD-RW drives
@@ -104,7 +104,6 @@
* - Sony IEEE-1394 CD-RW drives
* - Epson IEEE-1394 scanner
* - ADS IEEE-1394 memory stick and compact flash readers
- * (e.g. "insmod sbp2 mode_sense_hack=1" for mem stick and flash readers))
* - SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges)
* - Various other standard IEEE-1394 hard drives and enclosures
*
@@ -130,10 +129,6 @@
* add some init code to the kernel to support this... and modules are much
* more flexible anyway. ;-)
*
- * - The scsi stack in recent kernels pass down the data transfer
- * direction as scsicmd->sc_data_direction, which we should use
- * instead of the sbp2scsi_direction_table.
- *
*
* History:
*
@@ -239,9 +234,20 @@
* upon module unload. Moved much initialization
* from sbp2scsi_detect to sbp2_module_init.
* Kristian Hogsberg <hogsberg@users.sf.net>
+ * 01/06/02 - Misc bug fixes/enhancements: (JSG)
+ * * Enable use_new_eh_code for scsi stuff.
+ * * Do not write all ones for NULL ORB high/low fields, but
+ * rather leave reserved areas zeroed (per SBP2 spec).
+ * * Use newer scsi transfer direction passed down instead of our
+ * direction table.
+ * * Bumped login time-out to 20 seconds, as some devices are slow.
+ * * Fixed a couple scsi unregister bugs on module unload
+ * 01/13/02 - Fixed compatibility with certain SBP2 devices, such as Iomega
+ * 1394 devices (Peerless, Jazz). Also a bit of clean-up of the
+ * driver, thanks to H.J.Lu (hjl@lucon.org). Removed mode_sense_hack
+ * module load option, as it's been fixed in the 2.4 scsi stack.
*/
-
/*
* Includes
@@ -270,6 +276,16 @@
#include <asm/io.h>
#include <asm/scatterlist.h>
+#ifdef CONFIG_KBUILD_2_5
+#include <scsi.h>
+#include <hosts.h>
+#include <sd.h>
+#else
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+#endif
+
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
@@ -278,9 +294,6 @@
#include "highlevel.h"
#include "ieee1394_transactions.h"
#include "ieee1394_hotplug.h"
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
#include "sbp2.h"
/*
@@ -288,16 +301,6 @@
*/
/*
- * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device,
- * like a 1394 memory stick reader, compact flash reader, or MO drive that
- * does not support mode sense. Allows you to mount the media rw instead
- * of ro.
- */
-MODULE_PARM(mode_sense_hack,"i");
-MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers");
-static int mode_sense_hack = 0;
-
-/*
* Change max_speed on module load if you have a bad IEEE-1394 controller
* that has trouble running 2KB packets at 400mb.
*
@@ -352,7 +355,7 @@ MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
*/
#ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
-#define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2("__FUNCTION__"): "fmt, ## args)
+#define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
static u32 global_outstanding_command_orbs = 0;
#define outstanding_orb_incr global_outstanding_command_orbs++
#define outstanding_orb_decr global_outstanding_command_orbs--
@@ -364,10 +367,10 @@ static u32 global_outstanding_command_orbs = 0;
#ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
#define SBP2_DMA_ALLOC(fmt, args...) \
- HPSB_ERR("sbp2("__FUNCTION__")alloc(%d): "fmt, \
+ HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \
++global_outstanding_dmas, ## args)
#define SBP2_DMA_FREE(fmt, args...) \
- HPSB_ERR("sbp2("__FUNCTION__")free(%d): "fmt, \
+ HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \
--global_outstanding_dmas, ## args)
static u32 global_outstanding_dmas = 0;
#else
@@ -375,7 +378,6 @@ static u32 global_outstanding_dmas = 0;
#define SBP2_DMA_FREE(fmt, args...)
#endif
-
#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
#define SBP2_DEBUG(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_INFO(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
@@ -418,7 +420,6 @@ static Scsi_Host_Template scsi_driver_template;
static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
static LIST_HEAD(sbp2_host_info_list);
-static int sbp2_host_count = 0;
static struct hpsb_highlevel *sbp2_hl_handle = NULL;
@@ -804,14 +805,26 @@ static void sbp2util_free_command_dma(struct sbp2_command_info *command)
hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0];
if (hi == NULL) {
- printk(KERN_ERR __FUNCTION__": hi == NULL\n");
+ printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
return;
}
if (command->cmd_dma) {
- pci_unmap_single(hi->host->pdev, command->cmd_dma,
- command->dma_size, command->dma_dir);
- SBP2_DMA_FREE("single bulk");
+ if (command->dma_type == CMD_DMA_SINGLE) {
+ pci_unmap_single(hi->host->pdev, command->cmd_dma,
+ command->dma_size, command->dma_dir);
+ SBP2_DMA_FREE("single bulk");
+ } else if (command->dma_type == CMD_DMA_PAGE) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
+ pci_unmap_single(hi->host->pdev, command->cmd_dma,
+ command->dma_size, command->dma_dir);
+#else
+ pci_unmap_page(hi->host->pdev, command->cmd_dma,
+ command->dma_size, command->dma_dir);
+#endif /* Linux version < 2.4.13 */
+ SBP2_DMA_FREE("single page");
+ } /* XXX: Check for CMD_DMA_NONE bug */
+ command->dma_type = CMD_DMA_NONE;
command->cmd_dma = 0;
}
@@ -991,7 +1004,6 @@ static void sbp2_add_host(struct hpsb_host *host)
sbp2_spin_lock(&sbp2_host_info_lock, flags);
list_add_tail(&hi->list, &sbp2_host_info_list);
- sbp2_host_count++;
sbp2_spin_unlock(&sbp2_host_info_lock, flags);
/* Register our host with the SCSI stack. */
@@ -1014,12 +1026,29 @@ static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host)
list_for_each (lh, &sbp2_host_info_list) {
hi = list_entry(lh, struct sbp2scsi_host_info, list);
- if (hi->host == host) {
+ if (hi->host == host)
return hi;
- }
}
- return(NULL);
+ return NULL;
+}
+
+/*
+ * This function returns a host info structure for a given Scsi_Host
+ * struct.
+ */
+static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host)
+{
+ struct list_head *lh;
+ struct sbp2scsi_host_info *hi;
+
+ list_for_each (lh, &sbp2_host_info_list) {
+ hi = list_entry(lh, struct sbp2scsi_host_info, list);
+ if (hi->scsi_host == host)
+ return hi;
+ }
+
+ return NULL;
}
/*
@@ -1037,10 +1066,7 @@ static void sbp2_remove_host(struct hpsb_host *host)
hi = sbp2_find_host_info(host);
if (hi != NULL) {
sbp2util_remove_request_packet_pool(hi);
- sbp2_host_count--;
list_del(&hi->list);
- scsi_unregister(hi->scsi_host);
- scsi_driver_template.present--;
kfree(hi);
}
else
@@ -1367,9 +1393,9 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta
save_flags(flags);
cli();
- /* 10 second timeout */
+ /* 20 second timeout */
if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma)
- sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ);
+ sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ);
restore_flags(flags);
SBP2_DEBUG("sbp2_login_device: initial check");
@@ -1597,13 +1623,13 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
ud = scsi_id->ud;
/* Handle different fields in the unit directory, based on keys */
- for (i = 0; i < ud->arb_count; i++) {
- switch (ud->arb_keys[i]) {
+ for (i = 0; i < ud->count; i++) {
+ switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
case SBP2_CSR_OFFSET_KEY:
/* Save off the management agent address */
scsi_id->sbp2_management_agent_addr =
- CONFIG_ROM_INITIAL_MEMORY_SPACE +
- (ud->arb_values[i] << 2);
+ CSR_REGISTER_BASE +
+ (CONFIG_ROM_VALUE(ud->quadlets[i]) << 2);
SBP2_DEBUG("sbp2_management_agent_addr = %x",
(unsigned int) scsi_id->sbp2_management_agent_addr);
@@ -1611,14 +1637,16 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
case SBP2_COMMAND_SET_SPEC_ID_KEY:
/* Command spec organization */
- scsi_id->sbp2_command_set_spec_id = ud->arb_values[i];
+ scsi_id->sbp2_command_set_spec_id
+ = CONFIG_ROM_VALUE(ud->quadlets[i]);
SBP2_DEBUG("sbp2_command_set_spec_id = %x",
(unsigned int) scsi_id->sbp2_command_set_spec_id);
break;
case SBP2_COMMAND_SET_KEY:
/* Command set used by sbp2 device */
- scsi_id->sbp2_command_set = ud->arb_values[i];
+ scsi_id->sbp2_command_set
+ = CONFIG_ROM_VALUE(ud->quadlets[i]);
SBP2_DEBUG("sbp2_command_set = %x",
(unsigned int) scsi_id->sbp2_command_set);
break;
@@ -1628,7 +1656,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
* Unit characterisitcs (orb related stuff
* that I'm not yet paying attention to)
*/
- scsi_id->sbp2_unit_characteristics = ud->arb_values[i];
+ scsi_id->sbp2_unit_characteristics
+ = CONFIG_ROM_VALUE(ud->quadlets[i]);
SBP2_DEBUG("sbp2_unit_characteristics = %x",
(unsigned int) scsi_id->sbp2_unit_characteristics);
break;
@@ -1638,7 +1667,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
* Device type and lun (used for
* detemining type of sbp2 device)
*/
- scsi_id->sbp2_device_type_and_lun = ud->arb_values[i];
+ scsi_id->sbp2_device_type_and_lun
+ = CONFIG_ROM_VALUE(ud->quadlets[i]);
SBP2_DEBUG("sbp2_device_type_and_lun = %x",
(unsigned int) scsi_id->sbp2_device_type_and_lun);
break;
@@ -1651,7 +1681,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
* bridge with 128KB max transfer size
* limitation.
*/
- scsi_id->sbp2_firmware_revision = ud->arb_values[i];
+ scsi_id->sbp2_firmware_revision
+ = CONFIG_ROM_VALUE(ud->quadlets[i]);
if (scsi_id->sbp2_firmware_revision ==
SBP2_128KB_BROKEN_FIRMWARE) {
SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size");
@@ -1693,7 +1724,7 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id
scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],
(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
- SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
+ SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]",
NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code],
1 << ((u32)scsi_id->max_payload_size + 2));
@@ -1753,13 +1784,15 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
unchar *scsi_cmd,
unsigned int scsi_use_sg,
unsigned int scsi_request_bufflen,
- void *scsi_request_buffer, int dma_dir)
+ void *scsi_request_buffer,
+ unsigned char scsi_dir)
{
struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
struct sbp2_command_orb *command_orb = &command->command_orb;
struct sbp2_unrestricted_page_table *scatter_gather_element =
&command->scatter_gather_element[0];
- u32 sg_count, sg_len;
+ int dma_dir = scsi_to_pci_dma_dir (scsi_dir);
+ u32 sg_count, sg_len, orb_direction;
dma_addr_t sg_addr;
int i;
@@ -1771,25 +1804,49 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
* that data_size becomes the number of s/g elements, and
* page_size should be zero (for unrestricted).
*/
- command_orb->next_ORB_hi = 0xffffffff;
- command_orb->next_ORB_lo = 0xffffffff;
+ command_orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
+ command_orb->next_ORB_lo = 0x0;
command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size);
command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code);
command_orb->misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */
/*
+ * Get the direction of the transfer. If the direction is unknown, then use our
+ * goofy table as a back-up.
+ */
+ switch (scsi_dir) {
+ case SCSI_DATA_NONE:
+ orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
+ break;
+ case SCSI_DATA_WRITE:
+ orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
+ break;
+ case SCSI_DATA_READ:
+ orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
+ break;
+ case SCSI_DATA_UNKNOWN:
+ default:
+ SBP2_ERR("SCSI data transfer direction not specified. "
+ "Update the SBP2 direction table in sbp2.h if "
+ "necessary for your application");
+ print_command (scsi_cmd);
+ orb_direction = sbp2scsi_direction_table[*scsi_cmd];
+ break;
+ }
+
+ /*
* Set-up our pagetable stuff... unfortunately, this has become
* messier than I'd like. Need to clean this up a bit. ;-)
*/
- if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) {
+ if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
SBP2_DEBUG("No data transfer");
/*
* Handle no data transfer
*/
- command_orb->data_descriptor_hi = 0xffffffff;
- command_orb->data_descriptor_lo = 0xffffffff;
+ command_orb->data_descriptor_hi = 0x0;
+ command_orb->data_descriptor_lo = 0x0;
command_orb->misc |= ORB_SET_DIRECTION(1);
} else if (scsi_use_sg) {
@@ -1804,17 +1861,24 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
SBP2_DEBUG("Only one s/g element");
command->dma_dir = dma_dir;
command->dma_size = sgpnt[0].length;
+ command->dma_type = CMD_DMA_PAGE;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
+ command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
+ command->dma_size,
+ command->dma_dir);
+#else
command->cmd_dma = pci_map_page(hi->host->pdev,
sgpnt[0].page,
sgpnt[0].offset,
command->dma_size,
command->dma_dir);
- SBP2_DMA_ALLOC("single scatter element");
+#endif /* Linux version < 2.4.13 */
+ SBP2_DMA_ALLOC("single page scatter element");
command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
command_orb->data_descriptor_lo = command->cmd_dma;
command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size);
- command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+ command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
} else {
int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir);
@@ -1826,7 +1890,7 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
/* use page tables (s/g) */
command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
- command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+ command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
command_orb->data_descriptor_lo = command->sge_dma;
@@ -1871,6 +1935,7 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
command->dma_dir = dma_dir;
command->dma_size = scsi_request_bufflen;
+ command->dma_type = CMD_DMA_SINGLE;
command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer,
command->dma_size,
command->dma_dir);
@@ -1885,15 +1950,15 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
command_orb->data_descriptor_lo = command->cmd_dma;
command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
- command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+ command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
/*
* Sanity, in case our direction table is not
* up-to-date
*/
if (!scsi_request_bufflen) {
- command_orb->data_descriptor_hi = 0xffffffff;
- command_orb->data_descriptor_lo = 0xffffffff;
+ command_orb->data_descriptor_hi = 0x0;
+ command_orb->data_descriptor_lo = 0x0;
command_orb->misc |= ORB_SET_DIRECTION(1);
}
@@ -1907,7 +1972,7 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
/* Use page tables (s/g) */
command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
- command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+ command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
/*
* fill out our sbp-2 page tables (and split up
@@ -1972,6 +2037,12 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i
SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x",
command_orb, command->linked, global_outstanding_command_orbs);
+ pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+ PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
/*
* Check to see if there are any previous orbs to use
*/
@@ -2008,6 +2079,7 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i
}
scsi_id->last_orb = command_orb;
+ scsi_id->last_orb_dma = command->command_orb_dma;
} else {
@@ -2022,6 +2094,9 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i
cpu_to_be32(command->command_orb_dma);
/* Tells hardware that this pointer is valid */
scsi_id->last_orb->next_ORB_hi = 0x0;
+ pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma,
+ sizeof(struct sbp2_command_orb),
+ PCI_DMA_BIDIRECTIONAL);
/*
* Only ring the doorbell if we need to (first parts of
@@ -2049,6 +2124,7 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i
}
scsi_id->last_orb = command_orb;
+ scsi_id->last_orb_dma = command->command_orb_dma;
}
return(0);
@@ -2061,12 +2137,17 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
unchar *cmd = (unchar *) SCpnt->cmnd;
- u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
+ unsigned int request_bufflen = SCpnt->request_bufflen;
+ u8 device_type
+ = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
struct sbp2_command_info *command;
SBP2_DEBUG("sbp2_send_command");
- SBP2_DEBUG("SCSI command = %02x", *cmd);
- SBP2_DEBUG("SCSI transfer size = %x", SCpnt->request_bufflen);
+ SBP2_DEBUG("SCSI command:");
+#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
+ print_command (cmd);
+#endif
+ SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
/*
@@ -2077,7 +2158,7 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
(SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) &&
(device_type == TYPE_DISK) &&
(SCpnt->use_sg) &&
- (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) {
+ (*cmd == READ_6 || *cmd == READ_10 || *cmd == WRITE_6 || *cmd == WRITE_10)) {
/*
* Darn, a broken device. We'll need to split up the
@@ -2096,14 +2177,24 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
}
/*
+ * The scsi stack sends down a request_bufflen which does not match the
+ * length field in the scsi cdb. This causes some sbp2 devices to
+ * reject this inquiry command. Fix is to fix request_bufflen to match
+ * the value in the cdb.
+ */
+ if (*cmd == INQUIRY) {
+ request_bufflen = cmd[4];
+ }
+
+ /*
* Now actually fill in the comamnd orb and sbp2 s/g list
*/
sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg,
- SCpnt->request_bufflen, SCpnt->request_buffer,
- scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+ request_bufflen, SCpnt->request_buffer,
+ SCpnt->sc_data_direction);
/*
* Update our cdb if necessary (to handle sbp2 RBC command set
- * differences). This is where the command set hacks go! =)
+ * differences). This is where the command set hacks go! =)
*/
if ((device_type == TYPE_DISK) ||
(device_type == TYPE_SDAD) ||
@@ -2193,7 +2284,7 @@ static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id
sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg,
total_transfer, &sgpnt[current_sg],
- scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+ SCpnt->sc_data_direction);
/*
* Link up the orb, and ring the doorbell if needed
@@ -2227,7 +2318,7 @@ static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id
sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg,
total_transfer, &sgpnt[current_sg],
- scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+ SCpnt->sc_data_direction);
/*
* Link up the orb, and ring the doorbell if needed
@@ -2369,15 +2460,20 @@ static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi,
Scsi_Cmnd *SCpnt)
{
u8 *scsi_buf = SCpnt->request_buffer;
- u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
-
+ u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
+
SBP2_DEBUG("sbp2_check_sbp2_response");
switch (SCpnt->cmnd[0]) {
case INQUIRY:
- SBP2_DEBUG("Check Inquiry data");
+ /*
+ * Make sure data length is ok. Minimum length is 36 bytes
+ */
+ if (scsi_buf[4] == 0) {
+ scsi_buf[4] = 36 - 5;
+ }
/*
* Check for Simple Direct Access Device and change it to TYPE_DISK
@@ -2493,6 +2589,12 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
if (command) {
SBP2_DEBUG("Found status for command ORB");
+ pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+ PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
outstanding_orb_decr;
@@ -2506,22 +2608,27 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
if (SCpnt && !command->linked) {
/*
- * Handle check conditions
+ * See if the target stored any scsi status information
*/
- if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
-
- SBP2_DEBUG("CHECK CONDITION");
-
+ if (length > 8) {
/*
* Translate SBP-2 status to SCSI sense data
*/
scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
+ }
+ /*
+ * Handle check conditions. If there is either SBP status or SCSI status
+ * then we'll do a fetch agent reset and note that a check condition
+ * occured.
+ */
+ if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc) ||
+ scsi_status) {
/*
* Initiate a fetch agent reset.
*/
+ SBP2_DEBUG("CHECK CONDITION");
sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
-
}
SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
@@ -2655,6 +2762,12 @@ static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi,
SBP2_DEBUG("Found pending command to complete");
lh = scsi_id->sbp2_command_orb_inuse.next;
command = list_entry(lh, struct sbp2_command_info, list);
+ pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+ PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
sbp2util_mark_command_completed(scsi_id, command);
if (command->Current_SCpnt && !command->linked) {
void (*done)(Scsi_Cmnd *) = command->Current_done;
@@ -2712,13 +2825,17 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi
/*
* Debug stuff
*/
+#if CONFIG_IEEE1394_SBP2_DEBUG >= 1
+ print_command (SCpnt->cmnd);
print_sense("bh", SCpnt);
+#endif
break;
case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
SCpnt->result = DID_NO_CONNECT << 16;
+ print_command (SCpnt->cmnd);
break;
case SBP2_SCSI_STATUS_CONDITION_MET:
@@ -2726,6 +2843,7 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi
case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
SBP2_ERR("Bad SCSI status = %x", scsi_status);
SCpnt->result = DID_ERROR << 16;
+ print_command (SCpnt->cmnd);
break;
default:
@@ -2741,19 +2859,6 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi
}
/*
- * One more quick hack (not enabled by default). Some sbp2 devices
- * do not support mode sense. Turn-on this hack to allow the
- * device to pass the sd driver's write-protect test (so that you
- * can mount the device rw).
- */
- if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) {
- SBP2_INFO("Returning success to mode sense command");
- SCpnt->result = DID_OK;
- SCpnt->sense_buffer[0] = 0;
- memset (SCpnt->request_buffer, 0, 8);
- }
-
- /*
* If a bus reset is in progress and there was an error, complete
* the command as busy so that it will get retried.
*/
@@ -2792,7 +2897,8 @@ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
unsigned long flags;
SBP2_ERR("aborting sbp2 command");
-
+ print_command (SCpnt->cmnd);
+
if (scsi_id) {
/*
@@ -2805,6 +2911,14 @@ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
if (command) {
SBP2_DEBUG("Found command to abort");
+ pci_dma_sync_single(hi->host->pdev,
+ command->command_orb_dma,
+ sizeof(struct sbp2_command_orb),
+ PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single(hi->host->pdev,
+ command->sge_dma,
+ sizeof(command->scatter_gather_element),
+ PCI_DMA_BIDIRECTIONAL);
sbp2util_mark_command_completed(scsi_id, command);
if (command->Current_SCpnt && !command->linked) {
void (*done)(Scsi_Cmnd *) = command->Current_done;
@@ -2822,13 +2936,13 @@ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
}
- return(SCSI_ABORT_SUCCESS);
+ return(SUCCESS);
}
/*
* Called by scsi stack when something has really gone wrong.
*/
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
{
struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
@@ -2839,7 +2953,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
hpsb_reset_bus(hi->host, LONG_RESET);
}
- return(SCSI_RESET_SUCCESS);
+ return(SUCCESS);
}
/*
@@ -2868,6 +2982,9 @@ static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[])
return(0);
}
+/*
+ * Called by scsi stack after scsi driver is registered
+ */
static int sbp2scsi_detect (Scsi_Host_Template *tpnt)
{
SBP2_DEBUG("sbp2scsi_detect");
@@ -2881,33 +2998,68 @@ static int sbp2scsi_detect (Scsi_Host_Template *tpnt)
sbp2_init();
/* We return the number of hosts registered. */
- return sbp2_host_count;
+ return scsi_driver_template.present;
+}
+
+
+/*
+ * Called for contents of procfs
+ */
+static const char *sbp2scsi_info (struct Scsi_Host *host)
+{
+ struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host);
+ static char info[1024];
+
+ if (!hi) /* shouldn't happen, but... */
+ return "IEEE-1394 SBP-2 protocol driver";
+
+ sprintf(info, "IEEE-1394 SBP-2 protocol driver\nHost Driver: %s\nSerial I/O: %s",
+ hi->host->driver->name, serialize_io ? "yes" : "no");
+
+ return info;
}
+
MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,26)
+#define PROC_SCSI_SBP2 PROC_SCSI_NOT_PRESENT /* What should I use? */
+static struct proc_dir_entry proc_scsi_sbp2scsi = {
+ low_ino: PROC_SCSI_SBP2,
+ namelen: SBP2_DEVICE_NAME_SIZE,
+ name: SBP2_DEVICE_NAME,
+ mode: S_IFDIR | S_IRUGO | S_IXUGO,
+ nlink: 2
+};
+#endif
+
/* SCSI host template */
static Scsi_Host_Template scsi_driver_template = {
- name: "IEEE-1394 SBP-2 protocol driver",
- detect: sbp2scsi_detect,
- queuecommand: sbp2scsi_queuecommand,
- abort: sbp2scsi_abort,
- reset: sbp2scsi_reset,
- bios_param: sbp2scsi_biosparam,
- can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS,
- this_id: -1,
- sg_tablesize: SBP2_MAX_SG_ELEMENTS,
- cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN,
- use_clustering: SBP2_CLUSTERING,
- emulated: 1,
-
- module: THIS_MODULE,
-
+ name: "IEEE-1394 SBP-2 protocol driver",
+ info: sbp2scsi_info,
+ detect: sbp2scsi_detect,
+ queuecommand: sbp2scsi_queuecommand,
+ eh_abort_handler: sbp2scsi_abort,
+ eh_device_reset_handler:sbp2scsi_reset,
+ eh_bus_reset_handler: sbp2scsi_reset,
+ eh_host_reset_handler: sbp2scsi_reset,
+ bios_param: sbp2scsi_biosparam,
+ can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS,
+ this_id: -1,
+ sg_tablesize: SBP2_MAX_SG_ELEMENTS,
+ cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN,
+ use_clustering: SBP2_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ use_new_eh_code: TRUE,
+#endif
+ emulated: 1,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
- proc_name: SBP2_DEVICE_NAME
+ proc_name: SBP2_DEVICE_NAME,
+#else
+ proc_dir: &proc_scsi_sbp2scsi,
#endif
};
@@ -2935,10 +3087,6 @@ static int sbp2_module_init(void)
scsi_driver_template.use_clustering = DISABLE_CLUSTERING;
}
- if (mode_sense_hack) {
- SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)");
- }
-
/*
* Ideally we would register our scsi_driver_template with the
* scsi stack and after that register with the ieee1394 stack
@@ -2947,7 +3095,8 @@ static int sbp2_module_init(void)
* least one host, so we "nest" the registrations by calling
* sbp2_init from the detect function.
*/
- if (scsi_register_host(&scsi_driver_template) ||
+ scsi_driver_template.module = THIS_MODULE;
+ if (SCSI_REGISTER_HOST(&scsi_driver_template) ||
!scsi_driver_template.present) {
SBP2_ERR("Please load the lower level IEEE-1394 driver "
"(e.g. ohci1394) before sbp2...");
@@ -2970,8 +3119,9 @@ static void __exit sbp2_module_exit(void)
*/
sbp2_cleanup();
- if (scsi_unregister_host(&scsi_driver_template))
+ if (SCSI_UNREGISTER_HOST(&scsi_driver_template))
SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
+
}
module_init(sbp2_module_init);
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index 2a4996ec0..559fa3951 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -22,6 +22,15 @@
#ifndef SBP2_H
#define SBP2_H
+/* Some compatibility code */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define SCSI_REGISTER_HOST(tmpl) scsi_register_module(MODULE_SCSI_HA, tmpl)
+#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_module(MODULE_SCSI_HA, tmpl)
+#else
+#define SCSI_REGISTER_HOST(tmpl) scsi_register_host(tmpl)
+#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_host(tmpl)
+#endif
+
#define SBP2_DEVICE_NAME "sbp2"
#define SBP2_DEVICE_NAME_SIZE 4
@@ -36,6 +45,7 @@
#define ORB_DIRECTION_READ_FROM_MEDIA 0x1
#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
+#define ORB_SET_NULL_PTR(value) ((value & 0x1) << 31)
#define ORB_SET_NOTIFY(value) ((value & 0x1) << 31)
#define ORB_SET_RQ_FMT(value) ((value & 0x3) << 29)
#define ORB_SET_NODE_ID(value) ((value & 0xffff) << 16)
@@ -199,6 +209,9 @@ struct sbp2_status_block {
#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14
#define SBP2_FIRMWARE_REVISION_KEY 0x3c
+#define SBP2_DEVICE_TYPE(q) (((q) >> 16) & 0x1f)
+#define SBP2_DEVICE_LUN(q) ((q) & 0xffff)
+
#define SBP2_AGENT_STATE_OFFSET 0x00ULL
#define SBP2_AGENT_RESET_OFFSET 0x04ULL
#define SBP2_ORB_POINTER_OFFSET 0x08ULL
@@ -218,15 +231,6 @@ struct sbp2_status_block {
#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
#define SBP2_SW_VERSION_ENTRY 0x00010483
-/*
- * Miscellaneous general config rom related defines
- */
-
-#define CONFIG_ROM_INITIAL_MEMORY_SPACE 0xfffff0000000ULL
-
-#define CONFIG_ROM_BASE_ADDRESS 0xfffff0000400ULL
-#define CONFIG_ROM_ROOT_DIR_BASE 0xfffff0000414ULL
-#define CONFIG_ROM_UNIT_DIRECTORY_OFFSET 0xfffff0000424ULL
#define SBP2_128KB_BROKEN_FIRMWARE 0xa0b800
#define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER 0x20000
@@ -252,7 +256,8 @@ struct sbp2_status_block {
#endif
/*
- * SCSI direction table... since the scsi stack doesn't specify direction... =(
+ * SCSI direction table...
+ * (now used as a back-up in case the direction passed down from above is "unknown")
*
* DIN = IN data direction
* DOU = OUT data direction
@@ -306,21 +311,27 @@ struct sbp2_request_packet {
};
+
+/* This is the two dma types we use for cmd_dma below */
+#define CMD_DMA_NONE 0x0
+#define CMD_DMA_PAGE 0x1
+#define CMD_DMA_SINGLE 0x2
+
/*
* Encapsulates all the info necessary for an outstanding command.
*/
struct sbp2_command_info {
struct list_head list;
- struct sbp2_command_orb command_orb;
- dma_addr_t command_orb_dma;
+ struct sbp2_command_orb command_orb ____cacheline_aligned;
+ dma_addr_t command_orb_dma ____cacheline_aligned;
Scsi_Cmnd *Current_SCpnt;
void (*Current_done)(Scsi_Cmnd *);
unsigned int linked;
/* Also need s/g structure for each sbp2 command */
- struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS];
- dma_addr_t sge_dma;
+ struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS] ____cacheline_aligned;
+ dma_addr_t sge_dma ____cacheline_aligned;
void *sge_buffer;
dma_addr_t cmd_dma;
int dma_type;
@@ -340,6 +351,7 @@ struct scsi_id_instance_data {
* Various sbp2 specific structures
*/
struct sbp2_command_orb *last_orb;
+ dma_addr_t last_orb_dma;
struct sbp2_login_orb *login_orb;
dma_addr_t login_orb_dma;
struct sbp2_login_response *login_response;
@@ -487,7 +499,8 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
unchar *scsi_cmd,
unsigned int scsi_use_sg,
unsigned int scsi_request_bufflen,
- void *scsi_request_buffer, int dma_dir);
+ void *scsi_request_buffer,
+ unsigned char scsi_dir);
static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
struct sbp2_command_info *command);
static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
@@ -506,10 +519,11 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id
* Scsi interface related prototypes
*/
static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
+static const char *sbp2scsi_info (struct Scsi_Host *host);
void sbp2scsi_setup(char *str, int *ints);
static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt);
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags);
+static int sbp2scsi_reset (Scsi_Cmnd *SCpnt);
static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
u32 status);
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index ff14786f5..b435f99dd 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -43,6 +43,7 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
+#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
#include <linux/vmalloc.h>
@@ -58,7 +59,6 @@
#include "ohci1394.h"
-#define VIDEO1394_MAJOR 172
#define ISO_CHANNELS 64
#define ISO_RECEIVE 0
#define ISO_TRANSMIT 1
@@ -80,6 +80,7 @@ struct it_dma_prg {
struct dma_iso_ctx {
struct ti_ohci *ohci;
+ int type; /* ISO_TRANSMIT or ISO_RECEIVE */
int ctx;
int channel;
int last_buffer;
@@ -144,7 +145,7 @@ printk(level "video1394: " fmt "\n" , ## args)
printk(level "video1394_%d: " fmt "\n" , card , ## args)
static void irq_handler(int card, quadlet_t isoRecvIntEvent,
- quadlet_t isoXmitIntEvent);
+ quadlet_t isoXmitIntEvent, void *data);
static LIST_HEAD(video1394_cards);
static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
@@ -152,8 +153,6 @@ static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
static devfs_handle_t devfs_handle;
static struct hpsb_highlevel *hl_handle = NULL;
-static struct video_template video_tmpl = { irq_handler };
-
/* Code taken from bttv.c */
/*******************************/
@@ -280,6 +279,7 @@ static int free_dma_iso_ctx(struct dma_iso_ctx **d)
{
int i;
struct ti_ohci *ohci;
+ unsigned long *usage;
if ((*d)==NULL) return -1;
@@ -313,6 +313,12 @@ static int free_dma_iso_ctx(struct dma_iso_ctx **d)
if ((*d)->next_buffer)
kfree((*d)->next_buffer);
+ usage = ((*d)->type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
+ &ohci->it_ctx_usage;
+
+ /* clear the ISO context usage bit */
+ clear_bit((*d)->ctx, usage);
+
kfree(*d);
*d = NULL;
@@ -320,12 +326,28 @@ static int free_dma_iso_ctx(struct dma_iso_ctx **d)
}
static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc,
+alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
int buf_size, int channel, unsigned int packet_size)
{
struct dma_iso_ctx *d=NULL;
int i;
+ unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
+ &ohci->it_ctx_usage;
+
+ /* try to claim the ISO context usage bit */
+ for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) {
+ if (!test_and_set_bit(i, usage)) {
+ PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i);
+ break;
+ }
+ }
+
+ if (i == ohci->nb_iso_rcv_ctx) {
+ PRINT(KERN_ERR, ohci->id, "No DMA contexts available");
+ return NULL;
+ }
+
d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx),
GFP_KERNEL);
if (d==NULL) {
@@ -336,7 +358,8 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc,
memset(d, 0, sizeof(struct dma_iso_ctx));
d->ohci = (void *)ohci;
- d->ctx = ctx;
+ d->type = type;
+ d->ctx = i;
d->channel = channel;
d->num_desc = num_desc;
d->frame_size = buf_size;
@@ -567,38 +590,38 @@ static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
}
/* find which context is listening to this channel */
-int ir_ctx_listening(struct video_card *video, int channel)
+static struct dma_iso_ctx **
+ir_ctx_listening(struct video_card *video, int channel)
{
int i;
struct ti_ohci *ohci = video->ohci;
- for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++)
- if (video->ir_context[i]) {
- if (video->ir_context[i]->channel==channel)
- return i;
- }
+ for (i = 0; i < ohci->nb_iso_rcv_ctx-1; i++)
+ if (video->ir_context[i] &&
+ video->ir_context[i]->channel == channel)
+ return &video->ir_context[i];
PRINT(KERN_ERR, ohci->id, "No iso context is listening to channel %d",
channel);
- return -1;
+ return NULL;
}
-int it_ctx_talking(struct video_card *video, int channel)
+static struct dma_iso_ctx **
+it_ctx_talking(struct video_card *video, int channel)
{
int i;
struct ti_ohci *ohci = video->ohci;
- for (i=0;i<ohci->nb_iso_xmit_ctx;i++)
- if (video->it_context[i]) {
- if (video->it_context[i]->channel==channel)
- return i;
- }
+ for (i = 0; i < ohci->nb_iso_xmit_ctx; i++)
+ if (video->it_context[i] &&
+ video->it_context[i]->channel==channel)
+ return &video->ir_context[i];
PRINT(KERN_ERR, ohci->id, "No iso context is talking to channel %d",
channel);
- return -1;
+ return NULL;
}
int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d)
@@ -821,7 +844,7 @@ static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
}
-static int do_iso_mmap(struct vm_area_struct *vma, struct ti_ohci *ohci, struct dma_iso_ctx *d,
+static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
const char *adr, unsigned long size)
{
unsigned long start=(unsigned long) adr;
@@ -842,7 +865,7 @@ static int do_iso_mmap(struct vm_area_struct *vma, struct ti_ohci *ohci, struct
pos=(unsigned long) d->buf;
while (size > 0) {
page = kvirt_to_pa(pos);
- if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
start+=PAGE_SIZE;
pos+=PAGE_SIZE;
@@ -864,7 +887,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
struct video_card *p;
list_for_each(lh, &video1394_cards) {
p = list_entry(lh, struct video_card, list);
- if (p->id == MINOR(inode->i_rdev)) {
+ if (p->id == ieee1394_file_to_instance(file)) {
video = p;
ohci = video->ohci;
break;
@@ -874,7 +897,8 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
spin_unlock_irqrestore(&video1394_cards_lock, flags);
if (video == NULL) {
- PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", MINOR(inode->i_rdev));
+ PRINT_G(KERN_ERR, "%s: Unknown video card for minor %d",
+ __FUNCTION__, ieee1394_file_to_instance(file));
return -EFAULT;
}
@@ -896,7 +920,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
for (i=0; i<ISO_CHANNELS; i++) {
if (!(ohci->ISO_channel_usage & mask)) {
v.channel = i;
- PRINT(KERN_INFO, ohci->id, "Found free channel %d\n", i);
+ PRINT(KERN_INFO, ohci->id, "Found free channel %d", i);
break;
}
mask = mask << 1;
@@ -951,7 +975,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
}
video->ir_context[i] =
- alloc_dma_iso_ctx(ohci, ISO_RECEIVE, i+1,
+ alloc_dma_iso_ctx(ohci, ISO_RECEIVE,
v.nb_buffers, v.buf_size,
v.channel, 0);
@@ -968,8 +992,8 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
v.buf_size = video->ir_context[i]->buf_size;
PRINT(KERN_INFO, ohci->id,
- "iso context %d listen on channel %d", i+1,
- v.channel);
+ "iso context %d listen on channel %d",
+ video->current_ctx->ctx, v.channel);
}
else {
/* find a free iso transmit context */
@@ -983,7 +1007,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
}
video->it_context[i] =
- alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, i,
+ alloc_dma_iso_ctx(ohci, ISO_TRANSMIT,
v.nb_buffers, v.buf_size,
v.channel, v.packet_size);
@@ -1014,7 +1038,6 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
{
int channel;
u64 mask;
- int i;
if(copy_from_user(&channel, (void *)arg, sizeof(int)))
return -EFAULT;
@@ -1033,24 +1056,23 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
ohci->ISO_channel_usage &= ~mask;
if (cmd == VIDEO1394_UNLISTEN_CHANNEL) {
- i = ir_ctx_listening(video, channel);
- if (i<0) return -EFAULT;
-
- free_dma_iso_ctx(&video->ir_context[i]);
-
+ struct dma_iso_ctx **d;
+ d = ir_ctx_listening(video, channel);
+ if (d == NULL) return -EFAULT;
PRINT(KERN_INFO, ohci->id,
"Iso context %d stop listening on channel %d",
- i+1, channel);
+ (*d)->ctx, channel);
+ free_dma_iso_ctx(d);
}
else {
- i = it_ctx_talking(video, channel);
- if (i<0) return -EFAULT;
-
- free_dma_iso_ctx(&video->it_context[i]);
-
+ struct dma_iso_ctx **d;
+ d = it_ctx_talking(video, channel);
+ if (d == NULL) return -EFAULT;
PRINT(KERN_INFO, ohci->id,
"Iso context %d stop talking on channel %d",
- i, channel);
+ (*d)->ctx, channel);
+ free_dma_iso_ctx(d);
+
}
return 0;
@@ -1058,15 +1080,14 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
case VIDEO1394_LISTEN_QUEUE_BUFFER:
{
struct video1394_wait v;
- struct dma_iso_ctx *d;
- int i;
+ struct dma_iso_ctx *d, **dd;
if(copy_from_user(&v, (void *)arg, sizeof(v)))
return -EFAULT;
- i = ir_ctx_listening(video, v.channel);
- if (i<0) return -EFAULT;
- d = video->ir_context[i];
+ dd = ir_ctx_listening(video, v.channel);
+ if (dd == NULL) return -EFAULT;
+ d = *dd;
if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->id,
@@ -1122,15 +1143,15 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
case VIDEO1394_LISTEN_POLL_BUFFER:
{
struct video1394_wait v;
- struct dma_iso_ctx *d;
+ struct dma_iso_ctx *d, **dd;
int i;
if(copy_from_user(&v, (void *)arg, sizeof(v)))
return -EFAULT;
- i = ir_ctx_listening(video, v.channel);
- if (i<0) return -EFAULT;
- d = video->ir_context[i];
+ dd = ir_ctx_listening(video, v.channel);
+ if (dd==NULL) return -EFAULT;
+ d = *dd;
if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->id,
@@ -1206,15 +1227,14 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
{
struct video1394_wait v;
struct video1394_queue_variable qv;
- struct dma_iso_ctx *d;
- int i;
+ struct dma_iso_ctx *d, **dd;
if(copy_from_user(&v, (void *)arg, sizeof(v)))
return -EFAULT;
- i = it_ctx_talking(video, v.channel);
- if (i<0) return -EFAULT;
- d = video->it_context[i];
+ dd = it_ctx_talking(video, v.channel);
+ if (dd == NULL) return -EFAULT;
+ d = *dd;
if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->id,
@@ -1298,15 +1318,14 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
case VIDEO1394_TALK_WAIT_BUFFER:
{
struct video1394_wait v;
- struct dma_iso_ctx *d;
- int i;
+ struct dma_iso_ctx *d, **dd;
if(copy_from_user(&v, (void *)arg, sizeof(v)))
return -EFAULT;
- i = it_ctx_talking(video, v.channel);
- if (i<0) return -EFAULT;
- d = video->it_context[i];
+ dd = it_ctx_talking(video, v.channel);
+ if (dd == NULL) return -EFAULT;
+ d = *dd;
if ((v.buffer<0) || (v.buffer>d->num_desc)) {
PRINT(KERN_ERR, ohci->id,
@@ -1367,7 +1386,7 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma)
struct video_card *p;
list_for_each(lh, &video1394_cards) {
p = list_entry(lh, struct video_card, list);
- if (p->id == MINOR(file->f_dentry->d_inode->i_rdev)) {
+ if (p->id == ieee1394_file_to_instance(file)) {
video = p;
break;
}
@@ -1376,8 +1395,8 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma)
spin_unlock_irqrestore(&video1394_cards_lock, flags);
if (video == NULL) {
- PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d",
- MINOR(file->f_dentry->d_inode->i_rdev));
+ PRINT_G(KERN_ERR, "%s: Unknown video card for minor %d",
+ __FUNCTION__, ieee1394_file_to_instance(file));
return -EFAULT;
}
@@ -1387,7 +1406,7 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma)
if (video->current_ctx == NULL) {
PRINT(KERN_ERR, ohci->id, "Current iso context not set");
} else
- res = do_iso_mmap(vma, ohci, video->current_ctx,
+ res = do_iso_mmap(ohci, video->current_ctx,
(char *)vma->vm_start,
(unsigned long)(vma->vm_end-vma->vm_start));
unlock_kernel();
@@ -1396,7 +1415,7 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma)
static int video1394_open(struct inode *inode, struct file *file)
{
- int i = MINOR(inode->i_rdev);
+ int i = ieee1394_file_to_instance(file);
unsigned long flags;
struct video_card *video = NULL;
struct list_head *lh;
@@ -1436,7 +1455,7 @@ static int video1394_release(struct inode *inode, struct file *file)
struct video_card *p;
list_for_each(lh, &video1394_cards) {
p = list_entry(lh, struct video_card, list);
- if (p->id == MINOR(inode->i_rdev)) {
+ if (p->id == ieee1394_file_to_instance(file)) {
video = p;
break;
}
@@ -1445,8 +1464,8 @@ static int video1394_release(struct inode *inode, struct file *file)
spin_unlock_irqrestore(&video1394_cards_lock, flags);
if (video == NULL) {
- PRINT_G(KERN_ERR, __FUNCTION__": Unknown device for minor %d",
- MINOR(inode->i_rdev));
+ PRINT_G(KERN_ERR, "%s: Unknown device for minor %d",
+ __FUNCTION__, ieee1394_file_to_instance(file));
return 1;
}
@@ -1458,13 +1477,13 @@ static int video1394_release(struct inode *inode, struct file *file)
mask = (u64)0x1<<video->ir_context[i]->channel;
if (!(ohci->ISO_channel_usage & mask))
PRINT(KERN_ERR, ohci->id,
- "Channel %d is not being used",
+ "On release: Channel %d is not being used",
video->ir_context[i]->channel);
else
ohci->ISO_channel_usage &= ~mask;
PRINT(KERN_INFO, ohci->id,
"Iso receive context %d stop listening "
- "on channel %d", i+1,
+ "on channel %d", video->ir_context[i]->ctx,
video->ir_context[i]->channel);
free_dma_iso_ctx(&video->ir_context[i]);
}
@@ -1480,7 +1499,7 @@ static int video1394_release(struct inode *inode, struct file *file)
ohci->ISO_channel_usage &= ~mask;
PRINT(KERN_INFO, ohci->id,
"Iso transmit context %d stop talking "
- "on channel %d", i+1,
+ "on channel %d", video->it_context[i]->ctx,
video->it_context[i]->channel);
free_dma_iso_ctx(&video->it_context[i]);
}
@@ -1492,44 +1511,29 @@ static int video1394_release(struct inode *inode, struct file *file)
}
static void irq_handler(int card, quadlet_t isoRecvIntEvent,
- quadlet_t isoXmitIntEvent)
+ quadlet_t isoXmitIntEvent, void *data)
{
int i;
- unsigned long flags;
- struct video_card *video = NULL;
- struct list_head *lh;
-
- spin_lock_irqsave(&video1394_cards_lock, flags);
- if (!list_empty(&video1394_cards)) {
- struct video_card *p;
- list_for_each(lh, &video1394_cards) {
- p = list_entry(lh, struct video_card, list);
- if (p->id == card) {
- video = p;
- break;
- }
- }
- }
- spin_unlock_irqrestore(&video1394_cards_lock, flags);
+ struct video_card *video = (struct video_card*) data;
if (video == NULL) {
- PRINT_G(KERN_ERR, __FUNCTION__": Unknown card number %d!!",
- card);
+ PRINT_G(KERN_ERR, "%s: Unknown card number %d",
+ __FUNCTION__, card);
return;
}
DBGMSG(card, "Iso event Recv: %08x Xmit: %08x",
isoRecvIntEvent, isoXmitIntEvent);
- for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++)
- if (isoRecvIntEvent & (1<<(i+1)))
- wakeup_dma_ir_ctx(video->ohci,
- video->ir_context[i]);
+ for (i = 0; i < video->ohci->nb_iso_rcv_ctx-1; i++)
+ if (video->ir_context[i] != NULL &&
+ isoRecvIntEvent & (1<<(video->ir_context[i]->ctx)))
+ wakeup_dma_ir_ctx(video->ohci, video->ir_context[i]);
- for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++)
- if (isoXmitIntEvent & (1<<i))
- wakeup_dma_it_ctx(video->ohci,
- video->it_context[i]);
+ for (i = 0; i < video->ohci->nb_iso_xmit_ctx; i++)
+ if (video->it_context[i] != NULL &&
+ isoXmitIntEvent & (1<<(video->it_context[i]->ctx)))
+ wakeup_dma_it_ctx(video->ohci, video->it_context[i]);
}
static struct file_operations video1394_fops=
@@ -1559,8 +1563,8 @@ static int video1394_init(struct ti_ohci *ohci)
list_add_tail(&video->list, &video1394_cards);
spin_unlock_irqrestore(&video1394_cards_lock, flags);
- if (ohci1394_register_video(ohci, &video_tmpl)<0) {
- PRINT(KERN_ERR, ohci->id, "Register_video failed");
+ if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
+ PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed");
return -1;
}
@@ -1594,7 +1598,8 @@ static int video1394_init(struct ti_ohci *ohci)
sprintf(name, "%d", video->id);
video->devfs = devfs_register(devfs_handle, name,
DEVFS_FL_AUTO_OWNER,
- VIDEO1394_MAJOR, 0,
+ IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_VIDEO1394*16+video->id,
S_IFCHR | S_IRUSR | S_IWUSR,
&video1394_fops, NULL);
@@ -1606,7 +1611,7 @@ static void remove_card(struct video_card *video)
{
int i;
- ohci1394_unregister_video(video->ohci, &video_tmpl);
+ ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
devfs_unregister(video->devfs);
@@ -1638,7 +1643,7 @@ static void video1394_remove_host (struct hpsb_host *host)
struct video_card *p;
/* We only work with the OHCI-1394 driver */
- if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
+ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
return;
ohci = (struct ti_ohci *)host->hostdata;
@@ -1661,7 +1666,7 @@ static void video1394_add_host (struct hpsb_host *host)
struct ti_ohci *ohci;
/* We only work with the OHCI-1394 driver */
- if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
+ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
return;
ohci = (struct ti_ohci *)host->hostdata;
@@ -1686,19 +1691,19 @@ static void __exit video1394_exit_module (void)
hpsb_unregister_highlevel (hl_handle);
devfs_unregister(devfs_handle);
- devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
-
+ ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
+
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
}
static int __init video1394_init_module (void)
{
- if (devfs_register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME,
- &video1394_fops)) {
- PRINT_G(KERN_ERR, "video1394: unable to get major %d\n",
- VIDEO1394_MAJOR);
- return -EIO;
- }
+ if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
+ THIS_MODULE, &video1394_fops)) {
+ PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
+ return -EIO;
+ }
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
strlen(VIDEO1394_DRIVER_NAME), NULL);
@@ -1710,7 +1715,7 @@ static int __init video1394_init_module (void)
if (hl_handle == NULL) {
PRINT_G(KERN_ERR, "No more memory for driver\n");
devfs_unregister(devfs_handle);
- devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
+ ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
return -ENOMEM;
}
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 77e8488ce..0dd3cc6ea 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -83,6 +83,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
+ dep_tristate 'AVM Fritz!Card classic support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_CLASSIC $CONFIG_HISAX $CONFIG_EXPERIMENTAL
fi
endmenu
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index 5894c35b1..ec2158289 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -67,26 +67,6 @@ static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
card->interrupt = 0;
}
-/* ------------------------------------------------------------- */
-
-static void b1pci_remove_ctr(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- unsigned int port = card->port;
-
- b1_reset(port);
- b1_reset(port);
-
- di->detach_ctr(ctrl);
- free_irq(card->irq, card);
- release_region(card->port, AVMB1_PORTLEN);
- ctrl->driverdata = 0;
- kfree(card->ctrlinfo);
- kfree(card);
-
- MOD_DEC_USE_COUNT;
-}
/* ------------------------------------------------------------- */
@@ -118,20 +98,18 @@ static int b1pci_add_card(struct capi_driver *driver,
MOD_INC_USE_COUNT;
- card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+ retval = -ENOMEM;
+ card = kmalloc(sizeof(avmcard), GFP_KERNEL);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err;
}
memset(card, 0, sizeof(avmcard));
- cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+
+ cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_kfree;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
@@ -140,51 +118,38 @@ static int b1pci_add_card(struct capi_driver *driver,
card->port = p->port;
card->irq = p->irq;
card->cardtype = avm_b1pci;
-
- if (check_region(card->port, AVMB1_PORTLEN)) {
+
+ if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ goto err_kfree_ctrlinfo;
}
b1_reset(card->port);
- if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+ retval = b1_detect(card->port, card->cardtype);
+ if (retval) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
- driver->name, card->port, retval);
- kfree(card->ctrlinfo);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ driver->name, card->port, retval);
+ retval = -EIO;
+ goto err_release_region;
}
b1_reset(card->port);
b1_getrevision(card);
-
- request_region(p->port, AVMB1_PORTLEN, card->name);
-
+
retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
- driver->name, card->irq);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ driver->name, card->irq);
+ retval = -EBUSY;
+ goto err_release_region;
}
-
+
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n",
- driver->name);
- free_irq(card->irq, card);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ driver->name);
+ retval = -EBUSY;
+ goto err_free_irq;
}
if (card->revision >= 4) {
@@ -198,6 +163,37 @@ static int b1pci_add_card(struct capi_driver *driver,
}
return 0;
+
+ err_free_irq:
+ free_irq(card->irq, card);
+ err_release_region:
+ release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+ kfree(card->ctrlinfo);
+ err_kfree:
+ kfree(card);
+ err:
+ MOD_DEC_USE_COUNT;
+ return retval;
+}
+
+static void b1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned int port = card->port;
+
+ b1_reset(port);
+ b1_reset(port);
+
+ di->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
@@ -226,25 +222,6 @@ static struct capi_driver_interface *div4;
/* ------------------------------------------------------------- */
-static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
-
- b1dma_reset(card);
-
- div4->detach_ctr(ctrl);
- free_irq(card->irq, card);
- iounmap(card->mbase);
- release_region(card->port, AVMB1_PORTLEN);
- ctrl->driverdata = 0;
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
-
- MOD_DEC_USE_COUNT;
-}
-
static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -274,28 +251,23 @@ static int b1pciv4_add_card(struct capi_driver *driver,
MOD_INC_USE_COUNT;
- card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+ retval = -ENOMEM;
+ card = kmalloc(sizeof(avmcard), GFP_KERNEL);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err;
}
memset(card, 0, sizeof(avmcard));
+
card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
if (!card->dma) {
printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_kfree;
}
- cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+ cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_dma_free;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
@@ -306,69 +278,47 @@ static int b1pciv4_add_card(struct capi_driver *driver,
card->membase = p->membase;
card->cardtype = avm_b1pci;
- if (check_region(card->port, AVMB1_PORTLEN)) {
+ if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_kfree_ctrlinfo;
}
card->mbase = ioremap_nocache(card->membase, 64);
if (!card->mbase) {
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ retval = -EIO;
+ goto err_release_region;
}
b1dma_reset(card);
- if ((retval = b1pciv4_detect(card)) != 0) {
+ retval = b1pciv4_detect(card);
+ if (retval) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
- iounmap(card->mbase);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ retval = -EIO;
+ goto err_unmap;
}
b1dma_reset(card);
b1_getrevision(card);
- request_region(p->port, AVMB1_PORTLEN, card->name);
-
retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
- iounmap(card->mbase);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_unmap;
}
cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
- iounmap(card->mbase);
- free_irq(card->irq, card);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_free_irq;
}
card->cardnr = cinfo->capi_ctrl->cnr;
@@ -378,6 +328,42 @@ static int b1pciv4_add_card(struct capi_driver *driver,
card->membase, card->revision);
return 0;
+
+ err_free_irq:
+ free_irq(card->irq, card);
+ err_unmap:
+ iounmap(card->mbase);
+ err_release_region:
+ release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+ kfree(card->ctrlinfo);
+ err_dma_free:
+ avmcard_dma_free(card->dma);
+ err_kfree:
+ kfree(card);
+ err:
+ MOD_DEC_USE_COUNT;
+ return retval;
+
+}
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+
+ b1dma_reset(card);
+
+ div4->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ iounmap(card->mbase);
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ avmcard_dma_free(card->dma);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
@@ -402,8 +388,6 @@ static struct capi_driver b1pciv4_driver = {
#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
-static int ncards = 0;
-
static int __devinit b1pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
@@ -470,6 +454,7 @@ static int __init b1pci_init(void)
struct capi_driver *driverv4 = &b1pciv4_driver;
#endif
char *p;
+ int ncards;
MOD_INC_USE_COUNT;
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
index 970eec149..6ea98c6e2 100644
--- a/drivers/isdn/avmb1/c4.c
+++ b/drivers/isdn/avmb1/c4.c
@@ -1133,28 +1133,23 @@ static int c4_add_card(struct capi_driver *driver,
MOD_INC_USE_COUNT;
- card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+ retval = -ENOMEM;
+ card = kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err;
}
memset(card, 0, sizeof(avmcard));
+
card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_kfree;
}
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_dma_free;
}
memset(cinfo, 0, sizeof(avmctrl_info)*4);
card->ctrlinfo = cinfo;
@@ -1168,53 +1163,37 @@ static int c4_add_card(struct capi_driver *driver,
card->membase = p->membase;
card->cardtype = nr == 4 ? avm_c4 : avm_c2;
- if (check_region(card->port, AVMB1_PORTLEN)) {
+ if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_kfree_ctrlinfo;
}
card->mbase = ioremap_nocache(card->membase, 128);
if (card->mbase == 0) {
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ retval = -EIO;
+ goto err_release_region;
}
- if ((retval = c4_detect(card)) != 0) {
+ retval = c4_detect(card);
+ if (retval != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
- iounmap(card->mbase);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ retval = -EIO;
+ goto err_unmap;
}
c4_reset(card);
- request_region(p->port, AVMB1_PORTLEN, card->name);
-
retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
- iounmap(card->mbase);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_unmap;
}
for (i=0; i < nr ; i++) {
@@ -1228,14 +1207,7 @@ static int c4_add_card(struct capi_driver *driver,
cinfo = &card->ctrlinfo[i];
di->detach_ctr(cinfo->capi_ctrl);
}
- iounmap(card->mbase);
- free_irq(card->irq, card);
- release_region(card->port, AVMB1_PORTLEN);
- avmcard_dma_free(card->dma);
- kfree(card->ctrlinfo);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ goto err_free_irq;
}
if (i == 0)
card->cardnr = cinfo->capi_ctrl->cnr;
@@ -1246,6 +1218,22 @@ static int c4_add_card(struct capi_driver *driver,
driver->name, nr, card->port, card->irq, card->membase);
return 0;
+
+ err_free_irq:
+ free_irq(card->irq, card);
+ err_unmap:
+ iounmap(card->mbase);
+ err_release_region:
+ release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+ kfree(card->ctrlinfo);
+ err_dma_free:
+ avmcard_dma_free(card->dma);
+ err_kfree:
+ kfree(card);
+ err:
+ MOD_DEC_USE_COUNT;
+ return retval;
}
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
index e07ffe0d3..85c054d2b 100644
--- a/drivers/isdn/avmb1/t1pci.c
+++ b/drivers/isdn/avmb1/t1pci.c
@@ -49,27 +49,6 @@ static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
-static void t1pci_remove_ctr(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
-
- b1dma_reset(card);
-
- di->detach_ctr(ctrl);
- free_irq(card->irq, card);
- iounmap(card->mbase);
- release_region(card->port, AVMB1_PORTLEN);
- ctrl->driverdata = 0;
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
-
- MOD_DEC_USE_COUNT;
-}
-
-/* ------------------------------------------------------------- */
-
static int t1pci_add_card(struct capi_driver *driver,
struct capicardparams *p,
struct pci_dev *dev)
@@ -80,28 +59,22 @@ static int t1pci_add_card(struct capi_driver *driver,
MOD_INC_USE_COUNT;
- card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+ retval = -ENOMEM;
+ card = kmalloc(sizeof(avmcard), GFP_KERNEL);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err;
}
memset(card, 0, sizeof(avmcard));
card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_kfree;
}
- cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+ cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
+ goto err_dma_free;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
@@ -112,72 +85,50 @@ static int t1pci_add_card(struct capi_driver *driver,
card->membase = p->membase;
card->cardtype = avm_t1pci;
- if (check_region(card->port, AVMB1_PORTLEN)) {
+ if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_kfree_ctrlinfo;
}
card->mbase = ioremap_nocache(card->membase, 64);
if (!card->mbase) {
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ retval = -EIO;
+ goto err_release_region;
}
b1dma_reset(card);
- if ((retval = t1pci_detect(card)) != 0) {
+ retval = t1pci_detect(card);
+ if (retval != 0) {
if (retval < 6)
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
else
printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
driver->name, card->port, retval);
- iounmap(card->mbase);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EIO;
+ retval = -EIO;
+ goto err_unmap;
}
b1dma_reset(card);
- request_region(p->port, AVMB1_PORTLEN, card->name);
-
retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
- iounmap(card->mbase);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_unmap;
}
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
- iounmap(card->mbase);
- free_irq(card->irq, card);
- release_region(card->port, AVMB1_PORTLEN);
- kfree(card->ctrlinfo);
- avmcard_dma_free(card->dma);
- kfree(card);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_free_irq;
}
card->cardnr = cinfo->capi_ctrl->cnr;
@@ -186,6 +137,43 @@ static int t1pci_add_card(struct capi_driver *driver,
driver->name, card->port, card->irq, card->membase);
return 0;
+
+ err_free_irq:
+ free_irq(card->irq, card);
+ err_unmap:
+ iounmap(card->mbase);
+ err_release_region:
+ release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+ kfree(card->ctrlinfo);
+ err_dma_free:
+ avmcard_dma_free(card->dma);
+ err_kfree:
+ kfree(card);
+ err:
+ MOD_DEC_USE_COUNT;
+ return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+
+ b1dma_reset(card);
+
+ di->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ iounmap(card->mbase);
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ avmcard_dma_free(card->dma);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index ef6aaca1a..8fdf46943 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -10,7 +10,7 @@ EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
# Objects that export symbols.
-export-objs := config.o fsm.o hisax_isac.o
+export-objs := config.o fsm.o hisax_isac.o hisax_hscx.o
# Multipart objects.
@@ -63,6 +63,7 @@ obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
+obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o
CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 9215b06ae..bed060a41 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -561,7 +561,7 @@ hdlc_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -577,7 +577,7 @@ hdlc_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
modehdlc(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -640,7 +640,7 @@ setstack_hdlc(struct PStack *st, struct BCState *bcs)
if (open_hdlcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = hdlc_l2l1;
+ st->l1.l2l1 = hdlc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 47cee5b06..918a39b41 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -250,7 +250,6 @@ lli_leased_in(struct FsmInst *fi, int event, void *arg)
}
}
-
/*
* Dial out
*/
@@ -264,7 +263,7 @@ lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
link_debug(chanp, 0, "STAT_DCONN");
HL_LL(chanp, ISDN_STAT_DCONN);
init_b_st(chanp, 0);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+ L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
}
static void
@@ -281,7 +280,7 @@ lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
lli_init_bchan_out(fi, event, arg);
} else {
FsmChangeState(fi, ST_OUT_DIAL);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
+ L4L3(chanp->d_st, CC_SETUP | REQUEST, chanp);
}
}
@@ -299,7 +298,7 @@ lli_resume(struct FsmInst *fi, int event, void *arg)
lli_init_bchan_out(fi, event, arg);
} else {
FsmChangeState(fi, ST_OUT_DIAL);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
+ L4L3(chanp->d_st, CC_RESUME | REQUEST, chanp);
}
}
@@ -366,33 +365,33 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
case 1: /* OK, someone likes this call */
FsmDelTimer(&chanp->drel_timer, 61);
FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
break;
case 5: /* direct redirect */
case 4: /* Proceeding desired */
FsmDelTimer(&chanp->drel_timer, 61);
FsmChangeState(fi, ST_IN_PROCEED_SEND);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
if (ret == 5) {
memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
}
break;
case 2: /* Rejecting Call */
break;
case 3: /* incomplete number */
FsmDelTimer(&chanp->drel_timer, 61);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
break;
case 0: /* OK, nobody likes this call */
default: /* statcallb problems */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
FsmChangeState(fi, ST_NULL);
break;
}
} else {
- chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
}
}
@@ -403,7 +402,7 @@ lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+ L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
}
static void
@@ -412,7 +411,7 @@ lli_send_alert(struct FsmInst *fi, int event, void *arg)
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
}
static void
@@ -420,7 +419,7 @@ lli_send_redir(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
}
static void
@@ -435,7 +434,7 @@ lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
chanp->l2_active_protocol = chanp->l2_protocol;
chanp->incoming = !0;
init_b_st(chanp, !0);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+ L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
}
static void
@@ -448,9 +447,9 @@ lli_setup_rsp(struct FsmInst *fi, int event, void *arg)
} else {
FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
#ifdef WANT_ALERT
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
#endif
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+ L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
}
}
@@ -461,7 +460,7 @@ lli_suspend(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
}
/* Call clearing */
@@ -493,8 +492,7 @@ lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
FsmChangeState(fi, ST_WAIT_DRELEASE);
if (chanp->proc)
chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
- chanp->proc);
+ L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
}
}
@@ -509,8 +507,7 @@ lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
FsmChangeState(fi, ST_WAIT_DRELEASE);
if (chanp->proc)
chanp->proc->para.cause = 0x15; /* Call Rejected */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
- chanp->proc);
+ L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
}
}
@@ -542,12 +539,12 @@ lli_reject_req(struct FsmInst *fi, int event, void *arg)
#ifndef ALERT_REJECT
if (chanp->proc)
chanp->proc->para.cause = 0x15; /* Call Rejected */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
lli_dhup_close(fi, event, arg);
#else
FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
#endif
}
@@ -558,7 +555,7 @@ lli_disconn_bchan(struct FsmInst *fi, int event, void *arg)
chanp->data_open = 0;
FsmChangeState(fi, ST_WAIT_BRELEASE);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+ L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
}
static void
@@ -613,7 +610,7 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg)
chanp->data_open = 0;
FsmChangeState(fi, ST_WAIT_BREL_DISC);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+ L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
}
@@ -643,7 +640,7 @@ lli_abort(struct FsmInst *fi, int event, void *arg)
struct Channel *chanp = fi->userdata;
chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+ L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
lli_bhup_dhup(fi, event, arg);
}
@@ -656,8 +653,7 @@ lli_release_req(struct FsmInst *fi, int event, void *arg)
lli_leased_hup(fi, chanp);
} else {
FsmChangeState(fi, ST_WAIT_D_REL_CNF);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST,
- chanp->proc);
+ L4L3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc);
}
}
@@ -768,7 +764,7 @@ lli_failure_a(struct FsmInst *fi, int event, void *arg)
struct Channel *chanp = fi->userdata;
chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+ L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
lli_bhup_fail(fi, event, arg);
}
@@ -942,7 +938,7 @@ dchan_l3l4(struct PStack *st, int pr, void *arg)
if (pr == (CC_SETUP | INDICATION)) {
if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
pc->para.cause = 0x11; /* User busy */
- pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
+ L4L3(pc->st, CC_REJECT | REQUEST, pc);
} else {
chanp->proc = pc;
pc->chan = chanp;
@@ -1025,16 +1021,16 @@ init_PStack(struct PStack **stp) {
if (!*stp)
return -ENOMEM;
(*stp)->next = NULL;
- (*stp)->l1.l1l2 = dummy_pstack;
(*stp)->l1.l1hw = dummy_pstack;
(*stp)->l1.l1tei = dummy_pstack;
+ (*stp)->l1.l2l1 = dummy_pstack;
+ (*stp)->l2.l1l2 = dummy_pstack;
(*stp)->l2.l2tei = dummy_pstack;
- (*stp)->l2.l2l1 = dummy_pstack;
- (*stp)->l2.l2l3 = dummy_pstack;
- (*stp)->l3.l3l2 = dummy_pstack;
+ (*stp)->l2.l3l2 = dummy_pstack;
+ (*stp)->l3.l2l3 = dummy_pstack;
(*stp)->l3.l3ml3 = dummy_pstack;
- (*stp)->l3.l3l4 = dummy_pstack;
- (*stp)->lli.l4l3 = dummy_pstack;
+ (*stp)->l3.l4l3 = dummy_pstack;
+ (*stp)->lli.l3l4 = dummy_pstack;
(*stp)->ma.layer = dummy_pstack;
return 0;
}
@@ -1073,7 +1069,7 @@ init_d_st(struct Channel *chanp)
setstack_l3dc(st, chanp);
st->lli.userdata = chanp;
st->lli.l2writewakeup = NULL;
- st->l3.l3l4 = dchan_l3l4;
+ st->lli.l3l4 = dchan_l3l4;
return 0;
}
@@ -1147,8 +1143,7 @@ CallcNewChan(struct IsdnCardState *csta) {
printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
- csta->channel->d_st->lli.l4l3(csta->channel->d_st,
- DL_ESTABLISH | REQUEST, NULL);
+ L4L3(csta->channel->d_st, DL_ESTABLISH | REQUEST, NULL);
}
return (0);
}
@@ -1317,7 +1312,7 @@ init_b_st(struct Channel *chanp, int incoming)
sprintf(tmp, "Ch%d X.75", chanp->chan);
setstack_isdnl2(st, tmp);
setstack_l3bc(st, chanp);
- st->l2.l2l3 = lldata_handler;
+ st->l3.l2l3 = lldata_handler;
st->lli.userdata = chanp;
st->lli.l1writewakeup = NULL;
st->lli.l2writewakeup = ll_writewakeup;
@@ -1329,7 +1324,7 @@ init_b_st(struct Channel *chanp, int incoming)
case (ISDN_PROTO_L2_TRANS):
case (ISDN_PROTO_L2_MODEM):
case (ISDN_PROTO_L2_FAX):
- st->l1.l1l2 = lltrans_handler;
+ st->l2.l1l2 = lltrans_handler;
st->lli.userdata = chanp;
st->lli.l1writewakeup = ll_writewakeup;
setstack_transl2(st);
@@ -1352,7 +1347,7 @@ leased_l4l3(struct PStack *st, int pr, void *arg)
dev_kfree_skb(skb);
break;
case (DL_ESTABLISH | REQUEST):
- st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+ L2L1(st, PH_ACTIVATE | REQUEST, NULL);
break;
case (DL_RELEASE | REQUEST):
break;
@@ -1650,16 +1645,15 @@ HiSax_command(isdn_ctrl * ic)
HiSax_putstatus(csta, "Card",
"%d channel %d set leased mode\n",
csta->cardnr + 1, num + 1);
- chanp->d_st->l1.l1l2 = leased_l1l2;
- chanp->d_st->lli.l4l3 = leased_l4l3;
- chanp->d_st->lli.l4l3(chanp->d_st,
- DL_ESTABLISH | REQUEST, NULL);
+ chanp->d_st->l2.l1l2 = leased_l1l2;
+ chanp->d_st->l3.l4l3 = leased_l4l3;
+ L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
}
break;
case (6): /* set B-channel test loop */
num = *(unsigned int *) ic->parm.num;
if (csta->stlist)
- csta->stlist->l2.l2l1(csta->stlist,
+ csta->stlist->l1.l2l1(csta->stlist,
PH_TESTLOOP | REQUEST, (void *) (long)num);
break;
case (7): /* set card in PTP mode */
@@ -1673,8 +1667,7 @@ HiSax_command(isdn_ctrl * ic)
HiSax_putstatus(csta, "set card ", "in PTP mode");
printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
- csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
- DL_ESTABLISH | REQUEST, NULL);
+ L4L3(csta->channel[0].d_st, DL_ESTABLISH | REQUEST, NULL);
} else {
test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
@@ -1698,8 +1691,7 @@ HiSax_command(isdn_ctrl * ic)
printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
num);
}
- chanp->d_st->lli.l4l3(chanp->d_st,
- DL_ESTABLISH | REQUEST, NULL);
+ L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
break;
#ifdef MODULE
case (55):
@@ -1764,7 +1756,7 @@ HiSax_command(isdn_ctrl * ic)
case (ISDN_CMD_PROT_IO):
for (st = csta->stlist; st; st = st->next)
if (st->protocol == (ic->arg & 0xFF))
- return(st->lli.l4l3_proto(st, ic));
+ return(st->l3.l4l3_proto(st, ic));
return(-EINVAL);
break;
default:
@@ -1820,10 +1812,10 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
if (!ack)
nskb->pkt_type = PACKET_NOACK;
if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I)
- st->l3.l3l2(st, DL_DATA | REQUEST, nskb);
+ L3L2(st, DL_DATA | REQUEST, nskb);
else {
chanp->bcs->tx_cnt += len;
- st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
+ st->l1.l2l1(st, PH_DATA | REQUEST, nskb);
}
dev_kfree_skb(skb);
} else
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 56f2e69be..25280172b 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1776,7 +1776,7 @@ int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
cs->hw.hisax_d_if = hisax_d_if;
cs->cardmsg = hisax_cardmsg;
cs->tqueue.routine = (void *) (void *) hisax_bh;
- cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1;
+ cs->channel[0].d_st->l1.l2l1 = hisax_d_l2l1;
for (i = 0; i < 2; i++) {
cs->bcs[i].BC_SetStack = hisax_bc_setstack;
cs->bcs[i].BC_Close = hisax_bc_close;
@@ -1823,7 +1823,7 @@ static void hisax_bh(struct IsdnCardState *cs)
else
pr = PH_DEACTIVATE | INDICATION;
for (st = cs->stlist; st; st = st->next)
- st->l1.l1l2(st, pr, NULL);
+ L1L2(st, pr, NULL);
}
}
@@ -1876,7 +1876,7 @@ static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg)
clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
for (st = cs->stlist; st; st = st->next) {
if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
break;
}
}
@@ -1901,10 +1901,10 @@ static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
// FIXME use isdnl1?
switch (pr) {
case PH_ACTIVATE | INDICATION:
- st->l1.l1l2(st, pr, NULL);
+ L1L2(st, pr, NULL);
break;
case PH_DEACTIVATE | INDICATION:
- st->l1.l1l2(st, pr, NULL);
+ L1L2(st, pr, NULL);
bcs->hw.b_if = NULL;
break;
case PH_DATA | INDICATION:
@@ -1922,7 +1922,7 @@ static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
}
clear_bit(BC_FLG_BUSY, &bcs->Flag);
if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
}
break;
default:
@@ -1953,7 +1953,7 @@ static void hisax_d_l2l1(struct PStack *st, int pr, void *arg)
break;
case PH_PULL | REQUEST:
if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
else
set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -1988,7 +1988,7 @@ static void hisax_b_l2l1(struct PStack *st, int pr, void *arg)
break;
case PH_PULL | REQUEST:
if (!test_bit(BC_FLG_BUSY, &bcs->Flag))
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
else
set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -2009,7 +2009,7 @@ static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs)
hisax_d_if->b_if[st->l1.bc]->bcs = bcs;
st->l1.bcs = bcs;
- st->l2.l2l1 = hisax_b_l2l1;
+ st->l1.l2l1 = hisax_b_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 877834257..6ef49f05b 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -591,7 +591,7 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
}
} else if (pr == (PH_ACTIVATE | REQUEST)) {
test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
set_arcofi(st->l1.bcs->cs, st->l1.bc);
mstartup(st->l1.bcs->cs);
modem_set_dial(st->l1.bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
@@ -617,7 +617,7 @@ setstack_elsa(struct PStack *st, struct BCState *bcs)
case L1_MODE_TRANS:
if (open_hscxstate(st->l1.hardware, bcs))
return (-1);
- st->l2.l2l1 = hscx_l2l1;
+ st->l1.l2l1 = hscx_l2l1;
break;
case L1_MODE_MODEM:
bcs->mode = L1_MODE_MODEM;
@@ -632,7 +632,7 @@ setstack_elsa(struct PStack *st, struct BCState *bcs)
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
bcs->cs->hw.elsa.bcs = bcs;
- st->l2.l2l1 = modem_l2l1;
+ st->l1.l2l1 = modem_l2l1;
break;
}
st->l1.bcs = bcs;
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index cb8eb837f..7695a2ccb 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -545,7 +545,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -561,7 +561,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
mode_2bs0(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -602,7 +602,7 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
if (open_hfcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = hfc_l2l1;
+ st->l1.l2l1 = hfc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
@@ -1066,7 +1066,7 @@ HFCD_l1hw(struct PStack *st, int pr, void *arg)
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index e329f0480..2b7e330bc 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -507,7 +507,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -523,7 +523,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
mode_hfc(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -566,7 +566,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
if (open_hfcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = hfc_l2l1;
+ st->l1.l2l1 = hfc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index eb5cf7de2..bcebb3b95 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -776,7 +776,7 @@ dch_nt_l2l1(struct PStack *st, int pr, void *arg)
st->l1.l1hw(st, pr, arg);
break;
case (PH_ACTIVATE | REQUEST):
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
break;
case (PH_TESTLOOP | REQUEST):
if (1 & (long) arg)
@@ -821,7 +821,7 @@ hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
cs->dc.hfcpci.ph_state = 1;
cs->hw.hfcpci.nt_mode = 1;
cs->hw.hfcpci.nt_timer = 0;
- cs->stlist->l2.l2l1 = dch_nt_l2l1;
+ cs->stlist->l1.l2l1 = dch_nt_l2l1;
restore_flags(flags);
debugl1(cs, "NT mode activated");
return (0);
@@ -1211,7 +1211,7 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -1462,7 +1462,7 @@ hfcpci_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -1478,7 +1478,7 @@ hfcpci_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
mode_hfcpci(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -1528,7 +1528,7 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
if (open_hfcpcistate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = hfcpci_l2l1;
+ st->l1.l2l1 = hfcpci_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index ad9690ff0..a01628bb3 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -632,7 +632,7 @@ dch_nt_l2l1(struct PStack *st, int pr, void *arg)
st->l1.l1hw(st, pr, arg);
break;
case (PH_ACTIVATE | REQUEST):
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
break;
case (PH_TESTLOOP | REQUEST):
if (1 & (long) arg)
@@ -676,7 +676,7 @@ hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
cs->dc.hfcsx.ph_state = 1;
cs->hw.hfcsx.nt_mode = 1;
cs->hw.hfcsx.nt_timer = 0;
- cs->stlist->l2.l2l1 = dch_nt_l2l1;
+ cs->stlist->l1.l2l1 = dch_nt_l2l1;
restore_flags(flags);
debugl1(cs, "NT mode activated");
return (0);
@@ -1008,7 +1008,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -1248,7 +1248,7 @@ hfcsx_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -1264,7 +1264,7 @@ hfcsx_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
mode_hfcsx(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -1314,7 +1314,7 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
if (open_hfcsxstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = hfcsx_l2l1;
+ st->l1.l2l1 = hfcsx_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index cee7b10a2..4915d01ad 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -203,9 +203,9 @@ struct Layer1 {
long Flags;
struct FsmInst l1m;
struct FsmTimer timer;
- void (*l1l2) (struct PStack *, int, void *);
void (*l1hw) (struct PStack *, int, void *);
void (*l1tei) (struct PStack *, int, void *);
+ void (*l2l1) (struct PStack *, int, void *);
int mode, bc;
int delay;
};
@@ -247,8 +247,8 @@ struct Layer2 {
struct sk_buff *windowar[MAX_WINDOW];
struct sk_buff_head i_queue;
struct sk_buff_head ui_queue;
- void (*l2l1) (struct PStack *, int, void *);
- void (*l2l3) (struct PStack *, int, void *);
+ void (*l3l2) (struct PStack *, int, void *);
+ void (*l1l2) (struct PStack *, int, void *);
void (*l2tei) (struct PStack *, int, void *);
struct FsmInst l2m;
struct FsmTimer t200, t203;
@@ -258,9 +258,10 @@ struct Layer2 {
};
struct Layer3 {
- void (*l3l4) (struct PStack *, int, void *);
+ void (*l4l3) (struct PStack *, int, void *);
+ int (*l4l3_proto) (struct PStack *, isdn_ctrl *);
void (*l3ml3) (struct PStack *, int, void *);
- void (*l3l2) (struct PStack *, int, void *);
+ void (*l2l3) (struct PStack *, int, void *);
struct FsmInst l3m;
struct FsmTimer l3m_timer;
struct sk_buff_head squeue;
@@ -272,8 +273,7 @@ struct Layer3 {
};
struct LLInterface {
- void (*l4l3) (struct PStack *, int, void *);
- int (*l4l3_proto) (struct PStack *, isdn_ctrl *);
+ void (*l3l4) (struct PStack *, int, void *);
void *userdata;
void (*l1writewakeup) (struct PStack *, int);
void (*l2writewakeup) (struct PStack *, int);
@@ -1348,3 +1348,40 @@ char *HiSax_getrev(const char *revision);
int TeiNew(void);
void TeiFree(void);
int certification_check(int output);
+
+static inline void
+L2L1(struct PStack *st, int pr, void *arg)
+{
+ st->l1.l2l1(st, pr, arg);
+}
+
+static inline void
+L1L2(struct PStack *st, int pr, void *arg)
+{
+ st->l2.l1l2(st, pr, arg);
+}
+
+static inline void
+L3L2(struct PStack *st, int pr, void *arg)
+{
+ st->l2.l3l2(st, pr, arg);
+}
+
+static inline void
+L2L3(struct PStack *st, int pr, void *arg)
+{
+ st->l3.l2l3(st, pr, arg);
+}
+
+static inline void
+L3L4(struct PStack *st, int pr, void *arg)
+{
+ st->lli.l3l4(st, pr, arg);
+}
+
+static inline void
+L4L3(struct PStack *st, int pr, void *arg)
+{
+ st->l3.l4l3(st, pr, arg);
+}
+
diff --git a/drivers/isdn/hisax/hisax_fcclassic.c b/drivers/isdn/hisax/hisax_fcclassic.c
new file mode 100644
index 000000000..a5061581e
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_fcclassic.c
@@ -0,0 +1,384 @@
+/*
+ * Driver for AVM Fritz!classic (ISA) ISDN card
+ *
+ * Author Kai Germaschewski
+ * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ * 2001 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * based upon Karsten Keil's original avm_a1.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include "hisax_fcclassic.h"
+
+// debugging cruft
+#define __debug_variable debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("AVM Fritz!Card classic ISDN driver");
+
+static int protocol = 2; /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+// ----------------------------------------------------------------------
+
+#define AVM_A1_STAT_ISAC 0x01
+#define AVM_A1_STAT_HSCX 0x02
+#define AVM_A1_STAT_TIMER 0x04
+
+// ----------------------------------------------------------------------
+
+static unsigned char
+fcclassic_read_isac(struct isac *isac, unsigned char offset)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned char val;
+
+ val = inb(adapter->isac_base + offset);
+ DBG(0x1000, " port %#x, value %#x",
+ offset, val);
+ return val;
+}
+
+static void
+fcclassic_write_isac(struct isac *isac, unsigned char offset,
+ unsigned char value)
+{
+ struct fritz_adapter *adapter = isac->priv;
+
+ DBG(0x1000, " port %#x, value %#x",
+ offset, value);
+ outb(value, adapter->isac_base + offset);
+}
+
+static void
+fcclassic_read_isac_fifo(struct isac *isac, unsigned char * data, int size)
+{
+ struct fritz_adapter *adapter = isac->priv;
+
+ insb(adapter->isac_fifo, data, size);
+}
+
+static void
+fcclassic_write_isac_fifo(struct isac *isac, unsigned char * data, int size)
+{
+ struct fritz_adapter *adapter = isac->priv;
+
+ outsb(adapter->isac_fifo, data, size);
+}
+
+static u_char
+fcclassic_read_hscx(struct hscx *hscx, u_char offset)
+{
+ struct fritz_adapter *adapter = hscx->priv;
+
+ return inb(adapter->hscx_base[hscx->channel] + offset);
+}
+
+static void
+fcclassic_write_hscx(struct hscx *hscx, u_char offset, u_char value)
+{
+ struct fritz_adapter *adapter = hscx->priv;
+
+ outb(value, adapter->hscx_base[hscx->channel] + offset);
+}
+
+static void
+fcclassic_read_hscx_fifo(struct hscx *hscx, unsigned char * data, int size)
+{
+ struct fritz_adapter *adapter = hscx->priv;
+
+ insb(adapter->hscx_fifo[hscx->channel], data, size);
+}
+
+static void
+fcclassic_write_hscx_fifo(struct hscx *hscx, unsigned char * data, int size)
+{
+ struct fritz_adapter *adapter = hscx->priv;
+
+ outsb(adapter->hscx_fifo[hscx->channel], data, size);
+}
+
+// ----------------------------------------------------------------------
+
+static void
+fcclassic_irq(int intno, void *dev, struct pt_regs *regs)
+{
+ struct fritz_adapter *adapter = dev;
+ unsigned char sval;
+
+ DBG(2, "");
+ while ((sval = inb(adapter->cfg_reg) & 0xf) != 0x7) {
+ DBG(2, "sval %#x", sval);
+ if (!(sval & AVM_A1_STAT_TIMER)) {
+ outb(0x1e, adapter->cfg_reg);
+ }
+ if (!(sval & AVM_A1_STAT_HSCX)) {
+ hscx_irq(adapter->hscx);
+ }
+ if (!(sval & AVM_A1_STAT_ISAC)) {
+ isac_irq(&adapter->isac);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+
+static int __init
+fcclassic_setup(struct fritz_adapter *adapter)
+{
+ u32 val = 0;
+ int i;
+ int retval;
+
+ DBG(1,"");
+
+ isac_init(&adapter->isac); // FIXME is this okay now
+
+ adapter->cfg_reg = adapter->io + 0x1800;
+ adapter->isac_base = adapter->io + 0x1400 - 0x20;
+ adapter->isac_fifo = adapter->io + 0x1000;
+ adapter->hscx_base[0] = adapter->io + 0x0400 - 0x20;
+ adapter->hscx_fifo[0] = adapter->io;
+ adapter->hscx_base[1] = adapter->io + 0x0c00 - 0x20;
+ adapter->hscx_fifo[1] = adapter->io + 0x0800;
+
+ retval = -EBUSY;
+ if (!request_region(adapter->cfg_reg , 8,
+ "fcclassic cfg"))
+ goto err;
+ if (!request_region(adapter->isac_base + 0x20 , 32,
+ "fcclassic isac"))
+ goto err_cfg_reg;
+ if (!request_region(adapter->isac_fifo , 1,
+ "fcclassic isac fifo"))
+ goto err_isac_base;
+ if (!request_region(adapter->hscx_base[0] + 0x20, 32,
+ "fcclassic hscx"))
+ goto err_isac_fifo;
+ if (!request_region(adapter->hscx_fifo[0] , 1,
+ "fcclassic hscx fifo"))
+ goto err_hscx_base_0;
+ if (!request_region(adapter->hscx_base[1] + 0x20, 32,
+ "fcclassic hscx"))
+ goto err_hscx_fifo_0;
+ if (!request_region(adapter->hscx_fifo[1] , 1,
+ "fcclassic hscx fifo"))
+ goto err_hscx_base_1;
+ retval = request_irq(adapter->irq, fcclassic_irq, 0,
+ "fcclassic", adapter);
+ if (retval)
+ goto err_hscx_fifo_1;
+
+ // Reset
+ outb(0x00, adapter->cfg_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(200 * HZ / 1000); // 200 msec
+ outb(0x01, adapter->cfg_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(200 * HZ / 1000); // 200 msec
+ outb(0x00, adapter->cfg_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(200 * HZ / 1000); // 200 msec
+
+ val = adapter->irq;
+ if (val == 9)
+ val = 2;
+ outb(val, adapter->cfg_reg + 1);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(200 * HZ / 1000); // 200 msec
+ outb(0x00, adapter->cfg_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(200 * HZ / 1000); // 200 msec
+
+ val = inb(adapter->cfg_reg);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ adapter->cfg_reg, val);
+ val = inb(adapter->cfg_reg + 3);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ adapter->cfg_reg + 3, val);
+ val = inb(adapter->cfg_reg + 2);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ adapter->cfg_reg + 2, val);
+ val = inb(adapter->cfg_reg);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ adapter->cfg_reg, val);
+
+ outb(0x16, adapter->cfg_reg);
+ outb(0x1e, adapter->cfg_reg);
+
+ adapter->isac.priv = adapter;
+ adapter->isac.read_isac = &fcclassic_read_isac;
+ adapter->isac.write_isac = &fcclassic_write_isac;
+ adapter->isac.read_isac_fifo = &fcclassic_read_isac_fifo;
+ adapter->isac.write_isac_fifo = &fcclassic_write_isac_fifo;
+ isac_setup(&adapter->isac);
+ for (i = 0; i < 2; i++) {
+ hscx_init(&adapter->hscx[i]);
+ adapter->hscx[i].priv = adapter;
+ adapter->hscx[i].read_hscx = &fcclassic_read_hscx;
+ adapter->hscx[i].write_hscx = &fcclassic_write_hscx;
+ adapter->hscx[i].read_hscx_fifo = &fcclassic_read_hscx_fifo;
+ adapter->hscx[i].write_hscx_fifo = &fcclassic_write_hscx_fifo;
+ hscx_setup(&adapter->hscx[i]);
+ }
+
+ return 0;
+
+ err_hscx_fifo_1:
+ release_region(adapter->hscx_fifo[1] , 1);
+ err_hscx_base_1:
+ release_region(adapter->hscx_base[1] + 0x20, 32);
+ err_hscx_fifo_0:
+ release_region(adapter->hscx_fifo[0] , 1);
+ err_hscx_base_0:
+ release_region(adapter->hscx_base[0] + 0x20, 32);
+ err_isac_fifo:
+ release_region(adapter->isac_fifo , 1);
+ err_isac_base:
+ release_region(adapter->isac_base + 0x20, 32);
+ err_cfg_reg:
+ release_region(adapter->cfg_reg , 8);
+ err:
+ return retval;
+}
+
+static void __exit fcclassic_release(struct fritz_adapter *adapter)
+{
+ DBG(1,"");
+
+// outb(0, adapter->io + AVM_STATUS0);
+ free_irq(adapter->irq, adapter);
+ release_region(adapter->hscx_fifo[1] , 1);
+ release_region(adapter->hscx_base[1] + 0x20, 32);
+ release_region(adapter->hscx_fifo[0] , 1);
+ release_region(adapter->hscx_base[0] + 0x20, 32);
+ release_region(adapter->isac_fifo , 1);
+ release_region(adapter->isac_base + 0x20, 32);
+ release_region(adapter->cfg_reg , 8);
+}
+
+// ----------------------------------------------------------------------
+
+static struct fritz_adapter * __init
+new_adapter(struct pci_dev *pdev)
+{
+ struct fritz_adapter *adapter;
+ struct hisax_b_if *b_if[2];
+ int i;
+
+ adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
+ if (!adapter)
+ return NULL;
+
+ memset(adapter, 0, sizeof(struct fritz_adapter));
+
+ SET_MODULE_OWNER(&adapter->isac.hisax_d_if);
+ adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
+ adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
+
+ for (i = 0; i < 2; i++) {
+ // adapter->hscx[i].adapter = adapter;
+ adapter->hscx[i].channel = i;
+ adapter->hscx[i].b_if.ifc.priv = &adapter->hscx[i];
+ adapter->hscx[i].b_if.ifc.l2l1 = hscx_b_l2l1;
+ }
+ pci_set_drvdata(pdev, adapter);
+
+ for (i = 0; i < 2; i++)
+ b_if[i] = &adapter->hscx[i].b_if;
+
+ hisax_register(&adapter->isac.hisax_d_if, b_if, "fcclassic", protocol);
+
+ return adapter;
+}
+
+static void
+delete_adapter(struct fritz_adapter *adapter)
+{
+ hisax_unregister(&adapter->isac.hisax_d_if);
+ kfree(adapter);
+}
+
+static int __init
+fcclassic_probe(struct pci_dev *pdev, const struct isapnp_device_id *ent)
+{
+ struct fritz_adapter *adapter;
+ int retval;
+
+ retval = -ENOMEM;
+ adapter = new_adapter(pdev);
+ if (!adapter)
+ goto err;
+
+ adapter->io = pdev->resource[0].start;
+ adapter->irq = pdev->irq_resource[0].start;
+
+ printk(KERN_INFO "hisax_fcclassic: found Fritz!Card classic at IO %#x irq %d\n",
+ adapter->io, adapter->irq);
+
+ retval = fcclassic_setup(adapter);
+ if (retval)
+ goto err_free;
+
+ return 0;
+
+ err_free:
+ delete_adapter(adapter);
+ err:
+ return retval;
+}
+
+static int __exit
+fcclassic_remove(struct pci_dev *pdev)
+{
+ struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+ fcclassic_release(adapter);
+ delete_adapter(adapter);
+
+ return 0;
+}
+
+static struct pci_dev isa_dev[4];
+
+static int __init
+hisax_fcclassic_init(void)
+{
+ printk(KERN_INFO "hisax_fcclassic: Fritz!Card classic ISDN driver v0.0.1\n");
+
+ isa_dev[0].resource[0].start = 0x300;
+ isa_dev[0].irq_resource[0].start = 7;
+
+ fcclassic_probe(isa_dev, NULL);
+
+ return 0;
+}
+
+static void __exit
+hisax_fcclassic_exit(void)
+{
+ fcclassic_remove(isa_dev);
+}
+
+module_init(hisax_fcclassic_init);
+module_exit(hisax_fcclassic_exit);
diff --git a/drivers/isdn/hisax/hisax_fcclassic.h b/drivers/isdn/hisax/hisax_fcclassic.h
new file mode 100644
index 000000000..9a606d22a
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_fcclassic.h
@@ -0,0 +1,18 @@
+#include "hisax_if.h"
+#include "hisax_isac.h"
+#include "hisax_hscx.h"
+
+#include <linux/pci.h>
+
+struct fritz_adapter {
+ unsigned int io;
+ unsigned int irq;
+ unsigned int cfg_reg;
+ unsigned int isac_base;
+ unsigned int isac_fifo;
+ unsigned int hscx_base[2];
+ unsigned int hscx_fifo[2];
+ struct isac isac;
+
+ struct hscx hscx[2];
+};
diff --git a/drivers/isdn/hisax/hisax_hscx.c b/drivers/isdn/hisax/hisax_hscx.c
new file mode 100644
index 000000000..bbeecd35d
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_hscx.c
@@ -0,0 +1,421 @@
+/*
+ * Driver for HSCX
+ * High-Level Serial Communcation Controller Extended
+ *
+ * Author Kai Germaschewski
+ * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ * 2001 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * based upon Karsten Keil's original isac.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+/* TODO:
+ * comments in .h
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include "hisax_hscx.h"
+
+// debugging cruft
+
+#define __debug_variable debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 1;
+MODULE_PARM(debug, "i");
+
+static char *HSCXVer[] =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("HSCX driver");
+
+#define DBG_WARN 0x0001
+#define DBG_IRQ 0x0002
+#define DBG_L1M 0x0004
+#define DBG_PR 0x0008
+#define DBG_RFIFO 0x0100
+#define DBG_RPACKET 0x0200
+#define DBG_XFIFO 0x1000
+#define DBG_XPACKET 0x2000
+
+#define HSCX_ISTA 0x20
+#define HSCX_ISTA_EXB 0x01
+#define HSCX_ISTA_EXA 0x02
+#define HSCX_ISTA_ICA 0x04
+#define HSCX_ISTA_TIN 0x08
+#define HSCX_ISTA_XPR 0x10
+#define HSCX_ISTA_RSC 0x20
+#define HSCX_ISTA_RPF 0x40
+#define HSCX_ISTA_RME 0x80
+
+#define HSCX_CMDR 0x21
+#define HSCX_CMDR_RMC 0x80
+#define HSCX_CMDR_RHR 0x40
+#define HSCX_CMDR_RNR 0x20
+#define HSCX_CMDR_STI 0x10
+#define HSCX_CMDR_XTF 0x08
+#define HSCX_CMDR_XIF 0x04
+#define HSCX_CMDR_XME 0x02
+#define HSCX_CMDR_XRES 0x01
+
+#define HSCX_EXIR 0x24
+#define HSCX_EXIR_XDU 0x40
+
+#define HSCX_RSTA 0x27
+#define HSCX_RSTA_VFR 0x80
+#define HSCX_RSTA_RDO 0x40
+#define HSCX_RSTA_CRC 0x20
+#define HSCX_RSTA_RAB 0x10
+
+#define HSCX_CCR1 0x2f
+#define HSCX_CCR2 0x2c
+#define HSCX_TSAR 0x31
+#define HSCX_TSAX 0x30
+#define HSCX_XCCR 0x32
+#define HSCX_RCCR 0x33
+#define HSCX_MODE 0x22
+
+#define HSCX_XAD1 0x24
+#define HSCX_XAD2 0x25
+#define HSCX_RAH2 0x27
+#define HSCX_TIMR 0x23
+#define HSCX_STAR 0x21
+#define HSCX_RBCL 0x25
+#define HSCX_XBCH 0x2d
+#define HSCX_VSTR 0x2e
+#define HSCX_RLCR 0x2e
+#define HSCX_MASK 0x20
+
+static inline void B_L1L2(struct hscx *hscx, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) &hscx->b_if;
+
+ DBG(0x10, "pr %#x", pr);
+ ifc->l1l2(ifc, pr, arg);
+}
+
+static void hscx_version(struct hscx *hscx)
+{
+ int val;
+
+ val = hscx->read_hscx(hscx, HSCX_VSTR) & 0xf;
+ DBG(1, "HSCX version (%x): %s", val, HSCXVer[val]);
+}
+
+static void hscx_empty_fifo(struct hscx *hscx, int count)
+{
+ u_char *ptr;
+
+ DBG(DBG_IRQ, "count %d", count);
+
+ if ((hscx->rcvidx + count) >= HSCX_BUFMAX) {
+ DBG(DBG_WARN, "overrun %d", hscx->rcvidx + count);
+ hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
+ hscx->rcvidx = 0;
+ return;
+ }
+ ptr = hscx->rcvbuf + hscx->rcvidx;
+ hscx->rcvidx += count;
+ hscx->read_hscx_fifo(hscx, ptr, count);
+ hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
+ DBG_PACKET(DBG_RFIFO, ptr, count);
+}
+
+static void hscx_fill_fifo(struct hscx *hscx)
+{
+ int count;
+ unsigned char cmd;
+ int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
+ unsigned char *ptr;
+
+ if (!hscx->tx_skb)
+ BUG();
+
+ count = hscx->tx_skb->len;
+ if (count <= 0)
+ BUG();
+
+ DBG(DBG_IRQ, "count %d", count);
+
+ if (count > fifo_size || hscx->mode == L1_MODE_TRANS) {
+ count = fifo_size;
+ cmd = 0x8;
+ } else {
+ cmd = 0xa;
+ }
+
+ ptr = hscx->tx_skb->data;
+ skb_pull(hscx->tx_skb, count);
+ hscx->tx_cnt += count;
+ DBG_PACKET(DBG_XFIFO, ptr, count);
+ hscx->write_hscx_fifo(hscx, ptr, count);
+ hscx->write_hscx(hscx, HSCX_CMDR, cmd);
+}
+
+static void hscx_retransmit(struct hscx *hscx)
+{
+ if (!hscx->tx_skb) {
+ DBG(DBG_WARN, "no skb");
+ return;
+ }
+ skb_push(hscx->tx_skb, hscx->tx_cnt);
+ hscx->tx_cnt = 0;
+ hscx->write_hscx(hscx, HSCX_CMDR, 0x01);
+}
+
+static inline void hscx_rme_interrupt(struct hscx *hscx)
+{
+ unsigned char val;
+ int count;
+ struct sk_buff *skb;
+ int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
+
+ val = hscx->read_hscx(hscx, HSCX_RSTA);
+ if ((val & (HSCX_RSTA_VFR | HSCX_RSTA_RDO | HSCX_RSTA_CRC | HSCX_RSTA_RAB) )
+ != (HSCX_RSTA_VFR | HSCX_RSTA_CRC)) {
+ DBG(DBG_WARN, "RSTA %#x, dropped", val);
+ hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
+ goto out;
+ }
+
+ count = hscx->read_hscx(hscx, HSCX_RBCL) & (fifo_size-1);
+ DBG(DBG_IRQ, "RBCL %#x", count);
+ if (count == 0)
+ count = fifo_size;
+
+ hscx_empty_fifo(hscx, count);
+
+ count = hscx->rcvidx;
+ if (count < 1) {
+ DBG(DBG_WARN, "count %d < 1", count);
+ goto out;
+ }
+
+ skb = alloc_skb(count, GFP_ATOMIC);
+ if (!skb) {
+ DBG(DBG_WARN, "no memory, dropping\n");
+ goto out;
+ }
+ memcpy(skb_put(skb, count), hscx->rcvbuf, count);
+ DBG_SKB(DBG_RPACKET, skb);
+ B_L1L2(hscx, PH_DATA | INDICATION, skb);
+ out:
+ hscx->rcvidx = 0;
+}
+
+static inline void hscx_xpr_interrupt(struct hscx *hscx)
+{
+ struct sk_buff *skb;
+
+ skb = hscx->tx_skb;
+ if (!skb)
+ return;
+
+ if (skb->len > 0) {
+ hscx_fill_fifo(hscx);
+ return;
+ }
+ hscx->tx_cnt = 0;
+ hscx->tx_skb = NULL;
+ B_L1L2(hscx, PH_DATA | CONFIRM, (void *) skb->truesize);
+ dev_kfree_skb_irq(skb);
+}
+
+static inline void hscx_exi_interrupt(struct hscx *hscx)
+{
+ unsigned char val;
+
+ val = hscx->read_hscx(hscx, HSCX_EXIR);
+ DBG(2, "EXIR %#x", val);
+
+ if (val & HSCX_EXIR_XDU) {
+ DBG(DBG_WARN, "HSCX XDU");
+ if (hscx->mode == L1_MODE_TRANS) {
+ hscx_fill_fifo(hscx);
+ } else {
+ hscx_retransmit(hscx);
+ }
+ }
+}
+
+static void hscx_reg_interrupt(struct hscx *hscx, unsigned char val)
+{
+ struct sk_buff *skb;
+
+ if (val & HSCX_ISTA_XPR) {
+ DBG(DBG_IRQ, "XPR");
+ hscx_xpr_interrupt(hscx);
+ }
+ if (val & HSCX_ISTA_RME) {
+ DBG(DBG_IRQ, "RME");
+ hscx_rme_interrupt(hscx);
+ }
+ if (val & HSCX_ISTA_RPF) {
+ int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
+
+ DBG(DBG_IRQ, "RPF");
+ hscx_empty_fifo(hscx, fifo_size);
+ if (hscx->mode == L1_MODE_TRANS) {
+ skb = dev_alloc_skb(fifo_size);
+ if (!skb) {
+ DBG(DBG_WARN, "no memory, dropping\n");
+ goto out;
+ }
+ memcpy(skb_put(skb, fifo_size), hscx->rcvbuf, fifo_size);
+ DBG_SKB(DBG_RPACKET, skb);
+ B_L1L2(hscx, PH_DATA | INDICATION, skb);
+ out:
+ hscx->rcvidx = 0;
+ }
+ }
+}
+
+void hscx_irq(struct hscx *hscx_a)
+{
+ struct hscx *hscx_b = hscx_a + 1;
+ unsigned char val;
+
+ val = hscx_b->read_hscx(hscx_b, HSCX_ISTA);
+ DBG(DBG_IRQ, "ISTA B %#x", val);
+
+ if (val & HSCX_ISTA_EXB) {
+ DBG(DBG_IRQ, "EXI B");
+ hscx_exi_interrupt(hscx_b);
+ }
+ if (val & HSCX_ISTA_EXA) {
+ DBG(DBG_IRQ, "EXI A");
+ hscx_exi_interrupt(hscx_a);
+ }
+ if (val & 0xf8) {
+ hscx_reg_interrupt(hscx_b, val);
+ }
+ if (val & HSCX_ISTA_ICA) {
+ val = hscx_a->read_hscx(hscx_a, HSCX_ISTA);
+ DBG(DBG_IRQ, "ISTA A %#x", val);
+ hscx_reg_interrupt(hscx_a, val);
+ hscx_a->write_hscx(hscx_a, HSCX_MASK, 0xff);
+ hscx_a->write_hscx(hscx_a, HSCX_MASK, 0x00);
+ }
+ hscx_b->write_hscx(hscx_b, HSCX_MASK, 0xff);
+ hscx_b->write_hscx(hscx_b, HSCX_MASK, 0x00);
+}
+
+static void modehscx(struct hscx *hscx, int mode)
+{
+ int bc = hscx->channel;
+
+ DBG(0x40, "hscx %c mode %d --> %d",
+ 'A' + hscx->channel, hscx->mode, mode);
+
+ hscx->mode = mode;
+ hscx->write_hscx(hscx, HSCX_XAD1, 0xFF);
+ hscx->write_hscx(hscx, HSCX_XAD2, 0xFF);
+ hscx->write_hscx(hscx, HSCX_RAH2, 0xFF);
+ hscx->write_hscx(hscx, HSCX_XBCH, 0x0);
+ hscx->write_hscx(hscx, HSCX_RLCR, 0x0);
+ hscx->write_hscx(hscx, HSCX_CCR1,
+ test_bit(HSCX_IPAC, &hscx->flags) ? 0x82 : 0x85);
+ hscx->write_hscx(hscx, HSCX_CCR2, 0x30);
+ hscx->write_hscx(hscx, HSCX_XCCR, 7);
+ hscx->write_hscx(hscx, HSCX_RCCR, 7);
+
+ /* Switch IOM 1 SSI */
+ if (test_bit(HSCX_IOM1, &hscx->flags))
+ bc = 1;
+
+ hscx->write_hscx(hscx, HSCX_TSAX, hscx->tsaxr);
+ hscx->write_hscx(hscx, HSCX_TSAR, hscx->tsaxr);
+
+ switch (mode) {
+ case (L1_MODE_NULL):
+ hscx->write_hscx(hscx, HSCX_TSAX, 0x1f);
+ hscx->write_hscx(hscx, HSCX_TSAR, 0x1f);
+ hscx->write_hscx(hscx, HSCX_MODE, 0x84);
+ break;
+ case (L1_MODE_TRANS):
+ hscx->write_hscx(hscx, HSCX_MODE, 0xe4);
+ break;
+ case (L1_MODE_HDLC):
+ hscx->write_hscx(hscx, HSCX_CCR1, test_bit(HSCX_IPAC, &hscx->flags) ? 0x8a : 0x8d);
+ hscx->write_hscx(hscx, HSCX_MODE, 0x8c);
+ break;
+ }
+ if (mode)
+ hscx->write_hscx(hscx, HSCX_CMDR, 0x41);
+
+ hscx->write_hscx(hscx, HSCX_ISTA, 0x00);
+}
+
+void hscx_init(struct hscx *hscx)
+{
+ if (hscx->channel)
+ hscx->tsaxr = 0x03;
+ else
+ hscx->tsaxr = 0x2f;
+}
+
+void hscx_setup(struct hscx *hscx)
+{
+ hscx_version(hscx);
+ hscx->mode = -1;
+ modehscx(hscx, L1_MODE_NULL);
+}
+
+void hscx_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
+{
+ struct hscx *hscx = ifc->priv;
+ struct sk_buff *skb = arg;
+ int mode;
+
+ DBG(0x10, "pr %#x", pr);
+
+ switch (pr) {
+ case PH_DATA | REQUEST:
+ if (hscx->tx_skb)
+ BUG();
+
+ hscx->tx_skb = skb;
+ DBG_SKB(1, skb);
+ hscx_fill_fifo(hscx);
+ break;
+ case PH_ACTIVATE | REQUEST:
+ mode = (int) arg;
+ DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", hscx->channel + 1, mode);
+ modehscx(hscx, mode);
+ B_L1L2(hscx, PH_ACTIVATE | INDICATION, NULL);
+ break;
+ case PH_DEACTIVATE | REQUEST:
+ DBG(4,"B%d,PH_DEACTIVATE_REQUEST", hscx->channel + 1);
+ modehscx(hscx, L1_MODE_NULL);
+ B_L1L2(hscx, PH_DEACTIVATE | INDICATION, NULL);
+ break;
+ }
+}
+
+static int __init hisax_hscx_init(void)
+{
+ printk(KERN_INFO "hisax_hscx: HSCX ISDN driver v0.1.0\n");
+ return 0;
+}
+
+static void __exit hisax_hscx_exit(void)
+{
+}
+
+EXPORT_SYMBOL(hscx_init);
+EXPORT_SYMBOL(hscx_b_l2l1);
+
+EXPORT_SYMBOL(hscx_setup);
+EXPORT_SYMBOL(hscx_irq);
+
+module_init(hisax_hscx_init);
+module_exit(hisax_hscx_exit);
diff --git a/drivers/isdn/hisax/hisax_hscx.h b/drivers/isdn/hisax/hisax_hscx.h
new file mode 100644
index 000000000..6177a680a
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_hscx.h
@@ -0,0 +1,37 @@
+#ifndef __HISAX_HSCX_H__
+#define __HISAX_HSCX_H__
+
+#include <linux/kernel.h>
+#include "fsm.h"
+#include "hisax_if.h"
+
+#define HSCX_BUFMAX 4096
+
+#define HSCX_IOM1 0
+#define HSCX_IPAC 1
+
+struct hscx {
+ void *priv;
+ u_long flags;
+ struct hisax_b_if b_if;
+ int mode;
+ int channel;
+ u_char tsaxr;
+ struct sk_buff *tx_skb;
+ int tx_cnt;
+ u_char rcvbuf[HSCX_BUFMAX];
+ int rcvidx;
+
+ u_char (*read_hscx) (struct hscx *, u_char);
+ void (*write_hscx) (struct hscx *, u_char, u_char);
+ void (*read_hscx_fifo) (struct hscx *, u_char *, int);
+ void (*write_hscx_fifo)(struct hscx *, u_char *, int);
+};
+
+void hscx_init(struct hscx *hscx);
+void hscx_b_l2l1(struct hisax_if *hisax_b_if, int pr, void *arg);
+
+void hscx_setup(struct hscx *hscx);
+void hscx_irq(struct hscx *hscx);
+
+#endif
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
index 6a261e0be..b5cb8e3c9 100644
--- a/drivers/isdn/hisax/hscx.c
+++ b/drivers/isdn/hisax/hscx.c
@@ -134,7 +134,7 @@ hscx_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -150,7 +150,7 @@ hscx_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
modehscx(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -214,7 +214,7 @@ setstack_hscx(struct PStack *st, struct BCState *bcs)
if (open_hscxstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = hscx_l2l1;
+ st->l1.l2l1 = hscx_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index 2f2242156..e6d655574 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -89,7 +89,7 @@ icc_bh(struct IsdnCardState *cs)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+ L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
@@ -506,7 +506,7 @@ ICC_l1hw(struct PStack *st, int pr, void *arg)
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -603,7 +603,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+ L1L2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index 61a0fff42..3d6b67428 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -93,7 +93,7 @@ isac_bh(struct IsdnCardState *cs)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+ L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
@@ -510,7 +510,7 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg)
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -605,7 +605,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+ L1L2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 01986d8ed..766428ed9 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -1602,7 +1602,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -1637,7 +1637,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
debugl1(st->l1.bcs->cs, "PDAC clear BC_FLG_BUSY");
modeisar(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -1696,7 +1696,7 @@ setstack_isar(struct PStack *st, struct BCState *bcs)
if (open_isarstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = isar_l2l1;
+ st->l1.l2l1 = isar_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 35b36bb14..a191be34b 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -160,9 +160,9 @@ L1activated(struct IsdnCardState *cs)
st = cs->stlist;
while (st) {
if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
else
- st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
+ L1L2(st, PH_ACTIVATE | INDICATION, NULL);
st = st->next;
}
}
@@ -175,8 +175,8 @@ L1deactivated(struct IsdnCardState *cs)
st = cs->stlist;
while (st) {
if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
- st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL);
+ L1L2(st, PH_PAUSE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | INDICATION, NULL);
st = st->next;
}
test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
@@ -193,7 +193,7 @@ DChannel_proc_xmt(struct IsdnCardState *cs)
stptr = cs->stlist;
while (stptr != NULL)
if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
- stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
+ L1L2(stptr, PH_PULL | CONFIRM, NULL);
break;
} else
stptr = stptr->next;
@@ -235,7 +235,7 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
if (sapi == CTRL_SAPI) { /* sapi 0 */
while (stptr != NULL) {
if ((nskb = skb_clone(skb, GFP_ATOMIC)))
- stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
+ L1L2(stptr, PH_DATA | INDICATION, nskb);
else
printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
stptr = stptr->next;
@@ -254,7 +254,7 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
found = 0;
while (stptr != NULL)
if (tei == stptr->l2.tei) {
- stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
+ L1L2(stptr, PH_DATA | INDICATION, skb);
found = !0;
break;
} else
@@ -277,10 +277,10 @@ BChannel_proc_xmt(struct BCState *bcs)
}
if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
- st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L2L1(st, PH_DEACTIVATE | CONFIRM, NULL);
}
}
}
@@ -295,7 +295,7 @@ BChannel_proc_rcv(struct BCState *bcs)
FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
}
while ((skb = skb_dequeue(&bcs->rqueue))) {
- bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
+ L1L2(bcs->st, PH_DATA | INDICATION, skb);
}
}
@@ -717,7 +717,7 @@ l1b_timer_act(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_ACTIV);
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
}
static void
@@ -726,7 +726,7 @@ l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_NULL);
- st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L2L1(st, PH_DEACTIVATE | CONFIRM, NULL);
}
static struct FsmNode L1BFnList[] __initdata =
@@ -801,7 +801,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg)
debugl1(cs, "PH_ACTIVATE_REQ %s",
st->l1.l1m.fsm->strState[st->l1.l1m.state]);
if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
else {
test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
@@ -897,7 +897,7 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
setstack_tei(st);
setstack_manager(st);
st->l1.stlistp = &(cs->stlist);
- st->l2.l2l1 = dch_l2l1;
+ st->l1.l2l1 = dch_l2l1;
if (cs->setstack_d)
cs->setstack_d(st, cs);
}
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 4b2a31196..fb593d1f5 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -27,14 +27,14 @@ static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
static struct Fsm l2fsm;
enum {
- ST_L2_1,
- ST_L2_2,
- ST_L2_3,
- ST_L2_4,
- ST_L2_5,
- ST_L2_6,
- ST_L2_7,
- ST_L2_8,
+ ST_L2_1, /* TEI unassigned */
+ ST_L2_2, /* Assign awaiting TEI */
+ ST_L2_3, /* Establish awaiting TEI */
+ ST_L2_4, /* TEI assigned */
+ ST_L2_5, /* Awaiting establishment */
+ ST_L2_6, /* Awaiting release */
+ ST_L2_7, /* Multiple frame established */
+ ST_L2_8, /* Timer recovery */
};
#define L2_STATE_COUNT (ST_L2_8+1)
@@ -219,7 +219,7 @@ enqueue_super(struct PStack *st,
{
if (test_bit(FLG_LAPB, &st->l2.flag))
st->l1.bcs->tx_cnt += skb->len;
- st->l2.l2l1(st, PH_DATA | REQUEST, skb);
+ L2L1(st, PH_DATA | REQUEST, skb);
}
#define enqueue_ui(a, b) enqueue_super(a, b)
@@ -494,15 +494,15 @@ st5_dl_release_l2l3(struct PStack *st)
else
pr = DL_RELEASE | INDICATION;
- st->l2.l2l3(st, pr, NULL);
+ L2L3(st, pr, NULL);
}
inline void
lapb_dl_release_l2l3(struct PStack *st, int f)
{
if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | f, NULL);
+ L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
+ L2L3(st, DL_RELEASE | f, NULL);
}
static void
@@ -631,7 +631,7 @@ l2_got_ui(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb = arg;
skb_pull(skb, l2headersize(&st->l2, 1));
- st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
+ L2L3(st, DL_UNIT_DATA | INDICATION, skb);
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* in states 1-3 for broadcast
*/
@@ -673,7 +673,7 @@ l2_release(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+ L2L3(st, DL_RELEASE | CONFIRM, NULL);
}
static void
@@ -714,7 +714,7 @@ l2_start_multi(struct FsmInst *fi, int event, void *arg)
FsmChangeState(fi, ST_L2_7);
FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
- st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
+ L2L3(st, DL_ESTABLISH | INDICATION, NULL);
}
static void
@@ -763,11 +763,11 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg)
FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
if (est)
- st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
+ L2L3(st, DL_ESTABLISH | INDICATION, NULL);
if ((ST_L2_7==state) || (ST_L2_8 == state))
if (skb_queue_len(&st->l2.i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
}
static void
@@ -820,10 +820,10 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
if (pr != -1)
- st->l2.l2l3(st, pr, NULL);
+ L2L3(st, pr, NULL);
if (skb_queue_len(&st->l2.i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
}
static void
@@ -866,7 +866,7 @@ l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
if (!test_bit(FLG_L3_INIT, &st->l2.flag))
skb_queue_purge(&st->l2.i_queue);
if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+ L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
st5_dl_release_l2l3(st);
FsmChangeState(fi, ST_L2_4);
}
@@ -962,7 +962,7 @@ invoke_retransmission(struct PStack *st, unsigned int nr)
skb_queue_head(&l2->i_queue, l2->windowar[p1]);
l2->windowar[p1] = NULL;
}
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
}
}
@@ -1022,7 +1022,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
restart_t200(st, 12);
}
if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
} else
nrerrorrecovery(fi);
}
@@ -1050,7 +1050,7 @@ l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
if (test_bit(FLG_LAPB, &st->l2.flag))
st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
skb_queue_tail(&st->l2.i_queue, skb);
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
}
static void
@@ -1099,7 +1099,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
else
test_and_set_bit(FLG_ACK_PEND, &l2->flag);
skb_pull(skb, l2headersize(l2, 0));
- st->l2.l2l3(st, DL_DATA | INDICATION, skb);
+ L2L3(st, DL_DATA | INDICATION, skb);
} else {
/* n(s)!=v(r) */
FreeSkb(skb);
@@ -1128,7 +1128,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
}
if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
enquiry_cr(st, RR, RSP, 0);
}
@@ -1163,7 +1163,7 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
skb_queue_purge(&st->l2.i_queue);
st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+ L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
st5_dl_release_l2l3(st);
} else {
st->l2.rc++;
@@ -1304,14 +1304,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
FreeSkb(oskb);
}
- st->l2.l2l1(st, PH_PULL | INDICATION, skb);
+ L2L1(st, PH_PULL | INDICATION, skb);
test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
FsmDelTimer(&st->l2.t203, 13);
FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
}
if (skb_queue_len(&l2->i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
}
static void
@@ -1357,7 +1357,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
invoke_retransmission(st, nr);
FsmChangeState(fi, ST_L2_7);
if (skb_queue_len(&l2->i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+ L2L1(st, PH_PULL | REQUEST, NULL);
} else
nrerrorrecovery(fi);
} else {
@@ -1404,7 +1404,7 @@ l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
skb_queue_purge(&st->l2.ui_queue);
st->l2.tei = -1;
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ L2L3(st, DL_RELEASE | INDICATION, NULL);
FsmChangeState(fi, ST_L2_1);
}
@@ -1430,7 +1430,7 @@ l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
skb_queue_purge(&st->l2.ui_queue);
st->l2.tei = -1;
stop_t200(st, 18);
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+ L2L3(st, DL_RELEASE | CONFIRM, NULL);
FsmChangeState(fi, ST_L2_1);
}
@@ -1445,7 +1445,7 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg)
st->l2.tei = -1;
stop_t200(st, 17);
FsmDelTimer(&st->l2.t203, 19);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ L2L3(st, DL_RELEASE | INDICATION, NULL);
FsmChangeState(fi, ST_L2_1);
}
@@ -1457,7 +1457,7 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
skb_queue_purge(&st->l2.i_queue);
skb_queue_purge(&st->l2.ui_queue);
if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ L2L3(st, DL_RELEASE | INDICATION, NULL);
}
static void
@@ -1480,7 +1480,7 @@ l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
skb_queue_purge(&st->l2.ui_queue);
stop_t200(st, 20);
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+ L2L3(st, DL_RELEASE | CONFIRM, NULL);
FsmChangeState(fi, ST_L2_4);
}
@@ -1494,7 +1494,7 @@ l2_persistant_da(struct FsmInst *fi, int event, void *arg)
freewin(st);
stop_t200(st, 19);
FsmDelTimer(&st->l2.t203, 19);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ L2L3(st, DL_RELEASE | INDICATION, NULL);
FsmChangeState(fi, ST_L2_4);
}
@@ -1739,12 +1739,12 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg)
test_bit(FLG_ORIG, &st->l2.flag)) {
test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
}
- st->l2.l2l1(st, PH_ACTIVATE, NULL);
+ L2L1(st, PH_ACTIVATE, NULL);
}
break;
case (DL_RELEASE | REQUEST):
if (test_bit(FLG_LAPB, &st->l2.flag)) {
- st->l2.l2l1(st, PH_DEACTIVATE, NULL);
+ L2L1(st, PH_DEACTIVATE, NULL);
}
FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg);
break;
@@ -1784,8 +1784,8 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...)
void
setstack_isdnl2(struct PStack *st, char *debug_id)
{
- st->l1.l1l2 = isdnl2_l1l2;
- st->l3.l3l2 = isdnl2_l3l2;
+ st->l2.l1l2 = isdnl2_l1l2;
+ st->l2.l3l2 = isdnl2_l3l2;
skb_queue_head_init(&st->l2.i_queue);
skb_queue_head_init(&st->l2.ui_queue);
@@ -1813,13 +1813,13 @@ transl2_l3l2(struct PStack *st, int pr, void *arg)
switch (pr) {
case (DL_DATA | REQUEST):
case (DL_UNIT_DATA | REQUEST):
- st->l2.l2l1(st, PH_DATA | REQUEST, arg);
+ L2L1(st, PH_DATA | REQUEST, arg);
break;
case (DL_ESTABLISH | REQUEST):
- st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+ L2L1(st, PH_ACTIVATE | REQUEST, NULL);
break;
case (DL_RELEASE | REQUEST):
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+ L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
break;
}
}
@@ -1827,7 +1827,7 @@ transl2_l3l2(struct PStack *st, int pr, void *arg)
void
setstack_transl2(struct PStack *st)
{
- st->l3.l3l2 = transl2_l3l2;
+ st->l2.l3l2 = transl2_l3l2;
}
void
diff --git a/drivers/isdn/hisax/isdnl2.h b/drivers/isdn/hisax/isdnl2.h
index 7e447fb8e..0cdab1b73 100644
--- a/drivers/isdn/hisax/isdnl2.h
+++ b/drivers/isdn/hisax/isdnl2.h
@@ -23,3 +23,4 @@
#define RSP 1
#define LC_FLUSH_WAIT 1
+
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index 02d23b8b7..4eccc8380 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -163,7 +163,7 @@ newl3state(struct l3_process *pc, int state)
static void
L3ExpireTimer(struct L3Timer *t)
{
- t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
+ t->pc->st->l3.l4l3(t->pc->st, t->event, t->pc);
}
void
@@ -355,7 +355,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
st->l3.l3m.printdebug = l3m_debug;
FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
strcpy(st->l3.debug_id, "L3DC ");
- st->lli.l4l3_proto = no_l3_proto_spec;
+ st->l3.l4l3_proto = no_l3_proto_spec;
#ifdef CONFIG_HISAX_EURO
if (st->protocol == ISDN_PTYPE_EURO) {
@@ -373,13 +373,13 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
} else
#endif
if (st->protocol == ISDN_PTYPE_LEASED) {
- st->lli.l4l3 = no_l3_proto;
- st->l2.l2l3 = no_l3_proto;
+ st->l3.l4l3 = no_l3_proto;
+ st->l3.l2l3 = no_l3_proto;
st->l3.l3ml3 = no_l3_proto;
printk(KERN_INFO "HiSax: Leased line mode\n");
} else {
- st->lli.l4l3 = no_l3_proto;
- st->l2.l2l3 = no_l3_proto;
+ st->l3.l4l3 = no_l3_proto;
+ st->l3.l2l3 = no_l3_proto;
st->l3.l3ml3 = no_l3_proto;
sprintf(tmp, "protocol %s not supported",
(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
@@ -393,7 +393,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
void
isdnl3_trans(struct PStack *st, int pr, void *arg) {
- st->l3.l3l2(st, pr, arg);
+ L3L2(st, pr, arg);
}
void
@@ -424,7 +424,7 @@ setstack_l3bc(struct PStack *st, struct Channel *chanp)
st->l3.l3m.userint = 0;
st->l3.l3m.printdebug = l3m_debug;
strcpy(st->l3.debug_id, "L3BC ");
- st->lli.l4l3 = isdnl3_trans;
+ st->l3.l4l3 = isdnl3_trans;
}
#define DREL_TIMER_VALUE 40000
@@ -435,7 +435,7 @@ lc_activate(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
- st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
+ L3L2(st, DL_ESTABLISH | REQUEST, NULL);
}
static void
@@ -447,7 +447,7 @@ lc_connect(struct FsmInst *fi, int event, void *arg)
FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&st->l3.squeue))) {
- st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+ L3L2(st, DL_DATA | REQUEST, skb);
dequeued++;
}
if ((!st->l3.proc) && dequeued) {
@@ -468,7 +468,7 @@ lc_connected(struct FsmInst *fi, int event, void *arg)
FsmDelTimer(&st->l3.l3m_timer, 51);
FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&st->l3.squeue))) {
- st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+ L3L2(st, DL_DATA | REQUEST, skb);
dequeued++;
}
if ((!st->l3.proc) && dequeued) {
@@ -512,7 +512,7 @@ lc_release_req(struct FsmInst *fi, int event, void *arg)
FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
} else {
FsmChangeState(fi, ST_L3_LC_REL_WAIT);
- st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+ L3L2(st, DL_RELEASE | REQUEST, NULL);
}
}
@@ -565,7 +565,7 @@ l3_msg(struct PStack *st, int pr, void *arg)
switch (pr) {
case (DL_DATA | REQUEST):
if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
- st->l3.l3l2(st, pr, arg);
+ L3L2(st, pr, arg);
} else {
struct sk_buff *skb = arg;
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index d866dd277..41b109ea7 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -177,7 +177,7 @@ jade_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -193,7 +193,7 @@ jade_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
modejade(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -258,7 +258,7 @@ setstack_jade(struct PStack *st, struct BCState *bcs)
if (open_jadestate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = jade_l2l1;
+ st->l1.l2l1 = jade_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index 4cb998d27..93fb3e94e 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -223,7 +223,7 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
l3_debug(pc->st, tmp);
}
newl3state(pc, 6);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+ L3L4(pc->st, CC_SETUP | INDICATION, pc);
} else
release_l3_process(pc);
}
@@ -253,7 +253,7 @@ l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
}
dev_kfree_skb(skb);
L3AddTimer(&pc->timer, T304, CC_T304);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
static void
@@ -285,7 +285,7 @@ l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
dev_kfree_skb(skb);
L3AddTimer(&pc->timer, T310, CC_T310);
newl3state(pc, 3);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+ L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
}
static void
@@ -296,7 +296,7 @@ l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
dev_kfree_skb(skb);
L3DelTimer(&pc->timer); /* T304 */
newl3state(pc, 4);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+ L3L4(pc->st, CC_ALERTING | INDICATION, pc);
}
static void
@@ -316,7 +316,7 @@ l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
}
if (tmpcharge > pc->para.chargeinfo) {
pc->para.chargeinfo = tmpcharge;
- pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
+ L3L4(pc->st, CC_CHARGE | INDICATION, pc);
}
if (pc->st->l3.debug & L3_DEB_CHARGE) {
sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -349,7 +349,7 @@ l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 10);
dev_kfree_skb(skb);
pc->para.chargeinfo = 0;
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+ L3L4(pc->st, CC_SETUP | CONFIRM, pc);
}
static void
@@ -379,7 +379,7 @@ l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
StopAllL3Timer(pc);
newl3state(pc, 0);
l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
@@ -392,7 +392,7 @@ l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
StopAllL3Timer(pc);
newl3state(pc, 0);
pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+ L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
release_l3_process(pc);
}
@@ -414,7 +414,7 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
}
if (tmpcharge > pc->para.chargeinfo) {
pc->para.chargeinfo = tmpcharge;
- pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
+ L3L4(pc->st, CC_CHARGE | INDICATION, pc);
}
if (pc->st->l3.debug & L3_DEB_CHARGE) {
sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -447,7 +447,7 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
}
dev_kfree_skb(skb);
newl3state(pc, 12);
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+ L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
}
@@ -464,7 +464,7 @@ l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 10);
pc->para.chargeinfo = 0;
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+ L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
}
static void
@@ -573,7 +573,7 @@ l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 0xE6;
l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -618,7 +618,7 @@ l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 0xE6;
l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -627,7 +627,7 @@ l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 0xE6;
l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+ L3L4(pc->st, CC_CONNECT_ERR, pc);
}
static void
@@ -643,7 +643,7 @@ static void
l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+ L3L4(pc->st, CC_RELEASE_ERR, pc);
release_l3_process(pc);
}
@@ -652,7 +652,7 @@ l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
{
pc->para.cause = CAUSE_LocalProcErr;
l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -661,7 +661,7 @@ l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
@@ -946,8 +946,8 @@ setstack_1tr6(struct PStack *st)
{
char tmp[64];
- st->lli.l4l3 = down1tr6;
- st->l2.l2l3 = up1tr6;
+ st->l3.l4l3 = down1tr6;
+ st->l3.l2l3 = up1tr6;
st->l3.l3ml3 = man1tr6;
st->l3.N303 = 0;
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 2f13dd3cf..8d84776e7 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -449,7 +449,7 @@ l3dss1_parse_facility(struct PStack *st, struct l3_process *pc,
pc->prot.dss1.remote_result = 0; /* success */
pc->prot.dss1.invoke_id = 0;
pc->redir_result = pc->prot.dss1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
+ L3L4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
else
l3_debug(st,"return error unknown identifier");
break;
@@ -494,7 +494,7 @@ l3dss1_parse_facility(struct PStack *st, struct l3_process *pc,
pc->prot.dss1.remote_result = err_ret; /* result */
pc->prot.dss1.invoke_id = 0;
pc->redir_result = pc->prot.dss1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
+ L3L4(st, CC_REDIR | INDICATION, pc);
} /* Deflection error */
else
l3_debug(st,"return result unknown identifier");
@@ -983,7 +983,7 @@ l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
pc->para.cause = NO_CAUSE;
StopAllL3Timer(pc);
newl3state(pc, 0);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+ L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
dss1_release_l3_process(pc);
}
@@ -1473,7 +1473,7 @@ l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
L3AddTimer(&pc->timer, T310, CC_T310);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+ L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
}
static void
@@ -1512,7 +1512,7 @@ l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
L3AddTimer(&pc->timer, T304, CC_T304);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
static void
@@ -1544,7 +1544,7 @@ l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
if (cause)
newl3state(pc, 19);
if (11 != ret)
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+ L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
else if (!cause)
l3dss1_release_req(pc, pr, NULL);
if (cause) {
@@ -1570,7 +1570,7 @@ l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
/* here should inserted COLP handling KKe */
if (ret)
l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+ L3L4(pc->st, CC_SETUP | CONFIRM, pc);
}
static void
@@ -1588,7 +1588,7 @@ l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 4);
if (ret)
l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+ L3L4(pc->st, CC_ALERTING | INDICATION, pc);
}
static void
@@ -1754,7 +1754,7 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 6);
if (err) /* STATUS for none mandatory IE errors after actions are taken */
l3dss1_std_ie_err(pc, err);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+ L3L4(pc->st, CC_SETUP | INDICATION, pc);
}
static void
@@ -1833,7 +1833,7 @@ l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
if (ret)
l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+ L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
}
static void
@@ -1860,7 +1860,7 @@ l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
return;
memcpy(skb_put(skb, l), tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
dss1_release_l3_process(pc);
}
@@ -1894,7 +1894,7 @@ l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
else
l3dss1_message(pc, MT_RELEASE_COMPLETE);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
dss1_release_l3_process(pc);
}
@@ -1916,7 +1916,7 @@ l3dss1_proceed_req(struct l3_process *pc, u_char pr,
{
newl3state(pc, 9);
l3dss1_message(pc, MT_CALL_PROCEEDING);
- pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
+ L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
}
static void
@@ -2009,7 +2009,7 @@ l3dss1_progress(struct l3_process *pc, u_char pr, void *arg)
if (err)
l3dss1_std_ie_err(pc, err);
if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+ L3L4(pc->st, CC_PROGRESS | INDICATION, pc);
}
static void
@@ -2050,7 +2050,7 @@ l3dss1_notify(struct l3_process *pc, u_char pr, void *arg)
if (err)
l3dss1_std_ie_err(pc, err);
if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
+ L3L4(pc->st, CC_NOTIFY | INDICATION, pc);
}
static void
@@ -2082,7 +2082,7 @@ l3dss1_information(struct l3_process *pc, u_char pr, void *arg)
if ((p = findie(p, skb->len, 0x70, 0))) {
iecpy(tmp, p, 1);
strcat(pc->para.setup.eazmsn, tmp);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
L3AddTimer(&pc->timer, T302, CC_T302);
}
@@ -2297,11 +2297,11 @@ l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
* set down layer 3 without sending any message
*/
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
dss1_release_l3_process(pc);
} else {
- pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+ L3L4(pc->st, CC_IGNORE | INDICATION, pc);
}
}
@@ -2317,7 +2317,7 @@ l3dss1_t302(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 28; /* invalid number */
l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -2330,7 +2330,7 @@ l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
} else {
L3DelTimer(&pc->timer);
l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
- pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+ L3L4(pc->st, CC_NOSETUP_RSP, pc);
dss1_release_l3_process(pc);
}
}
@@ -2342,7 +2342,7 @@ l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
@@ -2382,7 +2382,7 @@ l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -2392,7 +2392,7 @@ l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+ L3L4(pc->st, CC_CONNECT_ERR, pc);
}
static void
@@ -2408,7 +2408,7 @@ static void
l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+ L3L4(pc->st, CC_RELEASE_ERR, pc);
dss1_release_l3_process(pc);
}
@@ -2418,7 +2418,7 @@ l3dss1_t318(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 102; /* Timer expiry */
pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+ L3L4(pc->st, CC_RESUME_ERR, pc);
newl3state(pc, 19);
l3dss1_message(pc, MT_RELEASE);
L3AddTimer(&pc->timer, T308, CC_T308_1);
@@ -2430,7 +2430,7 @@ l3dss1_t319(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 102; /* Timer expiry */
pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+ L3L4(pc->st, CC_SUSPEND_ERR, pc);
newl3state(pc, 10);
}
@@ -2438,7 +2438,7 @@ static void
l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
dss1_release_l3_process(pc);
}
@@ -2494,7 +2494,7 @@ l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
* if received MT_STATUS with cause == 111 and call
* state == 0, then we must set down layer 3
*/
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
dss1_release_l3_process(pc);
}
@@ -2553,7 +2553,7 @@ l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
newl3state(pc, 0);
pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+ L3L4(pc->st, CC_SUSPEND | CONFIRM, pc);
/* We don't handle suspend_ack for IE errors now */
if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
if (pc->debug & L3_DEB_WARN)
@@ -2583,7 +2583,7 @@ l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
return;
}
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+ L3L4(pc->st, CC_SUSPEND_ERR, pc);
newl3state(pc, 10);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3dss1_std_ie_err(pc, ret);
@@ -2647,7 +2647,7 @@ l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
return;
}
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+ L3L4(pc->st, CC_RESUME | CONFIRM, pc);
newl3state(pc, 10);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3dss1_std_ie_err(pc, ret);
@@ -2675,7 +2675,7 @@ l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
return;
}
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+ L3L4(pc->st, CC_RESUME_ERR, pc);
newl3state(pc, 0);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3dss1_std_ie_err(pc, ret);
@@ -2713,9 +2713,9 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
up = pc->st->l3.proc;
while (up) {
if ((ri & 7) == 7)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+ L4L3(up->st, CC_RESTART | REQUEST, up);
else if (up->para.bchannel == chan)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+ L4L3(up->st, CC_RESTART | REQUEST, up);
up = up->next;
}
p = tmp;
@@ -2742,7 +2742,7 @@ l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
pc->para.cause = 0x29; /* Temporary failure */
pc->para.loc = 0;
l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -2751,7 +2751,7 @@ l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
@@ -3219,9 +3219,9 @@ setstack_dss1(struct PStack *st)
char tmp[64];
int i;
- st->lli.l4l3 = dss1down;
- st->lli.l4l3_proto = l3dss1_cmd_global;
- st->l2.l2l3 = dss1up;
+ st->l3.l4l3 = dss1down;
+ st->l3.l4l3_proto = l3dss1_cmd_global;
+ st->l3.l2l3 = dss1up;
st->l3.l3ml3 = dss1man;
st->l3.N303 = 1;
st->prot.dss1.last_invoke_id = 0;
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
index 8811f3ca1..a1e99dee8 100644
--- a/drivers/isdn/hisax/l3ni1.c
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -377,7 +377,7 @@ l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
pc->prot.ni1.remote_result = 0; /* success */
pc->prot.ni1.invoke_id = 0;
pc->redir_result = pc->prot.ni1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
+ L3L4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
else
l3_debug(st,"return error unknown identifier");
break;
@@ -422,7 +422,7 @@ l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
pc->prot.ni1.remote_result = err_ret; /* result */
pc->prot.ni1.invoke_id = 0;
pc->redir_result = pc->prot.ni1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
+ L3L4(st, CC_REDIR | INDICATION, pc);
} /* Deflection error */
else
l3_debug(st,"return result unknown identifier");
@@ -932,7 +932,7 @@ l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
pc->para.cause = NO_CAUSE;
StopAllL3Timer(pc);
newl3state(pc, 0);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+ L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
ni1_release_l3_process(pc);
}
@@ -1326,7 +1326,7 @@ l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
L3AddTimer(&pc->timer, T310, CC_T310);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+ L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
}
static void
@@ -1365,7 +1365,7 @@ l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
L3AddTimer(&pc->timer, T304, CC_T304);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
static void
@@ -1397,7 +1397,7 @@ l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
if (cause)
newl3state(pc, 19);
if (11 != ret)
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+ L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
else if (!cause)
l3ni1_release_req(pc, pr, NULL);
if (cause) {
@@ -1423,7 +1423,7 @@ l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
/* here should inserted COLP handling KKe */
if (ret)
l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+ L3L4(pc->st, CC_SETUP | CONFIRM, pc);
}
static void
@@ -1441,7 +1441,7 @@ l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 4);
if (ret)
l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+ L3L4(pc->st, CC_ALERTING | INDICATION, pc);
}
static void
@@ -1607,7 +1607,7 @@ l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 6);
if (err) /* STATUS for none mandatory IE errors after actions are taken */
l3ni1_std_ie_err(pc, err);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+ L3L4(pc->st, CC_SETUP | INDICATION, pc);
}
static void
@@ -1688,7 +1688,7 @@ l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
if (ret)
l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+ L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
}
static void
@@ -1715,7 +1715,7 @@ l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
return;
memcpy(skb_put(skb, l), tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
ni1_release_l3_process(pc);
}
@@ -1749,7 +1749,7 @@ l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
else
l3ni1_message(pc, MT_RELEASE_COMPLETE);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
ni1_release_l3_process(pc);
}
@@ -1771,7 +1771,7 @@ l3ni1_proceed_req(struct l3_process *pc, u_char pr,
{
newl3state(pc, 9);
l3ni1_message(pc, MT_CALL_PROCEEDING);
- pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
+ L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
}
static void
@@ -1864,7 +1864,7 @@ l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
if (err)
l3ni1_std_ie_err(pc, err);
if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+ L3L4(pc->st, CC_PROGRESS | INDICATION, pc);
}
static void
@@ -1905,7 +1905,7 @@ l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
if (err)
l3ni1_std_ie_err(pc, err);
if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
+ L3L4(pc->st, CC_NOTIFY | INDICATION, pc);
}
static void
@@ -1937,7 +1937,7 @@ l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
if ((p = findie(p, skb->len, 0x70, 0))) {
iecpy(tmp, p, 1);
strcat(pc->para.setup.eazmsn, tmp);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
L3AddTimer(&pc->timer, T302, CC_T302);
}
@@ -2152,11 +2152,11 @@ l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
* set down layer 3 without sending any message
*/
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
ni1_release_l3_process(pc);
} else {
- pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+ L3L4(pc->st, CC_IGNORE | INDICATION, pc);
}
}
@@ -2172,7 +2172,7 @@ l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 28; /* invalid number */
l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -2185,7 +2185,7 @@ l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
} else {
L3DelTimer(&pc->timer);
l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
- pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+ L3L4(pc->st, CC_NOSETUP_RSP, pc);
ni1_release_l3_process(pc);
}
}
@@ -2197,7 +2197,7 @@ l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 102;
l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
@@ -2237,7 +2237,7 @@ l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 102;
l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -2247,7 +2247,7 @@ l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
pc->para.cause = 102;
l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+ L3L4(pc->st, CC_CONNECT_ERR, pc);
}
static void
@@ -2263,7 +2263,7 @@ static void
l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+ L3L4(pc->st, CC_RELEASE_ERR, pc);
ni1_release_l3_process(pc);
}
@@ -2273,7 +2273,7 @@ l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 102; /* Timer expiry */
pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+ L3L4(pc->st, CC_RESUME_ERR, pc);
newl3state(pc, 19);
l3ni1_message(pc, MT_RELEASE);
L3AddTimer(&pc->timer, T308, CC_T308_1);
@@ -2285,7 +2285,7 @@ l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
pc->para.cause = 102; /* Timer expiry */
pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+ L3L4(pc->st, CC_SUSPEND_ERR, pc);
newl3state(pc, 10);
}
@@ -2293,7 +2293,7 @@ static void
l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
ni1_release_l3_process(pc);
}
@@ -2349,7 +2349,7 @@ l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
* if received MT_STATUS with cause == 111 and call
* state == 0, then we must set down layer 3
*/
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
ni1_release_l3_process(pc);
}
@@ -2408,7 +2408,7 @@ l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
L3DelTimer(&pc->timer);
newl3state(pc, 0);
pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+ L3L4(pc->st, CC_SUSPEND | CONFIRM, pc);
/* We don't handle suspend_ack for IE errors now */
if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
if (pc->debug & L3_DEB_WARN)
@@ -2438,7 +2438,7 @@ l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
return;
}
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+ L3L4(pc->st, CC_SUSPEND_ERR, pc);
newl3state(pc, 10);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3ni1_std_ie_err(pc, ret);
@@ -2502,7 +2502,7 @@ l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
return;
}
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+ L3L4(pc->st, CC_RESUME | CONFIRM, pc);
newl3state(pc, 10);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3ni1_std_ie_err(pc, ret);
@@ -2530,7 +2530,7 @@ l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
return;
}
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+ L3L4(pc->st, CC_RESUME_ERR, pc);
newl3state(pc, 0);
if (ret) /* STATUS for none mandatory IE errors after actions are taken */
l3ni1_std_ie_err(pc, ret);
@@ -2568,9 +2568,9 @@ l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
up = pc->st->l3.proc;
while (up) {
if ((ri & 7) == 7)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+ L4L3(up->st, CC_RESTART | REQUEST, up);
else if (up->para.bchannel == chan)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+ L4L3(up->st, CC_RESTART | REQUEST, up);
up = up->next;
}
@@ -2598,7 +2598,7 @@ l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
pc->para.cause = 0x29; /* Temporary failure */
pc->para.loc = 0;
l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+ L3L4(pc->st, CC_SETUP_ERR, pc);
}
static void
@@ -2607,7 +2607,7 @@ l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ L3L4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
@@ -2642,7 +2642,7 @@ static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *sk
{
printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn );
newl3state( pc, 0 );
- pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+ L3L2( pc->st, DL_RELEASE | REQUEST, NULL );
return;
}
@@ -2667,7 +2667,7 @@ static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *sk
L3DelTimer( &pc->timer );
L3AddTimer( &pc->timer, TSPID, CC_TSPID );
- pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb );
+ L3L2( pc->st, DL_DATA | REQUEST, skb );
}
static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
@@ -2700,7 +2700,7 @@ static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg )
printk( KERN_ERR "SPID not accepted\n" );
newl3state( pc, 0 );
- pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+ L3L2( pc->st, DL_RELEASE | REQUEST, NULL );
}
}
@@ -3170,9 +3170,9 @@ setstack_ni1(struct PStack *st)
char tmp[64];
int i;
- st->lli.l4l3 = ni1down;
- st->lli.l4l3_proto = l3ni1_cmd_global;
- st->l2.l2l3 = ni1up;
+ st->l3.l4l3 = ni1down;
+ st->l3.l4l3_proto = l3ni1_cmd_global;
+ st->l3.l2l3 = ni1up;
st->l3.l3ml3 = ni1man;
st->l3.N303 = 1;
st->prot.ni1.last_invoke_id = 0;
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 7482de0f6..482957140 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -847,7 +847,7 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -863,7 +863,7 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
mode_tiger(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -924,7 +924,7 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
if (open_tigerstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = tiger_l2l1;
+ st->l1.l2l1 = tiger_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index 2881487aa..3c6e70880 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -478,7 +478,7 @@ extern int st5481_debug;
if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
static void __attribute__((unused))
-dump_iso_packet(const char *name,urb_t *urb)
+dump_iso_packet(const char *name, struct urb *urb)
{
int i,j;
int len,ofs;
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index b0b3d0662..cd9b0389f 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -297,7 +297,7 @@ static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
unsigned int num_packets, packet_offset;
int len, buf_size, bytes_sent;
struct sk_buff *skb;
- iso_packet_descriptor_t *desc;
+ struct usb_iso_packet_descriptor *desc;
if (d_out->fsm.state != ST_DOUT_NORMAL)
return;
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index 0aa5edf99..a3e776f4d 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -235,7 +235,7 @@ int __devinit st5481_setup_usb(struct st5481_adapter *adapter)
struct usb_interface_descriptor *altsetting;
struct usb_endpoint_descriptor *endpoint;
int status;
- urb_t *urb;
+ struct urb *urb;
u_char *buf;
DBG(1,"");
@@ -560,7 +560,7 @@ void st5481_release_in(struct st5481_in *in)
*/
int st5481_isoc_flatten(struct urb *urb)
{
- iso_packet_descriptor_t *pipd,*pend;
+ struct usb_iso_packet_descriptor *pipd,*pend;
unsigned char *src,*dst;
unsigned int len;
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index e08446d44..9439ba57f 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -120,7 +120,7 @@ put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
bp[2] = ri & 0xff;
bp[3] = m_id;
bp[4] = (tei << 1) | 1;
- st->l2.l2l1(st, PH_DATA | REQUEST, skb);
+ L2L1(st, PH_DATA | REQUEST, skb);
}
static void
@@ -166,7 +166,7 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg)
} else if (ri == st->ma.ri) {
FsmDelTimer(&st->ma.t202, 1);
FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
- st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
+ L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
}
@@ -240,7 +240,7 @@ tei_id_remove(struct FsmInst *fi, int event, void *arg)
if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
FsmDelTimer(&st->ma.t202, 5);
FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
- st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
+ L3L2(st, MDL_REMOVE | REQUEST, 0);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
}
@@ -276,7 +276,7 @@ tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
} else {
st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
- st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0);
+ L3L2(st, MDL_ERROR | RESPONSE, 0);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
FsmChangeState(fi, ST_TEI_NOP);
@@ -299,7 +299,7 @@ tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
} else {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"verify req for tei %d failed", st->l2.tei);
- st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
+ L3L2(st, MDL_REMOVE | REQUEST, 0);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
FsmChangeState(fi, ST_TEI_NOP);
@@ -372,7 +372,7 @@ tei_l2tei(struct PStack *st, int pr, void *arg)
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"fixed assign tei %d", st->l2.tei);
- st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
+ L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
}
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index d8e82616c..7e0e6cff7 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -108,7 +108,7 @@ W6692_bh(struct IsdnCardState *cs)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+ L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
@@ -614,7 +614,7 @@ W6692_l1hw(struct PStack *st, int pr, void *arg)
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -687,7 +687,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+ L1L2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
@@ -772,7 +772,7 @@ W6692_l2l1(struct PStack *st, int pr, void *arg)
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ L1L2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
@@ -788,7 +788,7 @@ W6692_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
W6692Bmode(st->l1.bcs, 0, st->l1.bc);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
@@ -852,7 +852,7 @@ setstack_w6692(struct PStack *st, struct BCState *bcs)
if (open_w6692state(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
- st->l2.l2l1 = W6692_l2l1;
+ st->l1.l2l1 = W6692_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index 2e78a0e3d..d6fa2e0ef 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -65,7 +65,6 @@ static isdn_divert_if *divert_if; /* = NULL */
#endif /* CONFIG_ISDN_DIVERSION */
-static int isdn_writebuf_stub(int, int, const u_char *, int, int);
static void set_global_features(void);
static void isdn_register_devfs(int);
static void isdn_unregister_devfs(int);
@@ -946,7 +945,9 @@ isdn_statstr(void)
return istatbuf;
}
-/* Module interface-code */
+/*
+ * /dev/isdninfo
+ */
void
isdn_info_update(void)
@@ -960,234 +961,321 @@ isdn_info_update(void)
wake_up_interruptible(&(dev->info_waitq));
}
+static int
+isdn_status_open(struct inode *ino, struct file *filep)
+{
+ infostruct *p;
+
+ p = kmalloc(sizeof(infostruct), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->next = (char *) dev->infochain;
+ p->private = (char *) &(filep->private_data);
+ dev->infochain = p;
+ /* At opening we allow a single update */
+ filep->private_data = (char *) 1;
+
+ return 0;
+}
+
+static int
+isdn_status_release(struct inode *ino, struct file *filep)
+{
+ infostruct *p = dev->infochain;
+ infostruct *q = NULL;
+
+ lock_kernel();
+
+ while (p) {
+ if (p->private == (char *) &(filep->private_data)) {
+ if (q)
+ q->next = p->next;
+ else
+ dev->infochain = (infostruct *) (p->next);
+ kfree(p);
+ goto out;
+ }
+ q = p;
+ p = (infostruct *) (p->next);
+ }
+ printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+
+ out:
+ unlock_kernel();
+ return 0;
+}
+
static ssize_t
-isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off)
{
- uint minor = minor(file->f_dentry->d_inode->i_rdev);
- int len = 0;
- ulong flags;
- int drvidx;
- int chidx;
int retval;
+ int len = 0;
char *p;
if (off != &file->f_pos)
return -ESPIPE;
lock_kernel();
- if (minor == ISDN_MINOR_STATUS) {
- if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- interruptible_sleep_on(&(dev->info_waitq));
- }
- p = isdn_statstr();
- file->private_data = 0;
- if ((len = strlen(p)) <= count) {
- if (copy_to_user(buf, p, len)) {
- retval = -EFAULT;
- goto out;
- }
- *off += len;
- retval = len;
+ if (!file->private_data) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
goto out;
}
- retval = 0;
- goto out;
- }
- if (!dev->drivers) {
- retval = -ENODEV;
- goto out;
- }
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- if (!(p = kmalloc(count, GFP_KERNEL))) {
- retval = -ENOMEM;
- goto out;
- }
- save_flags(flags);
- cli();
- len = isdn_readbchan(drvidx, chidx, p, 0, count,
- &dev->drv[drvidx]->rcv_waitq[chidx]);
- *off += len;
- restore_flags(flags);
- if (copy_to_user(buf,p,len))
- len = -EFAULT;
- kfree(p);
- retval = len;
- goto out;
+ interruptible_sleep_on(&(dev->info_waitq));
}
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
+ p = isdn_statstr();
+ file->private_data = 0;
+ if ((len = strlen(p)) <= count) {
+ if (copy_to_user(buf, p, len)) {
+ retval = -EFAULT;
goto out;
}
- if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
- }
- if (dev->drv[drvidx]->interface->readstat) {
- if (count > dev->drv[drvidx]->stavail)
- count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->
- readstat(buf, count, 1, drvidx,
- isdn_minor2chan(minor));
- } else {
- len = 0;
- }
- save_flags(flags);
- cli();
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
- restore_flags(flags);
*off += len;
retval = len;
goto out;
}
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
+ retval = 0;
+ goto out;
+
out:
unlock_kernel();
return retval;
}
static ssize_t
-isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+ return -EPERM;
+}
+
+static unsigned int
+isdn_status_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ lock_kernel();
+
+ poll_wait(file, &(dev->info_waitq), wait);
+ if (file->private_data)
+ mask |= POLLIN | POLLRDNORM;
+
+ unlock_kernel();
+ return mask;
+}
+
+static int
+isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ int ret;
+ union iocpar {
+ char name[10];
+ char bname[22];
+ isdn_ioctl_struct iocts;
+ isdn_net_ioctl_phone phone;
+ isdn_net_ioctl_cfg cfg;
+ } iocpar;
+
+#define name iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg iocpar.cfg
+
+ switch (cmd) {
+ case IIOCGETDVR:
+ return (TTY_DV +
+ (NET_DV << 8) +
+ (INF_DV << 16));
+ case IIOCGETCPS:
+ if (arg) {
+ ulong *p = (ulong *) arg;
+ int i;
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+ return ret;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ put_user(dev->ibytes[i], p++);
+ put_user(dev->obytes[i], p++);
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+#ifdef CONFIG_NETDEVICES
+ case IIOCNETGPN:
+ /* Get peer phone number of a connected
+ * isdn network interface */
+ if (arg) {
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+ return -EFAULT;
+ return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+ } else
+ return -EINVAL;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
+}
+
+static struct file_operations isdn_status_fops =
+{
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ read: isdn_status_read,
+ write: isdn_status_write,
+ poll: isdn_status_poll,
+ ioctl: isdn_status_ioctl,
+ open: isdn_status_open,
+ release: isdn_status_release,
+};
+
+/*
+ * /dev/isdnctrlX
+ */
+
+static int
+isdn_ctrl_open(struct inode *ino, struct file *filep)
+{
+ uint minor = minor(ino->i_rdev);
+ int drvidx;
+
+ drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ if (drvidx < 0)
+ return -ENODEV;
+
+ isdn_lock_drivers();
+ return 0;
+}
+
+static int
+isdn_ctrl_release(struct inode *ino, struct file *filep)
+{
+ lock_kernel();
+
+ if (dev->profd == current)
+ dev->profd = NULL;
+
+ isdn_unlock_drivers();
+
+ unlock_kernel();
+ return 0;
+}
+
+static ssize_t
+isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
{
uint minor = minor(file->f_dentry->d_inode->i_rdev);
+ ulong flags;
+ int len = 0;
int drvidx;
- int chidx;
int retval;
if (off != &file->f_pos)
return -ESPIPE;
- if (minor == ISDN_MINOR_STATUS)
- return -EPERM;
- if (!dev->drivers)
- return -ENODEV;
-
lock_kernel();
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
- interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
- retval = count;
+
+ drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ if (drvidx < 0) {
+ retval = -ENODEV;
goto out;
}
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
+ if (!dev->drv[drvidx]->stavail) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
goto out;
}
- /*
- * We want to use the isdnctrl device to load the firmware
- *
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- */
- if (dev->drv[drvidx]->interface->writecmd)
- retval = dev->drv[drvidx]->interface->
- writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
- else
- retval = count;
+ interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+ }
+ if (dev->drv[drvidx]->interface->readstat) {
+ if (count > dev->drv[drvidx]->stavail)
+ count = dev->drv[drvidx]->stavail;
+ len = dev->drv[drvidx]->interface->
+ readstat(buf, count, 1, drvidx,
+ isdn_minor2chan(minor));
+ } else {
+ len = 0;
+ }
+ save_flags(flags);
+ cli();
+ if (len)
+ dev->drv[drvidx]->stavail -= len;
+ else
+ dev->drv[drvidx]->stavail = 0;
+ restore_flags(flags);
+ *off += len;
+ retval = len;
+
+ out:
+ unlock_kernel();
+ return retval;
+}
+
+static ssize_t
+isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+ uint minor = minor(file->f_dentry->d_inode->i_rdev);
+ int drvidx;
+ int retval;
+
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
+ lock_kernel();
+
+ drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ if (drvidx < 0) {
+ retval = -ENODEV;
goto out;
}
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
+ if (!dev->drv[drvidx]->interface->writecmd) {
+ retval = -EINVAL;
goto out;
}
-#endif
- retval = -ENODEV;
+ retval = dev->drv[drvidx]->interface->
+ writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
+
out:
unlock_kernel();
return retval;
}
static unsigned int
-isdn_poll(struct file *file, poll_table * wait)
+isdn_ctrl_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ int drvidx;
+
+ drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ if (drvidx < 0)
+ /* driver deregistered while file open */
+ return POLLHUP;
lock_kernel();
- if (minor == ISDN_MINOR_STATUS) {
- poll_wait(file, &(dev->info_waitq), wait);
- /* mask = POLLOUT | POLLWRNORM; */
- if (file->private_data) {
- mask |= POLLIN | POLLRDNORM;
- }
- goto out;
- }
- if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- if (drvidx < 0) {
- /* driver deregistered while file open */
- mask = POLLHUP;
- goto out;
- }
- poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
- mask = POLLOUT | POLLWRNORM;
- if (dev->drv[drvidx]->stavail) {
- mask |= POLLIN | POLLRDNORM;
- }
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- mask = isdn_ppp_poll(file, wait);
- goto out;
- }
-#endif
- mask = POLLERR;
- out:
+
+ poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+ mask = POLLOUT | POLLWRNORM;
+ if (dev->drv[drvidx]->stavail)
+ mask |= POLLIN | POLLRDNORM;
+
unlock_kernel();
return mask;
}
static int
-isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
- uint minor = minor(inode->i_rdev);
isdn_ctrl c;
int drvidx;
- int chidx;
int ret;
int i;
char *p;
@@ -1205,55 +1293,6 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
#define iocts iocpar.iocts
#define phone iocpar.phone
#define cfg iocpar.cfg
-
- if (minor == ISDN_MINOR_STATUS) {
- switch (cmd) {
- case IIOCGETDVR:
- return (TTY_DV +
- (NET_DV << 8) +
- (INF_DV << 16));
- case IIOCGETCPS:
- if (arg) {
- ulong *p = (ulong *) arg;
- int i;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
- return ret;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- put_user(dev->ibytes[i], p++);
- put_user(dev->obytes[i], p++);
- }
- return 0;
- } else
- return -EINVAL;
- break;
-#ifdef CONFIG_NETDEVICES
- case IIOCNETGPN:
- /* Get peer phone number of a connected
- * isdn network interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
- } else
- return -EINVAL;
-#endif
- default:
- return -EINVAL;
- }
- }
- if (!dev->drivers)
- return -ENODEV;
- if (minor <= ISDN_MINOR_BMAX) {
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- return -ENODEV;
- chidx = isdn_minor2chan(minor);
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- return 0;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
/*
* isdn net devices manage lots of configuration variables as linked lists.
* Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1261,366 +1300,360 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
* manipulating the lists and ioctl's sleeping while accessing the lists
* are serialized by means of a semaphore.
*/
- switch (cmd) {
- case IIOCNETDWRSET:
- printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
- return(-EINVAL);
- case IIOCNETLCR:
- printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
- return -ENODEV;
+ switch (cmd) {
+ case IIOCNETDWRSET:
+ printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+ return(-EINVAL);
+ case IIOCNETLCR:
+ printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+ return -ENODEV;
#ifdef CONFIG_NETDEVICES
- case IIOCNETAIF:
- /* Add a network-interface */
- if (arg) {
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- s = name;
- } else {
- s = NULL;
- }
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- if ((s = isdn_net_new(s, NULL))) {
- if (copy_to_user((char *) arg, s, strlen(s) + 1)){
- ret = -EFAULT;
- } else {
- ret = 0;
+ case IIOCNETAIF:
+ /* Add a network-interface */
+ if (arg) {
+ if (copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
+ s = name;
+ } else {
+ s = NULL;
+ }
+ ret = down_interruptible(&dev->sem);
+ if( ret ) return ret;
+ if ((s = isdn_net_new(s, NULL))) {
+ if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+ ret = -EFAULT;
+ } else {
+ ret = 0;
+ }
+ } else
+ ret = -ENODEV;
+ up(&dev->sem);
+ return ret;
+ case IIOCNETASL:
+ /* Add a slave to a network-interface */
+ if (arg) {
+ if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
+ return -EFAULT;
+ } else
+ return -EINVAL;
+ ret = down_interruptible(&dev->sem);
+ if( ret ) return ret;
+ if ((s = isdn_net_newslave(bname))) {
+ if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+ ret = -EFAULT;
+ } else {
+ ret = 0;
+ }
+ } else
+ ret = -ENODEV;
+ up(&dev->sem);
+ return ret;
+ case IIOCNETDIF:
+ /* Delete a network-interface */
+ if (arg) {
+ if (copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
+ ret = down_interruptible(&dev->sem);
+ if( ret ) return ret;
+ ret = isdn_net_rm(name);
+ up(&dev->sem);
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETSCF:
+ /* Set configurable parameters of a network-interface */
+ if (arg) {
+ if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+ return -EFAULT;
+ return isdn_net_setcfg(&cfg);
+ } else
+ return -EINVAL;
+ case IIOCNETGCF:
+ /* Get configurable parameters of a network-interface */
+ if (arg) {
+ if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+ return -EFAULT;
+ if (!(ret = isdn_net_getcfg(&cfg))) {
+ if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+ return -EFAULT;
+ }
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETANM:
+ /* Add a phone-number to a network-interface */
+ if (arg) {
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+ return -EFAULT;
+ ret = down_interruptible(&dev->sem);
+ if( ret ) return ret;
+ ret = isdn_net_addphone(&phone);
+ up(&dev->sem);
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETGNM:
+ /* Get list of phone-numbers of a network-interface */
+ if (arg) {
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+ return -EFAULT;
+ ret = down_interruptible(&dev->sem);
+ if( ret ) return ret;
+ ret = isdn_net_getphones(&phone, (char *) arg);
+ up(&dev->sem);
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETDNM:
+ /* Delete a phone-number of a network-interface */
+ if (arg) {
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+ return -EFAULT;
+ ret = down_interruptible(&dev->sem);
+ if( ret ) return ret;
+ ret = isdn_net_delphone(&phone);
+ up(&dev->sem);
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETDIL:
+ /* Force dialing of a network-interface */
+ if (arg) {
+ if (copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
+ return isdn_net_force_dial(name);
+ } else
+ return -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+ case IIOCNETALN:
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
+ return isdn_ppp_dial_slave(name);
+ case IIOCNETDLN:
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
+ return isdn_ppp_hangup_slave(name);
+#endif
+ case IIOCNETHUP:
+ /* Force hangup of a network-interface */
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
+ return isdn_net_force_hangup(name);
+ break;
+#endif /* CONFIG_NETDEVICES */
+ case IIOCSETVER:
+ dev->net_verbose = arg;
+ printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+ return 0;
+ case IIOCSETGST:
+ if (arg)
+ dev->global_flags |= ISDN_GLOBAL_STOPPED;
+ else
+ dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+ printk(KERN_INFO "isdn: Global Mode %s\n",
+ (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+ return 0;
+ case IIOCSETBRJ:
+ drvidx = -1;
+ if (arg) {
+ int i;
+ char *p;
+ if (copy_from_user((char *) &iocts, (char *) arg,
+ sizeof(isdn_ioctl_struct)))
+ return -EFAULT;
+ if (strlen(iocts.drvid)) {
+ if ((p = strchr(iocts.drvid, ',')))
+ *p = 0;
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
}
- } else
- ret = -ENODEV;
- up(&dev->sem);
+ }
+ }
+ if (drvidx == -1)
+ return -ENODEV;
+ if (iocts.arg)
+ dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+ else
+ dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+ return 0;
+ case IIOCSIGPRF:
+ dev->profd = current;
+ return 0;
+ break;
+ case IIOCGETPRF:
+ /* Get all Modem-Profiles */
+ if (arg) {
+ char *p = (char *) arg;
+ int i;
+
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+ * ISDN_MAX_CHANNELS)))
return ret;
- case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (arg) {
- if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
- return -EFAULT;
- } else
- return -EINVAL;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- if ((s = isdn_net_newslave(bname))) {
- if (copy_to_user((char *) arg, s, strlen(s) + 1)){
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- up(&dev->sem);
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+ ISDN_MODEM_NUMREG))
+ return -EFAULT;
+ p += ISDN_MODEM_NUMREG;
+ if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+ return -EFAULT;
+ p += ISDN_MSNLEN;
+ if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+ return -EFAULT;
+ p += ISDN_LMSNLEN;
+ }
+ return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+ } else
+ return -EINVAL;
+ break;
+ case IIOCSETPRF:
+ /* Set all Modem-Profiles */
+ if (arg) {
+ char *p = (char *) arg;
+ int i;
+
+ if ((ret = verify_area(VERIFY_READ, (void *) arg,
+ (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+ * ISDN_MAX_CHANNELS)))
return ret;
- case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_rm(name);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
- return -EFAULT;
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
- case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
- return -EFAULT;
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
- return -EFAULT;
- }
- return ret;
- } else
- return -EINVAL;
- case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_addphone(&phone);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_getphones(&phone, (char *) arg);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_delphone(&phone);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
- case IIOCNETALN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, (char *) arg, sizeof(name)))
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+ ISDN_MODEM_NUMREG))
return -EFAULT;
- return isdn_ppp_dial_slave(name);
- case IIOCNETDLN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, (char *) arg, sizeof(name)))
+ p += ISDN_MODEM_NUMREG;
+ if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
return -EFAULT;
- return isdn_ppp_hangup_slave(name);
-#endif
- case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, (char *) arg, sizeof(name)))
+ p += ISDN_LMSNLEN;
+ if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
return -EFAULT;
- return isdn_net_force_hangup(name);
- break;
-#endif /* CONFIG_NETDEVICES */
- case IIOCSETVER:
- dev->net_verbose = arg;
- printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
- return 0;
- case IIOCSETGST:
- if (arg)
- dev->global_flags |= ISDN_GLOBAL_STOPPED;
- else
- dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
- printk(KERN_INFO "isdn: Global Mode %s\n",
- (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
- return 0;
- case IIOCSETBRJ:
+ p += ISDN_MSNLEN;
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ case IIOCSETMAP:
+ case IIOCGETMAP:
+ /* Set/Get MSN->EAZ-Mapping for a driver */
+ if (arg) {
+
+ if (copy_from_user((char *) &iocts,
+ (char *) arg,
+ sizeof(isdn_ioctl_struct)))
+ return -EFAULT;
+ if (strlen(iocts.drvid)) {
drvidx = -1;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user((char *) &iocts, (char *) arg,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- }
- }
- if (drvidx == -1)
- return -ENODEV;
- if (iocts.arg)
- dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
- else
- dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
- return 0;
- case IIOCSIGPRF:
- dev->profd = current;
- return 0;
- break;
- case IIOCGETPRF:
- /* Get all Modem-Profiles */
- if (arg) {
- char *p = (char *) arg;
- int i;
-
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- }
- return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
- } else
- return -EINVAL;
- break;
- case IIOCSETPRF:
- /* Set all Modem-Profiles */
- if (arg) {
- char *p = (char *) arg;
- int i;
-
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
}
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCSETMAP:
- case IIOCGETMAP:
- /* Set/Get MSN->EAZ-Mapping for a driver */
- if (arg) {
-
- if (copy_from_user((char *) &iocts,
- (char *) arg,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if (cmd == IIOCSETMAP) {
- int loop = 1;
-
- p = (char *) iocts.arg;
- i = 0;
- while (loop) {
- int j = 0;
-
- while (1) {
- if ((ret = verify_area(VERIFY_READ, p, 1)))
- return ret;
- get_user(bname[j], p++);
- switch (bname[j]) {
- case '\0':
- loop = 0;
- /* Fall through */
- case ',':
- bname[j] = '\0';
- strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
- j = ISDN_MSNLEN;
- break;
- default:
- j++;
- }
- if (j >= ISDN_MSNLEN)
- break;
- }
- if (++i > 9)
- break;
- }
- } else {
- p = (char *) iocts.arg;
- for (i = 0; i < 10; i++) {
- sprintf(bname, "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "_",
- (i < 9) ? "," : "\0");
- if (copy_to_user(p, bname, strlen(bname) + 1))
- return -EFAULT;
- p += strlen(bname);
+ } else
+ drvidx = 0;
+ if (drvidx == -1)
+ return -ENODEV;
+ if (cmd == IIOCSETMAP) {
+ int loop = 1;
+
+ p = (char *) iocts.arg;
+ i = 0;
+ while (loop) {
+ int j = 0;
+
+ while (1) {
+ if ((ret = verify_area(VERIFY_READ, p, 1)))
+ return ret;
+ get_user(bname[j], p++);
+ switch (bname[j]) {
+ case '\0':
+ loop = 0;
+ /* Fall through */
+ case ',':
+ bname[j] = '\0';
+ strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+ j = ISDN_MSNLEN;
+ break;
+ default:
+ j++;
}
+ if (j >= ISDN_MSNLEN)
+ break;
}
- return 0;
- } else
- return -EINVAL;
- case IIOCDBGVAR:
- if (arg) {
- if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
- return -EFAULT;
- return 0;
- } else
- return -EINVAL;
- break;
- default:
- if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
- cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
- else
- return -EINVAL;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- c.driver = drvidx;
- c.command = ISDN_CMD_IOCTL;
- c.arg = cmd;
- memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
- ret = isdn_command(&c);
- memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
- if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+ if (++i > 9)
+ break;
+ }
+ } else {
+ p = (char *) iocts.arg;
+ for (i = 0; i < 10; i++) {
+ sprintf(bname, "%s%s",
+ strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+ dev->drv[drvidx]->msn2eaz[i] : "_",
+ (i < 9) ? "," : "\0");
+ if (copy_to_user(p, bname, strlen(bname) + 1))
return -EFAULT;
- return ret;
- } else
- return -EINVAL;
- }
+ p += strlen(bname);
+ }
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ case IIOCDBGVAR:
+ if (arg) {
+ if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
+ return -EFAULT;
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+ cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+ else
+ return -EINVAL;
+ if (arg) {
+ int i;
+ char *p;
+ if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
+ return -EFAULT;
+ if (strlen(iocts.drvid)) {
+ if ((p = strchr(iocts.drvid, ',')))
+ *p = 0;
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ } else
+ drvidx = 0;
+ if (drvidx == -1)
+ return -ENODEV;
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ c.driver = drvidx;
+ c.command = ISDN_CMD_IOCTL;
+ c.arg = cmd;
+ memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+ ret = isdn_command(&c);
+ memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+ if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+ return -EFAULT;
+ return ret;
+ } else
+ return -EINVAL;
}
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
- return -ENODEV;
#undef name
#undef bname
@@ -1629,123 +1662,62 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
#undef cfg
}
+static struct file_operations isdn_ctrl_fops =
+{
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ read: isdn_ctrl_read,
+ write: isdn_ctrl_write,
+ poll: isdn_ctrl_poll,
+ ioctl: isdn_ctrl_ioctl,
+ open: isdn_ctrl_open,
+ release: isdn_ctrl_release,
+};
+
/*
- * Open the device code.
+ * file_operations for major 43, /dev/isdn*
+ * stolen from drivers/char/misc.c
*/
+
static int
-isdn_open(struct inode *ino, struct file *filep)
+isdn_open(struct inode * inode, struct file * file)
{
- uint minor = minor(ino->i_rdev);
- int drvidx;
- int chidx;
- int retval = -ENODEV;
-
-
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p;
-
- if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
- p->next = (char *) dev->infochain;
- p->private = (char *) &(filep->private_data);
- dev->infochain = p;
- /* At opening we allow a single update */
- filep->private_data = (char *) 1;
- retval = 0;
- goto out;
- } else {
- retval = -ENOMEM;
- goto out;
- }
- }
- if (!dev->channels)
- goto out;
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- goto out;
- chidx = isdn_minor2chan(minor);
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- goto out;
- if (!(dev->drv[drvidx]->online & (1 << chidx)))
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
+ int minor = minor(inode->i_rdev);
+ int err = -ENODEV;
+ struct file_operations *old_fops, *new_fops = NULL;
+
+ if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX)
+ new_fops = fops_get(&isdn_ctrl_fops);
#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
- if (retval == 0)
- isdn_lock_drivers();
- goto out;
- }
+ else if (minor >= ISDN_MINOR_PPP && minor <= ISDN_MINOR_PPPMAX)
+ new_fops = fops_get(&isdn_ppp_fops);
#endif
- out:
- return retval;
-}
+ else if (minor == ISDN_MINOR_STATUS)
+ new_fops = fops_get(&isdn_status_fops);
-static int
-isdn_close(struct inode *ino, struct file *filep)
-{
- uint minor = minor(ino->i_rdev);
+ if (!new_fops)
+ goto out;
- lock_kernel();
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p = dev->infochain;
- infostruct *q = NULL;
-
- while (p) {
- if (p->private == (char *) &(filep->private_data)) {
- if (q)
- q->next = p->next;
- else
- dev->infochain = (infostruct *) (p->next);
- kfree(p);
- goto out;
- }
- q = p;
- p = (infostruct *) (p->next);
+ err = 0;
+ old_fops = file->f_op;
+ file->f_op = new_fops;
+ if (file->f_op->open) {
+ err = file->f_op->open(inode,file);
+ if (err) {
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
}
- printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- goto out;
}
- isdn_unlock_drivers();
- if (minor <= ISDN_MINOR_BMAX)
- goto out;
- if (minor <= ISDN_MINOR_CTRLMAX) {
- if (dev->profd == current)
- dev->profd = NULL;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
-#endif
-
+ fops_put(old_fops);
+
out:
- unlock_kernel();
- return 0;
+ return err;
}
static struct file_operations isdn_fops =
{
owner: THIS_MODULE,
- llseek: no_llseek,
- read: isdn_read,
- write: isdn_write,
- poll: isdn_poll,
- ioctl: isdn_ioctl,
open: isdn_open,
- release: isdn_close,
};
char *
@@ -1878,32 +1850,6 @@ isdn_unexclusive_channel(int di, int ch)
}
/*
- * writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
- int user)
-{
- int ret;
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
- struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
- if (!skb)
- return 0;
- skb_reserve(skb, hl);
- if (user)
- copy_from_user(skb_put(skb, len), buf, len);
- else
- memcpy(skb_put(skb, len), buf, len);
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
- if (ret <= 0)
- dev_kfree_skb(skb);
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
- return ret;
-}
-
-/*
* Return: length of data on success, -ERRcode on failure.
*/
int
@@ -2226,7 +2172,7 @@ static void isdn_register_devfs(int k)
sprintf (buf, "isdn%d", k);
dev->devfs_handle_isdnX[k] =
devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
- ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR,
+ ISDN_MAJOR, k,0600 | S_IFCHR,
&isdn_fops, NULL);
sprintf (buf, "isdnctrl%d", k);
dev->devfs_handle_isdnctrlX[k] =
diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h
index 2565366ff..492b3c42e 100644
--- a/drivers/isdn/isdn_common.h
+++ b/drivers/isdn/isdn_common.h
@@ -27,6 +27,8 @@
/* Prototypes */
extern void isdn_MOD_INC_USE_COUNT(void);
extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_lock_drivers(void);
+extern void isdn_unlock_drivers(void);
extern void isdn_free_channel(int di, int ch, int usage);
extern void isdn_all_eaz(int di, int ch);
extern int isdn_command(isdn_ctrl *);
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 431683e13..95d9f72a4 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -9,8 +9,9 @@
*
*/
-#include <linux/config.h>
+#include <linux/module.h>
#include <linux/isdn.h>
+#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/ppp-comp.h>
@@ -268,22 +269,20 @@ isdn_ppp_get_slot(void)
* isdn_ppp_open
*/
-int
-isdn_ppp_open(int min, struct file *file)
+static int
+isdn_ppp_open(struct inode *ino, struct file *file)
{
+ uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
int slot;
struct ippp_struct *is;
- if (min < 0 || min > ISDN_MAX_CHANNELS)
- return -ENODEV;
-
slot = isdn_ppp_get_slot();
if (slot < 0) {
return -EBUSY;
}
is = file->private_data = ippp_table[slot];
- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+ printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
/* compression stuff */
is->link_compressor = is->compressor = NULL;
@@ -306,7 +305,7 @@ isdn_ppp_open(int min, struct file *file)
init_waitqueue_head(&is->wq);
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
- is->minor = min;
+ is->minor = minor;
#ifdef CONFIG_ISDN_PPP_VJ
/*
* VJ header compression init
@@ -315,6 +314,7 @@ isdn_ppp_open(int min, struct file *file)
#endif
is->state = IPPP_OPEN;
+ isdn_lock_drivers();
return 0;
}
@@ -322,18 +322,19 @@ isdn_ppp_open(int min, struct file *file)
/*
* release ippp device
*/
-void
-isdn_ppp_release(int min, struct file *file)
+static int
+isdn_ppp_release(struct inode *ino, struct file *file)
{
+ uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
int i;
struct ippp_struct *is;
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return;
+ lock_kernel();
+
is = file->private_data;
if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
+ printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp);
if (is->lp) { /* a lp address says: this link is still up */
isdn_net_dev *p = is->lp->netdev;
@@ -381,6 +382,11 @@ isdn_ppp_release(int min, struct file *file)
/* this slot is ready for new connections */
is->state = 0;
+
+ isdn_unlock_drivers();
+
+ unlock_kernel();
+ return 0;
}
/*
@@ -412,8 +418,8 @@ set_arg(void *b, void *val,int len)
/*
* ippp device ioctl
*/
-int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+static int
+isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long val;
int r,i,j;
@@ -425,7 +431,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
lp = is->lp;
if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
+ printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
if (!(is->state & IPPP_OPEN))
return -EINVAL;
@@ -438,7 +444,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
if ((r = get_arg((void *) arg, &val, sizeof(val) )))
return r;
printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- (int) min, (int) is->unit, (int) val);
+ (int) is->minor, (int) is->unit, (int) val);
return isdn_ppp_bundle(is, val);
#else
return -1;
@@ -573,7 +579,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
return 0;
}
-unsigned int
+static unsigned int
isdn_ppp_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
@@ -582,6 +588,7 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
unsigned long flags;
struct ippp_struct *is;
+ lock_kernel();
is = file->private_data;
if (is->debug & 0x2)
@@ -592,10 +599,13 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
poll_wait(file, &is->wq, wait);
if (!(is->state & IPPP_OPEN)) {
- if(is->state == IPPP_CLOSEWAIT)
- return POLLHUP;
+ if(is->state == IPPP_CLOSEWAIT) {
+ mask = POLLHUP;
+ goto out;
+ }
printk(KERN_DEBUG "isdn_ppp: device not open\n");
- return POLLERR;
+ mask = POLLERR;
+ goto out;
}
/* we're always ready to send .. */
mask = POLLOUT | POLLWRNORM;
@@ -612,6 +622,9 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
mask |= POLLIN | POLLRDNORM;
}
restore_flags(flags);
+
+ out:
+ unlock_kernel();
return mask;
}
@@ -677,22 +690,29 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
* reports, that there is data
*/
-int
-isdn_ppp_read(int min, struct file *file, char *buf, int count)
+static int
+isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct ippp_struct *is;
struct ippp_buf_queue *b;
- int r;
unsigned long flags;
unsigned char *save_buf;
+ int retval;
- is = file->private_data;
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
+ lock_kernel();
- if (!(is->state & IPPP_OPEN))
- return 0;
+ is = file->private_data;
- if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
- return r;
+ if (!(is->state & IPPP_OPEN)) {
+ retval = 0;
+ goto out;
+ }
+ retval = verify_area(VERIFY_WRITE, (void *) buf, count);
+ if (retval)
+ goto out;
save_flags(flags);
cli();
@@ -701,7 +721,8 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
save_buf = b->buf;
if (!save_buf) {
restore_flags(flags);
- return -EAGAIN;
+ retval = -EAGAIN;
+ goto out;
}
if (b->len < count)
count = b->len;
@@ -713,25 +734,37 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
copy_to_user(buf, save_buf, count);
kfree(save_buf);
- return count;
+ retval = count;
+
+ out:
+ unlock_kernel();
+ return retval;
}
/*
* ipppd wanna write a packet to the card .. non-blocking
*/
-int
-isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+static int
+isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
isdn_net_local *lp;
struct ippp_struct *is;
int proto;
unsigned char protobuf[4];
+ int retval;
+
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
+ lock_kernel();
is = file->private_data;
- if (!(is->state & IPPP_CONNECT))
- return 0;
+ if (!(is->state & IPPP_CONNECT)) {
+ retval = 0;
+ goto out;
+ }
lp = is->lp;
@@ -744,15 +777,18 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
* Don't reset huptimer for
* LCP packets. (Echo requests).
*/
- if (copy_from_user(protobuf, buf, 4))
- return -EFAULT;
+ if (copy_from_user(protobuf, buf, 4)) {
+ retval = -EFAULT;
+ goto out;
+ }
proto = PPP_PROTOCOL(protobuf);
if (proto != PPP_LCP)
lp->huptimer = 0;
- if (lp->isdn_device < 0 || lp->isdn_channel < 0)
- return 0;
-
+ if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
+ retval = 0;
+ goto out;
+ }
if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
@@ -767,13 +803,15 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
skb = alloc_skb(hl+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
- return count;
+ retval = count;
+ goto out;
}
skb_reserve(skb, hl);
if (copy_from_user(skb_put(skb, count), buf, count))
{
kfree_skb(skb);
- return -EFAULT;
+ retval = -EFAULT;
+ goto out;
}
if (is->debug & 0x40) {
printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
@@ -785,9 +823,25 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
isdn_net_write_super(lp, skb);
}
}
- return count;
+ retval = count;
+
+ out:
+ unlock_kernel();
+ return retval;
}
+struct file_operations isdn_ppp_fops =
+{
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ read: isdn_ppp_read,
+ write: isdn_ppp_write,
+ poll: isdn_ppp_poll,
+ ioctl: isdn_ppp_ioctl,
+ open: isdn_ppp_open,
+ release: isdn_ppp_release,
+};
+
/*
* init memory, structures etc.
*/
diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h
index 4495b079f..3b59bdcd2 100644
--- a/drivers/isdn/isdn_ppp.h
+++ b/drivers/isdn/isdn_ppp.h
@@ -12,9 +12,8 @@
#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
#include <linux/isdn_ppp.h> /* for isdn_ppp info */
-extern int isdn_ppp_read(int, struct file *, char *, int);
-extern int isdn_ppp_write(int, struct file *, const char *, int);
-extern int isdn_ppp_open(int, struct file *);
+extern struct file_operations isdn_ppp_fops;
+
extern int isdn_ppp_init(void);
extern void isdn_ppp_cleanup(void);
extern int isdn_ppp_free(isdn_net_local *);
@@ -22,9 +21,6 @@ extern int isdn_ppp_bind(isdn_net_local *);
extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
extern int isdn_ppp_dial_slave(char *);
extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3fb9ad117..48bcb9516 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3458,8 +3458,7 @@ recheck:
* about not overloading the IO subsystem. (things like an
* e2fsck being done on the RAID array should execute fast)
*/
- if (current->need_resched)
- schedule();
+ cond_resched();
currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index a4c643ce9..19158bbc0 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -94,8 +94,7 @@ static inline int fmi_setfreq(struct fmi_device *dev)
for(i=0; i< 100; i++)
{
udelay(1400);
- if(current->need_resched)
- schedule();
+ cond_resched();
}
/* If this becomes allowed use it ...
current->state = TASK_UNINTERRUPTIBLE;
@@ -121,8 +120,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
for(i=0; i< 100; i++)
{
udelay(1400);
- if(current->need_resched)
- schedule();
+ cond_resched();
}
/* If this becomes allowed use it ...
current->state = TASK_UNINTERRUPTIBLE;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 6ca1f83dc..02e0f6881 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -425,8 +425,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
wantlen -= t;
if (t < s)
break;
- if (current->need_resched)
- schedule();
+ cond_resched();
}
len = outptr;
@@ -445,8 +444,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
int l;
do {
l = qcam_read_bytes(q, tmpbuf, 3);
- if (current->need_resched)
- schedule();
+ cond_resched();
} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
if (force_rgb) {
if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
@@ -478,8 +476,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
int l;
do {
l = qcam_read_bytes(q, tmpbuf, 1);
- if (current->need_resched)
- schedule();
+ cond_resched();
} while (l && tmpbuf[0] == 0x7e);
l = qcam_read_bytes(q, tmpbuf+1, 2);
if (force_rgb) {
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 3dfa777e5..00de51d3b 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -2147,8 +2147,7 @@ static void fetch_frame(void *data)
/* loop until image ready */
do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
while (cam->params.status.streamState != STREAM_READY) {
- if (current->need_resched)
- schedule();
+ cond_resched();
current->state = TASK_INTERRUPTIBLE;
@@ -2163,8 +2162,7 @@ static void fetch_frame(void *data)
}
/* grab image from camera */
- if (current->need_resched)
- schedule();
+ cond_resched();
oldjif = jiffies;
image_size = cam->ops->streamRead(cam->lowlevel_data,
@@ -2189,8 +2187,7 @@ static void fetch_frame(void *data)
/* decompress and convert image to by copying it from
* raw_image to decompressed_frame
*/
- if (current->need_resched)
- schedule();
+ cond_resched();
cam->image_size = parse_picture(cam, image_size);
if (cam->image_size <= 0)
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index 05001ea50..36157f5a1 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -392,7 +392,7 @@ static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
endseen = 0;
block_size = PARPORT_CHUNK_SIZE;
while( !cam->image_complete ) {
- if(current->need_resched) schedule();
+ cond_resched();
new_bytes = cpia_pp_read(cam->port, buffer, block_size );
if( new_bytes <= 0 ) {
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 938d99ee2..474b05c77 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -46,7 +46,7 @@
struct cpia_sbuf {
char *data;
- urb_t *urb;
+ struct urb *urb;
};
#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
@@ -168,7 +168,7 @@ static void cpia_usb_complete(struct urb *urb)
static int cpia_usb_open(void *privdata)
{
struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
- urb_t *urb;
+ struct urb *urb;
int ret, retval = 0, fx, err;
if (!ucpia)
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 8d4bd9cc1..81f91ebd6 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -127,11 +127,7 @@ struct saa5249_device
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
-#define RESCHED \
- do { \
- if (current->need_resched) \
- schedule(); \
- } while (0)
+#define RESCHED do { cond_resched(); } while(0)
static struct video_device saa_template; /* Declared near bottom */
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 67cdf1b11..52a81d8a1 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -889,7 +889,7 @@ retry:
times_left = 500000;
while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
- if (current->need_resched) {
+ if (need_resched()) {
spin_unlock_bh(chip->mutex);
schedule();
spin_lock_bh(chip->mutex);
@@ -1126,7 +1126,7 @@ retry:
/* Latency issues. Drop the lock, wait a while and retry */
spin_unlock_bh(chip->mutex);
- if (current->need_resched)
+ if (need_resched())
schedule();
else
udelay(1);
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index 837ed5fc8..36ad7dee6 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -97,7 +97,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc)
DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
return -EIO;
}
- if (current->need_resched) {
+ if (need_resched()) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index e78f8ad62..937c86063 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -293,7 +293,6 @@ comment 'Wireless LAN (non-hamradio)'
bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
if [ "$CONFIG_NET_RADIO" = "y" ]; then
dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
- tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index caea6b027..ca9b84495 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -167,7 +167,6 @@ obj-$(CONFIG_EEXPRESS) += eexpress.o
obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
-obj-$(CONFIG_WAVELAN) += wavelan.o
obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
obj-$(CONFIG_ZNET) += znet.o
obj-$(CONFIG_LAN_SAA9730) += saa9730.o
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index a9a4ac162..894e65f71 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1141,6 +1141,8 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
//data[3] = mdio_read(ioaddr, data[0], data[1]);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
//mdio_write(ioaddr, data[0], data[1], data[2]);
return 0;
default:
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 1c232734f..707adf273 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1040,6 +1040,8 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
break;
case SIOCDEVPRIVATE + 2:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
break;
case SIOCDEVPRIVATE + 3:
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index e4be90c3d..599913636 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -28,8 +28,6 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then
dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
- dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
- dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
fi
fi
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
index c83001315..ab0268f87 100644
--- a/drivers/net/pcmcia/Makefile
+++ b/drivers/net/pcmcia/Makefile
@@ -27,8 +27,6 @@ obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o
# 16-bit wireless client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
-obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o
-obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o
# Cardbus client drivers
diff --git a/drivers/net/wireless/Config.in b/drivers/net/wireless/Config.in
index aa404b045..f4fabcff0 100644
--- a/drivers/net/wireless/Config.in
+++ b/drivers/net/wireless/Config.in
@@ -2,6 +2,12 @@
# Wireless LAN device configuration
#
+comment 'Wireless ISA/PCI cards support'
+
+# Good old obsolete Wavelan.
+tristate ' AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support' CONFIG_WAVELAN
+
+# 802.11b cards
if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
tristate ' Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards' CONFIG_AIRO
fi
@@ -18,8 +24,13 @@ fi
# If Pcmcia is compiled in, offer Pcmcia cards...
if [ "$CONFIG_PCMCIA" != "n" ]; then
- comment 'Wireless Pcmcia cards support'
+ comment 'Wireless Pcmcia/Cardbus cards support'
+
+# Obsolete cards
+ dep_tristate ' Xircom Netwave AirSurfer Pcmcia wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
+ dep_tristate ' AT&T/Lucent old Wavelan Pcmcia wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
+# 802.11b cards
dep_tristate ' Hermes PCMCIA card support' CONFIG_PCMCIA_HERMES $CONFIG_HERMES
tristate ' Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards' CONFIG_AIRO_CS
fi
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 06d9e29f2..b3b8df628 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -14,6 +14,11 @@ obj- :=
# Things that need to export symbols
export-objs := airo.o orinoco.o hermes.o
+# Obsolete cards
+obj-$(CONFIG_WAVELAN) += wavelan.o
+obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o
+obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o
+
obj-$(CONFIG_HERMES) += orinoco.o hermes.o
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
obj-$(CONFIG_APPLE_AIRPORT) += airport.o
diff --git a/drivers/net/i82586.h b/drivers/net/wireless/i82586.h
index 5f65b2506..5f65b2506 100644
--- a/drivers/net/i82586.h
+++ b/drivers/net/wireless/i82586.h
diff --git a/drivers/net/pcmcia/i82593.h b/drivers/net/wireless/i82593.h
index 33acb8add..33acb8add 100644
--- a/drivers/net/pcmcia/i82593.h
+++ b/drivers/net/wireless/i82593.h
diff --git a/drivers/net/pcmcia/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 8119f1193..9823adc71 100644
--- a/drivers/net/pcmcia/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -61,7 +61,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#ifdef CONFIG_NET_PCMCIA_RADIO
+#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
#endif
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt
index f5fd819b7..a23e93841 100644
--- a/drivers/net/wireless/todo.txt
+++ b/drivers/net/wireless/todo.txt
@@ -4,16 +4,15 @@
1) Bring other kernel Wireless LAN drivers here
Already done :
o hermes.c/orinoco.c -> Wavelan IEEE driver + Airport driver
- Drivers I have control over :
+ o airo.c/airo_cs.c -> Ben's Aironet driver
o wavelan.c -> old Wavelan ISA driver
- o wavelan_cs.c -> old Wavelan Pcmcia driver (warning : header)
+ o wavelan_cs.c -> old Wavelan Pcmcia driver
o netwave_cs.c -> Netwave Pcmcia driver
Drivers likely to go :
o ray_cs.c -> Raytheon/Aviator driver (maintainer MIA)
Drivers I have absolutely no control over :
o arlan.c -> old Aironet Arlan 655 (need to ask Elmer)
o aironet4500_xxx.c -> Elmer's Aironet driver (need to ask Elmer)
- o airo.c/airo_cs.c -> Ben's Aironet driver (not yet in kernel)
o strip.c -> Metricom's stuff. Not a wlan. Hum...
ETA : Kernel 2.5.X
@@ -21,4 +20,10 @@
2) Bring new Wireless LAN driver not yet in the kernel there
See my web page for details
+3) Misc
+ o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
+ o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
+ o Use new Probe/module stuff in wavelan.c
+ o New Wireless Extension API (pending)
+
Jean II
diff --git a/drivers/net/wavelan.c b/drivers/net/wireless/wavelan.c
index 10805eff7..10805eff7 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
diff --git a/drivers/net/wavelan.h b/drivers/net/wireless/wavelan.h
index 27172cde5..27172cde5 100644
--- a/drivers/net/wavelan.h
+++ b/drivers/net/wireless/wavelan.h
diff --git a/drivers/net/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index 6bc145acc..6bc145acc 100644
--- a/drivers/net/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
diff --git a/drivers/net/pcmcia/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index c2efbe424..b11332345 100644
--- a/drivers/net/pcmcia/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4,7 +4,7 @@
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
- * Original copyright follow. See wavelan_cs.h for details.
+ * Original copyright follow. See wavelan_cs.p.h for details.
*
* This code is derived from Anthony D. Joseph's code and all the changes here
* are also under the original copyright below.
@@ -22,7 +22,7 @@
#ifdef WAVELAN_ROAMING
* Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
* based on patch by Joe Finney from Lancaster University.
-#endif :-)
+#endif
*
* Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
* Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
@@ -37,12 +37,6 @@
* Apr 2 '98 made changes to bring the i82593 control/int handling in line
* with offical specs...
*
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
- * - reorganize kmallocs in wavelan_attach, checking all for failure
- * and releasing the previous allocations if one fails
- *
- *
****************************************************************************
* Copyright 1995
* Anthony D. Joseph
@@ -62,7 +56,7 @@
*
*/
-#include "wavelan_cs.h" /* Private header */
+#include "wavelan_cs.p.h" /* Private header */
/************************* MISC SUBROUTINES **************************/
/*
@@ -72,6 +66,34 @@
/*------------------------------------------------------------------*/
/*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local * lp,
+ unsigned long * pflags)
+{
+ spin_lock_irqsave(&lp->spinlock, *pflags);
+ /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local * lp,
+ unsigned long * pflags)
+{
+ spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+ /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+ * via : outb(OP1_INT_ENABLE, LCCR(base));
+ */
+}
+
+/*------------------------------------------------------------------*/
+/*
* Wrapper for reporting error to cardservices
*/
static void cs_error(client_handle_t handle, int func, int ret)
@@ -103,7 +125,7 @@ wv_structuct_check(void)
/******************* MODEM MANAGEMENT SUBROUTINES *******************/
/*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
*/
/*------------------------------------------------------------------*/
@@ -138,7 +160,7 @@ hacr_write_slow(u_long base,
{
hacr_write(base, hacr);
/* delay might only be needed sometimes */
- mdelay(1L);
+ mdelay(1);
} /* hacr_write_slow */
/*------------------------------------------------------------------*/
@@ -529,7 +551,7 @@ void wv_roam_init(struct net_device *dev)
lp->curr_point=NULL; /* No default WavePoint */
lp->cell_search=0;
- lp->cell_timer.data=(int)lp; /* Start cell expiry timer */
+ lp->cell_timer.data=(long)lp; /* Start cell expiry timer */
lp->cell_timer.function=wl_cell_expiry;
lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
add_timer(&lp->cell_timer);
@@ -569,18 +591,18 @@ void wv_nwid_filter(unsigned char mode, net_local *lp)
#endif
/* Disable interrupts & save flags */
- spin_lock_irqsave (&lp->lock, flags);
+ wv_splhi(lp, &flags);
m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
- /* ReEnable interrupts & restore flags */
- spin_unlock_irqrestore (&lp->lock, flags);
-
if(mode==NWID_PROMISC)
lp->cell_search=1;
else
- lp->cell_search=0;
+ lp->cell_search=0;
+
+ /* ReEnable interrupts & restore flags */
+ wv_splx(lp, &flags);
}
/* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +759,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
ioaddr_t base = lp->dev->base_addr;
mm_t m;
unsigned long flags;
-
+
if(wavepoint==lp->curr_point) /* Sanity check... */
{
wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +771,16 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
#endif
/* Disable interrupts & save flags */
- spin_lock_irqsave(&lp->lock, flags);
-
+ wv_splhi(lp, &flags);
+
m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
/* ReEnable interrupts & restore flags */
- spin_unlock_irqrestore (&lp->lock, flags);
-
+ wv_splx(lp, &flags);
+
wv_nwid_filter(!NWID_PROMISC,lp);
lp->curr_point=wavepoint;
}
@@ -775,6 +797,11 @@ static inline void wl_roam_gather(device * dev,
wavepoint_history *wavepoint=NULL; /* WavePoint table entry */
net_local *lp=(net_local *)dev->priv; /* Device info */
+#if 0
+ /* Some people don't need this, some other may need it */
+ nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
#if WAVELAN_ROAMING_DEBUG > 1
printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +859,9 @@ static inline int WAVELAN_BEACON(unsigned char *data)
/*------------------------------------------------------------------*/
/*
* Routine to synchronously send a command to the i82593 chip.
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ * wv_82593_config() & wv_diag())
*/
static int
wv_82593_cmd(device * dev,
@@ -841,74 +870,98 @@ wv_82593_cmd(device * dev,
int result)
{
ioaddr_t base = dev->base_addr;
- net_local * lp = (net_local *)dev->priv;
int status;
+ int wait_completed;
long spin;
- u_long flags;
/* Spin until the chip finishes executing its current command (if any) */
+ spin = 1000;
do
{
- spin_lock_irqsave (&lp->lock, flags);
+ /* Time calibration of the loop */
+ udelay(10);
+
+ /* Read the interrupt register */
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- spin_unlock_irqrestore (&lp->lock, flags);
}
- while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+ while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
- /* We are waiting for command completion */
- wv_wait_completed = TRUE;
+ /* If the interrupt hasn't be posted */
+ if(spin <= 0)
+ {
+#ifdef DEBUG_INTERRUPT_ERROR
+ printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+ str, status);
+#endif
+ return(FALSE);
+ }
/* Issue the command to the controller */
outb(cmd, LCCR(base));
- /* If we don't have to check the result of the command */
+ /* If we don't have to check the result of the command
+ * Note : this mean that the irq handler will deal with that */
if(result == SR0_NO_RESULT)
- {
- wv_wait_completed = FALSE;
- return(TRUE);
- }
+ return(TRUE);
- /* Busy wait while the LAN controller executes the command.
- * Note : wv_wait_completed should be volatile */
- spin = 0;
- while(wv_wait_completed && (spin++ < 1000))
- udelay(10);
+ /* We are waiting for command completion */
+ wait_completed = TRUE;
- /* If the interrupt handler hasn't be called */
- if(wv_wait_completed)
+ /* Busy wait while the LAN controller executes the command. */
+ spin = 1000;
+ do
{
- outb(OP0_NOP, LCCR(base));
+ /* Time calibration of the loop */
+ udelay(10);
+
+ /* Read the interrupt register */
+ outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
status = inb(LCSR(base));
- if(status & SR0_INTERRUPT)
+
+ /* Check if there was an interrupt posted */
+ if((status & SR0_INTERRUPT))
{
- /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+ /* Acknowledge the interrupt */
+ outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
- wavelan_interrupt(dev->irq, (void *) dev,
- (struct pt_regs *) NULL);
+ /* Check if interrupt is a command completion */
+ if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+ ((status & SR0_BOTH_RX_TX) != 0x0) &&
+ !(status & SR0_RECEPTION))
+ {
+ /* Signal command completion */
+ wait_completed = FALSE;
+ }
+ else
+ {
+ /* Note : Rx interrupts will be handled later, because we can
+ * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+ printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+ }
}
- else
- {
- wv_wait_completed = 0; /* XXX */
+ }
+ while(wait_completed && (spin-- > 0));
+
+ /* If the interrupt hasn't be posted */
+ if(wait_completed)
+ {
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
- str, status);
+ printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+ str, status);
#endif
- /* We probably should reset the controller here */
- return(FALSE);
- }
+ return(FALSE);
}
- /* Check the return code provided by the interrupt handler against
+ /* Check the return code returned by the card (see above) against
* the expected return code provided by the caller */
- if((lp->status & SR0_EVENT_MASK) != result)
+ if((status & SR0_EVENT_MASK) != result)
{
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
- str, lp->status);
+ printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+ str, status);
#endif
return(FALSE);
}
@@ -924,14 +977,16 @@ wv_82593_cmd(device * dev,
static inline int
wv_diag(device * dev)
{
+ int ret = FALSE;
+
if(wv_82593_cmd(dev, "wv_diag(): diagnose",
OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
- return(TRUE);
+ ret = TRUE;
#ifdef DEBUG_CONFIG_ERROR
printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
#endif
- return(FALSE);
+ return(ret);
} /* wv_diag */
/*------------------------------------------------------------------*/
@@ -951,15 +1006,6 @@ read_ringbuf(device * dev,
int chunk_len;
char * buf_ptr = buf;
-#ifdef OLDIES
- /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
- * quite safe to remove this... */
-
- /* If buf is NULL, just increment the ring buffer pointer */
- if(buf == NULL)
- return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
/* Get all the buffer */
while(len > 0)
{
@@ -990,70 +1036,32 @@ read_ringbuf(device * dev,
* wavelan_interrupt is not an option...), so you may experience
* some delay sometime...
*/
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device * dev)
{
- net_local *lp = (net_local *) dev->priv;
- dev_link_t *link = ((net_local *) dev->priv)->link;
+ net_local * lp = (net_local *)dev->priv;
+ dev_link_t * link = ((net_local *) dev->priv)->link;
+ unsigned long flags;
+
+ /* Arm the flag, will be cleard in wv_82593_config() */
+ lp->reconfig_82593 = TRUE;
- /* Check if we can do it now ! */
- if (!(link->open)) {
- lp->reconfig_82593 = TRUE;
+ /* Check if we can do it now ! */
+ if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+ {
+ wv_splhi(lp, &flags); /* Disable interrupts */
+ wv_82593_config(dev);
+ wv_splx(lp, &flags); /* Re-enable interrupts */
+ }
+ else
+ {
#ifdef DEBUG_IOCTL_INFO
- printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
- dev->name, link->open);
+ printk(KERN_DEBUG
+ "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+ dev->name, dev->state, link->open);
#endif
- } else {
- netif_stop_queue (dev);
-
- lp->reconfig_82593 = FALSE;
- wv_82593_config (dev);
- netif_wake_queue (dev);
- }
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
- ioaddr_t base = dev->base_addr;
- int i, c;
-
- /* disable receiver so we can use channel 1 */
- outb(OP0_RCV_DISABLE, LCCR(base));
-
- /* reset receive DMA pointer */
- hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
- hacr_write(base, HACR_DEFAULT);
-
- /* dump into receive buffer */
- wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
- /* set read pointer to start of receive buffer */
- outb(0, PIORL(base));
- outb(0, PIORH(base));
-
- printk(KERN_DEBUG "wavelan_cs: dump:\n");
- printk(KERN_DEBUG " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
- for(i = 0; i < 73; i++){
- if((i % 16) == 0) {
- printk("\n0x%02x:", i);
- if (!i) {
- printk(" ");
- continue;
- }
}
- c = inb(PIOP(base));
- printk("%02x ", c);
- }
- printk("\n");
-
- /* enable the receiver again */
- wv_ru_start(dev);
}
-#endif
/********************* DEBUG & INFO SUBROUTINES *********************/
/*
@@ -1171,6 +1179,8 @@ wv_mmc_show(device * dev)
return;
}
+ wv_splhi(lp, &flags);
+
/* Read the mmc */
mmc_out(base, mmwoff(0, mmw_freeze), 1);
mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1191,8 @@ wv_mmc_show(device * dev)
lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
#endif /* WIRELESS_EXT */
+ wv_splx(lp, &flags);
+
printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED
printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1277,7 @@ static void
wv_dev_show(device * dev)
{
printk(KERN_DEBUG "dev:");
+ printk(" state=%lX,", dev->state);
printk(" trans_start=%ld,", dev->trans_start);
printk(" flags=0x%x,", dev->flags);
printk("\n");
@@ -1404,7 +1417,7 @@ wv_init_info(device * dev)
printk("2430.5");
break;
default:
- printk("unknown");
+ printk("???");
}
}
@@ -1719,7 +1732,7 @@ wv_set_frequency(u_long base, /* i/o port of the card */
memcmp(dac, dac_verify, 2 * 2))
{
#ifdef DEBUG_IOCTL_ERROR
- printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
+ printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
#endif
return -EOPNOTSUPP;
}
@@ -1892,7 +1905,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
#endif
/* Disable interrupts & save flags */
- spin_lock_irqsave (&lp->lock, flags);
+ wv_splhi(lp, &flags);
/* Look what is the request */
switch(cmd)
@@ -1968,7 +1981,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
case SIOCGIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody XXX - especially old cards...) */
+ * (does it work for everybody ??? - especially old cards...) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
@@ -2239,15 +2252,17 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
{
struct iw_range range;
- /* Set the length (very important for backward compatibility) */
- wrq->u.data.length = sizeof(struct iw_range);
+ /* Set the length (very important for backward compatibility) */
+ wrq->u.data.length = sizeof(struct iw_range);
- /* Set all the info we don't care or don't know about to zero */
- memset(&range, 0, sizeof(range));
+ /* Set all the info we don't care or don't know about to zero */
+ memset(&range, 0, sizeof(range));
- /* Set the Wireless Extension versions */
- range.we_version_compiled = WIRELESS_EXT;
- range.we_version_source = 9; /* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+ /* Set the Wireless Extension versions */
+ range.we_version_compiled = WIRELESS_EXT;
+ range.we_version_source = 9; /* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
@@ -2517,7 +2532,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
}
/* ReEnable interrupts & restore flags */
- spin_unlock_irqrestore (&lp->lock, flags);
+ wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2558,8 @@ wavelan_get_wireless_stats(device * dev)
printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
#endif
- if (lp == NULL) /* XXX will this ever occur? */
- return NULL;
-
/* Disable interrupts & save flags */
- spin_lock_irqsave (&lp->lock, flags);
+ wv_splhi(lp, &flags);
wstats = &lp->wstats;
@@ -2573,7 +2585,7 @@ wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L;
/* ReEnable interrupts & restore flags */
- spin_unlock_irqrestore (&lp->lock, flags);
+ wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2704,6 @@ wv_packet_read(device * dev,
skb->protocol = eth_type_trans(skb, dev);
#ifdef DEBUG_RX_INFO
- /* Another glitch : Due to the way the GET_PACKET macro is written,
- * we are not sure to have the same thing in skb->data. On the other
- * hand, skb->mac.raw is not defined everywhere...
- * For versions between 1.2.13 and those where skb->mac.raw appear,
- * I don't have a clue...
- */
wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
#endif /* DEBUG_RX_INFO */
@@ -2731,9 +2737,7 @@ wv_packet_read(device * dev,
wl_roam_gather(dev, skb->data, stats);
#endif /* WAVELAN_ROAMING */
- /* Spying stuff */
#ifdef WIRELESS_SPY
- /* Same as above */
wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
#endif /* WIRELESS_SPY */
#ifdef HISTOGRAM
@@ -2766,6 +2770,7 @@ wv_packet_read(device * dev,
* called to do the actual transfer of the card's data including the
* ethernet header into a packet consisting of an sk_buff chain.
* (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
*/
static inline void
wv_packet_rcv(device * dev)
@@ -2916,7 +2921,7 @@ wv_packet_write(device * dev,
printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
#endif
- spin_lock_irqsave (&lp->lock, flags);
+ wv_splhi(lp, &flags);
/* Check if we need some padding */
if(clen < ETH_ZLEN)
@@ -2946,15 +2951,7 @@ wv_packet_write(device * dev,
/* Keep stats up to date */
lp->stats.tx_bytes += length;
- /* If watchdog not already active, activate it... */
- if (!timer_pending(&lp->watchdog))
- {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
-
- spin_unlock_irqrestore (&lp->lock, flags);
+ wv_splx(lp, &flags);
#ifdef DEBUG_TX_INFO
wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2960,57 @@ wv_packet_write(device * dev,
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
#endif
-
- netif_start_queue (dev);
}
/*------------------------------------------------------------------*/
/*
* This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
* the packet. We also prevent reentrance. Then, we call the function
* to send the packet...
*/
-static int wavelan_packet_xmit (struct sk_buff *skb,
- device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff * skb,
+ device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local * lp = (net_local *)dev->priv;
+ unsigned long flags;
#ifdef DEBUG_TX_TRACE
- printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
- (unsigned) skb);
+ printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+ (unsigned) skb);
#endif
- /*
- * For ethernet, fill in the header.
- */
+ /*
+ * Block a timer-based transmit from overlapping a previous transmit.
+ * In other words, prevent reentering this routine.
+ */
+ netif_stop_queue(dev);
- netif_stop_queue (dev);
+ /* If somebody has asked to reconfigure the controller,
+ * we can do it now */
+ if(lp->reconfig_82593)
+ {
+ wv_splhi(lp, &flags); /* Disable interrupts */
+ wv_82593_config(dev);
+ wv_splx(lp, &flags); /* Re-enable interrupts */
+ /* Note : the configure procedure was totally synchronous,
+ * so the Tx buffer is now free */
+ }
- /*
- * Block a timer-based transmit from overlapping a previous transmit.
- * In other words, prevent reentering this routine.
- */
- if (1) {
- /* If somebody has asked to reconfigure the controller, we can do it now */
- if (lp->reconfig_82593) {
- lp->reconfig_82593 = FALSE;
- wv_82593_config (dev);
- }
#ifdef DEBUG_TX_ERROR
- if (skb->next)
- printk (KERN_INFO "skb has next\n");
+ if (skb->next)
+ printk(KERN_INFO "skb has next\n");
#endif
- wv_packet_write (dev, skb->data, skb->len);
- }
- dev_kfree_skb (skb);
+ wv_packet_write(dev, skb->data, skb->len);
+
+ dev_kfree_skb(skb);
#ifdef DEBUG_TX_TRACE
- printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return (0);
+ return(0);
}
/********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3163,7 @@ wv_mmc_init(device * dev)
*/
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody XXX - especially old cards...) */
+ * (does it work for everybody ??? - especially old cards...) */
/* Note : WFREQSEL verify that it is able to read from EEprom
* a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
* is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3221,7 @@ static int
wv_ru_stop(device * dev)
{
ioaddr_t base = dev->base_addr;
- net_local *lp = (net_local *) dev->priv;
+ net_local * lp = (net_local *) dev->priv;
unsigned long flags;
int status;
int spin;
@@ -3232,35 +3230,35 @@ wv_ru_stop(device * dev)
printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
#endif
+ wv_splhi(lp, &flags);
+
/* First, send the LAN controller a stop receive command */
wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
OP0_STOP_RCV, SR0_NO_RESULT);
/* Then, spin until the receive unit goes idle */
- spin = 0;
+ spin = 300;
do
{
udelay(10);
- spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- spin_unlock_irqrestore (&lp->lock, flags);
}
- while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+ while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
/* Now, spin until the chip finishes executing its current command */
do
{
udelay(10);
- spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- spin_unlock_irqrestore (&lp->lock, flags);
}
- while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+ while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+ wv_splx(lp, &flags);
/* If there was a problem */
- if(spin > 300)
+ if(spin <= 0)
{
#ifdef DEBUG_CONFIG_ERROR
printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3285,7 @@ wv_ru_start(device * dev)
{
ioaddr_t base = dev->base_addr;
net_local * lp = (net_local *) dev->priv;
+ unsigned long flags;
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3299,8 @@ wv_ru_start(device * dev)
if(!wv_ru_stop(dev))
return FALSE;
+ wv_splhi(lp, &flags);
+
/* Now we know that no command is being executed. */
/* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3310,17 @@ wv_ru_start(device * dev)
/* Reset ring management. This sets the receive frame pointer to 1 */
outb(OP1_RESET_RING_MNGMT, LCCR(base));
+#if 0
+ /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+ should be set as below */
+ /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+ /* but I set it 0 instead */
+ lp->stop = 0;
+#else
/* but I set it to 3 bytes per packet less than 8K */
lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
outb(OP1_INT_ENABLE, LCCR(base));
outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3336,15 @@ wv_ru_start(device * dev)
#ifdef DEBUG_I82593_SHOW
{
int status;
- unsigned long flags;
- int i = 0;
+ int opri;
+ int spin = 10000;
/* spin until the chip starts receiving */
do
{
- spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- spin_unlock_irqrestore (&lp->lock, flags);
- if(i++ > 10000)
+ if(spin-- <= 0)
break;
}
while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3353,9 @@ wv_ru_start(device * dev)
(status & SR3_RCV_STATE_MASK), i);
}
#endif
+
+ wv_splx(lp, &flags);
+
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
#endif
@@ -3363,6 +3374,7 @@ wv_82593_config(device * dev)
ioaddr_t base = dev->base_addr;
net_local * lp = (net_local *) dev->priv;
struct i82593_conf_block cfblk;
+ int ret = TRUE;
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3469,7 @@ wv_82593_config(device * dev)
hacr_write(base, HACR_DEFAULT);
if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
OP0_CONFIGURE, SR0_CONFIGURE_DONE))
- return(FALSE);
+ ret = FALSE;
/* Initialize adapter's ethernet MAC address */
outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3483,7 @@ wv_82593_config(device * dev)
hacr_write(base, HACR_DEFAULT);
if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
OP0_IA_SETUP, SR0_IA_SETUP_DONE))
- return(FALSE);
+ ret = FALSE;
#ifdef WAVELAN_ROAMING
/* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3520,17 @@ wv_82593_config(device * dev)
hacr_write(base, HACR_DEFAULT);
if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
OP0_MC_SETUP, SR0_MC_SETUP_DONE))
- return(FALSE);
+ ret = FALSE;
lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */
}
+ /* Job done, clear the flag */
+ lp->reconfig_82593 = FALSE;
+
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
#endif
- return(TRUE);
+ return(ret);
}
/*------------------------------------------------------------------*/
@@ -3594,6 +3609,8 @@ wv_hw_config(device * dev)
{
net_local * lp = (net_local *) dev->priv;
ioaddr_t base = dev->base_addr;
+ unsigned long flags;
+ int ret = FALSE;
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3629,78 @@ wv_hw_config(device * dev)
if(wv_pcmcia_reset(dev) == FALSE)
return FALSE;
- /* Power UP the module + reset the modem + reset host adapter
- * (in fact, reset DMA channels) */
- hacr_write_slow(base, HACR_RESET);
- hacr_write(base, HACR_DEFAULT);
+ /* Disable interrupts */
+ wv_splhi(lp, &flags);
- /* Check if the module has been powered up... */
- if(hasr_read(base) & HASR_NO_CLK)
+ /* Disguised goto ;-) */
+ do
{
+ /* Power UP the module + reset the modem + reset host adapter
+ * (in fact, reset DMA channels) */
+ hacr_write_slow(base, HACR_RESET);
+ hacr_write(base, HACR_DEFAULT);
+
+ /* Check if the module has been powered up... */
+ if(hasr_read(base) & HASR_NO_CLK)
+ {
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
- dev->name);
+ printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+ dev->name);
#endif
- return FALSE;
- }
+ break;
+ }
- /* initialize the modem */
- if(wv_mmc_init(dev) == FALSE)
- return FALSE;
+ /* initialize the modem */
+ if(wv_mmc_init(dev) == FALSE)
+ {
+#ifdef DEBUG_CONFIG_ERRORS
+ printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+ dev->name);
+#endif
+ break;
+ }
- /* reset the LAN controller (i82593) */
- outb(OP0_RESET, LCCR(base));
- mdelay(1); /* A bit crude ! */
+ /* reset the LAN controller (i82593) */
+ outb(OP0_RESET, LCCR(base));
+ mdelay(1); /* A bit crude ! */
- /* Initialize the LAN controller */
- if((wv_82593_config(dev) == FALSE) ||
- (wv_diag(dev) == FALSE))
- {
+ /* Initialize the LAN controller */
+ if(wv_82593_config(dev) == FALSE)
+ {
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+ printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+ dev->name);
#endif
- return FALSE;
- }
+ break;
+ }
- /*
- * insert code for loopback test here
- */
+ /* Diagnostic */
+ if(wv_diag(dev) == FALSE)
+ {
+#ifdef DEBUG_CONFIG_ERRORS
+ printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+ dev->name);
+#endif
+ break;
+ }
+
+ /*
+ * insert code for loopback test here
+ */
- /* The device is now configured */
- lp->configured = 1;
+ /* The device is now configured */
+ lp->configured = 1;
+ ret = TRUE;
+ }
+ while(0);
+
+ /* Re-enable interrupts */
+ wv_splx(lp, &flags);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
#endif
- return TRUE;
+ return(ret);
}
/*------------------------------------------------------------------*/
@@ -3675,10 +3720,6 @@ wv_hw_reset(device * dev)
printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
#endif
- /* If watchdog was activated, kill it ! */
- if (timer_pending(&lp->watchdog))
- del_timer(&lp->watchdog);
-
lp->nresets++;
lp->configured = 0;
@@ -3786,13 +3827,13 @@ wv_pcmcia_config(dev_link_t * link)
}
/*
- * Allocate a 4K memory window. Note that the dev_link_t
+ * Allocate a small memory window. Note that the dev_link_t
* structure provides space for one window handle -- if your
* device needs several windows, you'll need to keep track of
* the handles in your private data structure, link->priv.
*/
req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
- req.Base = 0; req.Size = 0x1000;
+ req.Base = req.Size = 0;
req.AccessSpeed = mem_speed;
link->win = (window_handle_t)link->handle;
i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3844,7 @@ wv_pcmcia_config(dev_link_t * link)
}
dev->rmem_start = dev->mem_start =
- (u_long)ioremap(req.Base, 0x1000);
+ (u_long)ioremap(req.Base, req.Size);
dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3858,7 @@ wv_pcmcia_config(dev_link_t * link)
/* Feed device with this info... */
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- netif_start_queue (dev);
+ netif_start_queue(dev);
#ifdef DEBUG_CONFIG_INFO
printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3884,7 @@ wv_pcmcia_config(dev_link_t * link)
return FALSE;
}
- /* XXX Could you explain me this, Dave ? */
+ strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
link->dev = &((net_local *) dev->priv)->node;
#ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3928,7 @@ wv_pcmcia_release(u_long arg) /* Address of the interface struct */
CardServices(ReleaseIO, link->handle, &link->io);
CardServices(ReleaseIRQ, link->handle, &link->irq);
- link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+ link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3937,7 @@ wv_pcmcia_release(u_long arg) /* Address of the interface struct */
/*------------------------------------------------------------------*/
/*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
* cardmgr (device still open, pcmcia_release not done) and the device
* is put in a STALE_LINK state and remains in memory.
*
@@ -3970,7 +4011,19 @@ wavelan_interrupt(int irq,
lp = (net_local *) dev->priv;
base = dev->base_addr;
- spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+ /* Check state of our spinlock (it should be cleared) */
+ if(spin_is_locked(&lp->spinlock))
+ printk(KERN_DEBUG
+ "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+ dev->name);
+#endif
+
+ /* Prevent reentrancy. We need to do that because we may have
+ * multiple interrupt handler running concurently.
+ * It is safe because wv_splhi() disable interrupts before aquiring
+ * the spinlock. */
+ spin_lock(&lp->spinlock);
/* Treat all pending interrupts */
while(1)
@@ -4015,8 +4068,6 @@ wavelan_interrupt(int irq,
break;
}
- lp->status = status0; /* Save current status (for commands) */
-
/* ----------------- RECEIVING PACKET ----------------- */
/*
* When the wavelan signal the reception of a new packet,
@@ -4054,22 +4105,6 @@ wavelan_interrupt(int irq,
* Most likely : transmission done
*/
- /* If we are already waiting elsewhere for the command to complete */
- if(wv_wait_completed)
- {
-#ifdef DEBUG_INTERRUPT_INFO
- printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
- dev->name);
-#endif
-
- /* Signal command completion */
- wv_wait_completed = 0;
-
- /* Acknowledge the interrupt */
- outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
- continue;
- }
-
/* If a transmission has been done */
if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
(status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4116,6 @@ wavelan_interrupt(int irq,
dev->name);
#endif
- /* If watchdog was activated, kill it ! */
- if(timer_pending(&lp->watchdog))
- del_timer(&lp->watchdog);
-
/* Get transmission status */
tx_status = inb(LCSR(base));
tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4205,7 @@ wavelan_interrupt(int irq,
lp->stats.collisions += (tx_status & TX_NCOL_MASK);
lp->stats.tx_packets++;
- netif_wake_queue (dev);
+ netif_wake_queue(dev);
outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */
}
else /* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4216,9 @@ wavelan_interrupt(int irq,
#endif
outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */
}
- }
+ } /* while(1) */
- spin_unlock_irq (&lp->lock);
+ spin_unlock(&lp->spinlock);
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4227,23 @@ wavelan_interrupt(int irq,
/*------------------------------------------------------------------*/
/*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel. If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel. If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
*
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
*/
static void
-wavelan_watchdog(u_long a)
+wavelan_watchdog(device * dev)
{
- device * dev;
- net_local * lp;
- ioaddr_t base;
- int spin;
-
- dev = (device *) a;
- base = dev->base_addr;
- lp = (net_local *) dev->priv;
+ net_local * lp = (net_local *) dev->priv;
+ ioaddr_t base = dev->base_addr;
+ unsigned long flags;
+ int aborted = FALSE;
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4254,21 @@ wavelan_watchdog(u_long a)
dev->name);
#endif
- /* We are waiting for command completion */
- wv_wait_completed = TRUE;
+ wv_splhi(lp, &flags);
/* Ask to abort the current command */
outb(OP0_ABORT, LCCR(base));
- /* Busy wait while the LAN controller executes the command.
- * Note : wv_wait_completed should be volatile */
- spin = 0;
- while(wv_wait_completed && (spin++ < 250))
- udelay(10);
+ /* Wait for the end of the command (a bit hackish) */
+ if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+ OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+ aborted = TRUE;
+
+ /* Release spinlock here so that wv_hw_reset() can grab it */
+ wv_splx(lp, &flags);
- /* If the interrupt handler hasn't be called or invalid status */
- if((wv_wait_completed) ||
- ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+ /* Check if we were successful in aborting it */
+ if(!aborted)
{
/* It seem that it wasn't enough */
#ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4293,7 @@ wavelan_watchdog(u_long a)
#endif
/* We are no more waiting for something... */
- netif_start_queue (dev);
+ netif_wake_queue(dev);
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4346,7 @@ wavelan_open(device * dev)
return FALSE;
if(!wv_ru_start(dev))
wv_hw_reset(dev); /* If problem : reset */
- netif_start_queue (dev);
+ netif_start_queue(dev);
/* Mark the device as used */
link->open++;
@@ -4348,7 +4372,6 @@ static int
wavelan_close(device * dev)
{
dev_link_t * link = ((net_local *) dev->priv)->link;
- net_local * lp = (net_local *)dev->priv;
ioaddr_t base = dev->base_addr;
#ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4379,6 @@ wavelan_close(device * dev)
(unsigned int) dev);
#endif
- netif_stop_queue (dev);
-
/* If the device isn't open, then nothing to do */
if(!link->open)
{
@@ -4373,17 +4394,13 @@ wavelan_close(device * dev)
wv_roam_cleanup(dev);
#endif /* WAVELAN_ROAMING */
- /* If watchdog was activated, kill it ! */
- if(timer_pending(&lp->watchdog))
- del_timer(&lp->watchdog);
-
link->open--;
MOD_DEC_USE_COUNT;
/* If the card is still present */
- if (netif_device_present(dev))
+ if(netif_running(dev))
{
- netif_stop_queue (dev);
+ netif_stop_queue(dev);
/* Stop receiving new messages and wait end of transmission */
wv_ru_stop(dev);
@@ -4404,21 +4421,6 @@ wavelan_close(device * dev)
/*------------------------------------------------------------------*/
/*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device * dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
- return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
* wavelan_attach() creates an "instance" of the driver, allocating
* local data structures for one device (one interface). The device
* is registered with Card Services.
@@ -4445,24 +4447,8 @@ wavelan_attach(void)
/* Initialize the dev_link_t structure */
link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
- if (!link)
- return NULL;
-
- /* Allocate the generic data structure */
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- if (!dev)
- goto fail_alloc_dev;
-
- /* Allocate the wavelan-specific data structure. */
- lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
- if (!lp)
- goto fail_alloc_dev_priv;
-
- memset(lp, 0, sizeof(net_local));
+ if (!link) return NULL;
memset(link, 0, sizeof(struct dev_link_t));
- memset(dev, 0, sizeof(struct net_device));
-
- dev->priv = lp;
/* Unused for the Wavelan */
link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4478,35 @@ wavelan_attach(void)
link->next = dev_list;
dev_list = link;
+ /* Allocate the generic data structure */
+ dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (!dev) {
+ kfree(link);
+ return NULL;
+ }
+ memset(dev, 0x00, sizeof(struct net_device));
link->priv = link->irq.Instance = dev;
+ /* Allocate the wavelan-specific data structure. */
+ dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+ if (!lp) {
+ kfree(link);
+ kfree(dev);
+ return NULL;
+ }
+ memset(lp, 0x00, sizeof(net_local));
+
/* Init specific data */
- wv_wait_completed = 0;
- lp->status = FALSE;
lp->configured = 0;
lp->reconfig_82593 = FALSE;
lp->nresets = 0;
+ /* Multicast stuff */
+ lp->promiscuous = 0;
+ lp->allmulticast = 0;
+ lp->mc_count = 0;
- /* Set the watchdog timer */
- lp->watchdog.function = wavelan_watchdog;
- lp->watchdog.data = (unsigned long) dev;
+ /* Init spinlock */
+ spin_lock_init(&lp->spinlock);
/* back links */
lp->link = link;
@@ -4513,7 +4516,6 @@ wavelan_attach(void)
ether_setup(dev);
/* wavelan NET3 callbacks */
- dev->init = &wavelan_init;
dev->open = &wavelan_open;
dev->stop = &wavelan_close;
dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4525,16 @@ wavelan_attach(void)
dev->set_mac_address = &wavelan_set_mac_address;
#endif /* SET_MAC_ADDRESS */
+ /* Set the watchdog timer */
+ dev->tx_timeout = &wavelan_watchdog;
+ dev->watchdog_timeo = WATCHDOG_JIFFIES;
+
#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
dev->do_ioctl = wavelan_ioctl; /* wireless extensions */
dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif
/* Other specific data */
- strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
- netif_start_queue (dev);
dev->mtu = WAVELAN_MTU;
/* Register with Card Services */
@@ -4562,12 +4566,6 @@ wavelan_attach(void)
#endif
return link;
-
-fail_alloc_dev_priv:
- kfree(dev);
-fail_alloc_dev:
- kfree(link);
- return NULL;
}
/*------------------------------------------------------------------*/
@@ -4698,7 +4696,7 @@ wavelan_event(event_t event, /* The event received */
if(link->state & DEV_CONFIG)
{
/* Accept no more transmissions */
- netif_device_detach(dev);
+ netif_device_detach(dev);
/* Release the card */
wv_pcmcia_release((u_long) link);
@@ -4720,7 +4718,7 @@ wavelan_event(event_t event, /* The event received */
* obliged to close nicely the wavelan here. David, could you
* close the device before suspending them ? And, by the way,
* could you, on resume, add a "route add -net ..." after the
- * ifconfig up XXX Thanks... */
+ * ifconfig up ??? Thanks... */
/* Stop receiving new messages and wait end of transmission */
wv_ru_stop(dev);
@@ -4735,8 +4733,7 @@ wavelan_event(event_t event, /* The event received */
if(link->state & DEV_CONFIG)
{
if(link->open)
- netif_device_detach(dev);
-
+ netif_device_detach(dev);
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -4748,7 +4745,7 @@ wavelan_event(event_t event, /* The event received */
if(link->state & DEV_CONFIG)
{
CardServices(RequestConfiguration, link->handle, &link->conf);
- if(link->open) /* If RESET -> True, If RESUME -> False XXX */
+ if(link->open) /* If RESET -> True, If RESUME -> False ??? */
{
wv_hw_reset(dev);
netif_device_attach(dev);
@@ -4838,4 +4835,3 @@ exit_wavelan_cs(void)
module_init(init_wavelan_cs);
module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/pcmcia/wavelan.h b/drivers/net/wireless/wavelan_cs.h
index 2d03b182c..755df6f7c 100644
--- a/drivers/net/pcmcia/wavelan.h
+++ b/drivers/net/wireless/wavelan_cs.h
@@ -52,8 +52,8 @@
* Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
*/
-#ifndef _WAVELAN_H
-#define _WAVELAN_H
+#ifndef _WAVELAN_CS_H
+#define _WAVELAN_CS_H
/************************** MAGIC NUMBERS ***************************/
@@ -88,6 +88,7 @@ const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
*/
const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+
/*************************** PC INTERFACE ****************************/
/* WaveLAN host interface definitions */
@@ -316,6 +317,7 @@ struct mmw_t
/* Calculate offset of a field in the above structure */
#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
+
/*
* Modem Management Controller (MMC) read structure.
*/
@@ -373,6 +375,7 @@ struct mmr_t
/* Calculate offset of a field in the above structure */
#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
/* Make the two above structures one */
typedef union mm_t
{
@@ -380,4 +383,4 @@ typedef union mm_t
struct mmr_t r; /* Read from the mmc */
} mm_t;
-#endif /* _WAVELAN_H */
+#endif /* _WAVELAN_CS_H */
diff --git a/drivers/net/pcmcia/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.p.h
index 6b613414c..67b19932a 100644
--- a/drivers/net/pcmcia/wavelan_cs.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -10,8 +10,8 @@
* be included only on wavelan_cs.c !!!
*/
-#ifndef WAVELAN_CS_H
-#define WAVELAN_CS_H
+#ifndef WAVELAN_CS_P_H
+#define WAVELAN_CS_P_H
/************************** DOCUMENTATION **************************/
/*
@@ -34,6 +34,25 @@
* I try to maintain a web page with the Wireless LAN Howto at :
* http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
*
+ * SMP
+ * ---
+ * We now are SMP compliant (I eventually fixed the remaining bugs).
+ * The driver has been tested on a dual P6-150 and survived my usual
+ * set of torture tests.
+ * Anyway, I spent enough time chasing interrupt re-entrancy during
+ * errors or reconfigure, and I designed the locked/unlocked sections
+ * of the driver with great care, and with the recent addition of
+ * the spinlock (thanks to the new API), we should be quite close to
+ * the truth.
+ * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ * but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ * I have also looked into disabling only our interrupt on the card
+ * (via HACR) instead of all interrupts in the processor (via cli),
+ * so that other driver are not impacted, and it look like it's
+ * possible, but it's very tricky to do right (full of races). As
+ * the gain would be mostly for SMP systems, it can wait...
+ *
* Debugging and options
* ---------------------
* You will find below a set of '#define" allowing a very fine control
@@ -57,7 +76,7 @@
* The detection code of the wavelan chech that the first 3
* octets of the MAC address fit the company code. This type of
* detection work well for AT&T cards (because the AT&T code is
- * hardcoded in wavelan.h), but of course will fail for other
+ * hardcoded in wavelan_cs.h), but of course will fail for other
* manufacturer.
*
* If you are sure that your card is derived from the wavelan,
@@ -67,7 +86,7 @@
* b) With the driver :
* o compile the kernel with DEBUG_CONFIG_INFO enabled
* o Boot and look the card messages
- * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
+ * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan_cs.h)
* 3) Compile & verify
* 4) Send me the MAC code - I will include it in the next version...
*
@@ -92,9 +111,9 @@
/*
* wavelan_cs.c : The actual code for the driver - C functions
*
- * wavelan_cs.h : Private header : local types / vars for the driver
+ * wavelan_cs.p.h : Private header : local types / vars for the driver
*
- * wavelan.h : Description of the hardware interface & structs
+ * wavelan_cs.h : Description of the hardware interface & structs
*
* i82593.h : Description if the Ethernet controller
*/
@@ -122,7 +141,7 @@
* Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
* Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
* correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
* Pcmcia package (+ bug corrections).
*
* I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
@@ -158,8 +177,8 @@
*
* This software was originally developed under Linux 1.2.3
* (Slackware 2.0 distribution).
- * And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- * HP OmniBook 4000 & 5500.
+ * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ * with an HP OmniBook 4000 and then a 5500.
*
* It is based on other device drivers and information either written
* or supplied by:
@@ -174,7 +193,7 @@
* Matthew Geier (matthew@cs.su.oz.au),
* Remo di Giovanni (remo@cs.su.oz.au),
* Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- * David Hinds <dhinds@pcmcia.sourceforge.org>,
+ * David Hinds <dahinds@users.sourceforge.net>,
* Jan Hoogendoorn (c/o marteijn@lucent.com),
* Bruce Janson <bruce@cs.usyd.edu.au>,
* Anthony D. Joseph <adj@lcs.mit.edu>,
@@ -349,6 +368,32 @@
* - Fix check for root permission (break instead of exit)
* - New nwid & encoding setting (Wireless Extension 9)
*
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ * - reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ * ugly things with interrupts.
+ * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ * - Update to new network API (softnet - 2.3.43) :
+ * o replace dev->tbusy (David + me)
+ * o replace dev->tstart (David + me)
+ * o remove dev->interrupt (David)
+ * o add SMP locking via spinlock in splxx (me)
+ * o add spinlock in interrupt handler (me)
+ * o use kernel watchdog instead of ours (me)
+ * o verify that all the changes make sense and work (me)
+ * - Re-sync kernel/pcmcia versions (not much actually)
+ * - A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ * - Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ * - Fix unfrequent card lockup when watchdog was reseting the hardware :
+ * o control first busy loop in wv_82593_cmd()
+ * o Extend spinlock protection in wv_hw_config()
+ *
* Wishes & dreams:
* ----------------
* - Cleanup and integrate the roaming code
@@ -368,6 +413,7 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
+#include <linux/spinlock.h>
#include <linux/in.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
@@ -382,9 +428,9 @@
#include <linux/ioport.h>
#include <linux/fcntl.h>
-#ifdef CONFIG_NET_PCMCIA_RADIO
+#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Wireless extensions */
-#endif /* CONFIG_NET_PCMCIA_RADIO */
+#endif
/* Pcmcia headers that we need */
#include <pcmcia/cs_types.h>
@@ -397,7 +443,7 @@
/* Wavelan declarations */
#include "i82593.h" /* Definitions for the Intel chip */
-#include "wavelan.h" /* Others bits of the hardware */
+#include "wavelan_cs.h" /* Others bits of the hardware */
/************************** DRIVER OPTIONS **************************/
/*
@@ -437,7 +483,7 @@
#undef DEBUG_RX_INFO /* Header of the transmitted packet */
#undef DEBUG_RX_FAIL /* Normal failure conditions */
#define DEBUG_RX_ERROR /* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */
#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */
#undef DEBUG_IOCTL_INFO /* Various debug info */
#define DEBUG_IOCTL_ERROR /* What's going wrong */
@@ -452,7 +498,7 @@
/************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
#endif
/* Watchdog temporisation */
@@ -557,9 +603,9 @@ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */
*/
struct net_local
{
- spinlock_t lock;
dev_node_t node; /* ???? What is this stuff ???? */
device * dev; /* Reverse link... */
+ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */
dev_link_t * link; /* pcmcia structure */
en_stats stats; /* Ethernet interface statistics */
int nresets; /* Number of hw resets */
@@ -568,9 +614,7 @@ struct net_local
u_char promiscuous; /* Promiscuous mode */
u_char allmulticast; /* All Multicast mode */
int mc_count; /* Number of multicast addresses */
- timer_list watchdog; /* To avoid blocking state */
- u_char status; /* Current i82593 status */
int stop; /* Current i82593 Stop Hit Register */
int rfp; /* Last DMA machine receive pointer */
int overrunning; /* Receiver overrun flag */
@@ -617,8 +661,14 @@ void wv_roam_cleanup(struct net_device *dev);
#endif /* WAVELAN_ROAMING */
/* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+ wv_splhi(net_local *, /* Disable interrupts */
+ unsigned long *); /* flags */
+static inline void
+ wv_splx(net_local *, /* ReEnable interrupts */
+ unsigned long *); /* flags */
static void
- cs_error(client_handle_t, /* Report error to cardmgr */
+ cs_error(client_handle_t, /* Report error to cardmgr */
int,
int);
/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
@@ -722,16 +772,15 @@ static void
wv_flush_stale_links(void); /* "detach" all possible devices */
/* ---------------------- INTERRUPT HANDLING ---------------------- */
static void
-wavelan_interrupt(int, /* Interrupt handler */
- void *,
- struct pt_regs *);
+ wavelan_interrupt(int, /* Interrupt handler */
+ void *,
+ struct pt_regs *);
static void
- wavelan_watchdog(u_long); /* Transmission watchdog */
+ wavelan_watchdog(device *); /* Transmission watchdog */
/* ------------------- CONFIGURATION CALLBACKS ------------------- */
static int
wavelan_open(device *), /* Open the device */
- wavelan_close(device *), /* Close the device */
- wavelan_init(device *); /* Do nothing */
+ wavelan_close(device *); /* Close the device */
static dev_link_t *
wavelan_attach(void); /* Create a new device */
static void
@@ -744,11 +793,7 @@ static int
/**************************** VARIABLES ****************************/
static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list; /* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */
-static volatile int wv_wait_completed;
+static dev_link_t *dev_list = NULL; /* Linked list of devices */
/*
* Parameters that can be set with 'insmod'
@@ -761,7 +806,7 @@ static int irq_mask = 0xdeb8;
static int irq_list[4] = { -1 };
/* Shared memory speed, in ns */
-static int mem_speed;
+static int mem_speed = 0;
/* New module interface */
MODULE_PARM(irq_mask, "i");
@@ -770,9 +815,11 @@ MODULE_PARM(mem_speed, "i");
#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */
/* Enable roaming mode ? No ! Please keep this to 0 */
-static int do_roaming;
+static int do_roaming = 0;
MODULE_PARM(do_roaming, "i");
#endif /* WAVELAN_ROAMING */
-#endif /* WAVELAN_CS_H */
+MODULE_LICENSE("GPL");
+
+#endif /* WAVELAN_CS_P_H */
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index 129450bf6..f5ed5694b 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,23 @@
+2001-12-07 Tim Waugh <twaugh@redhat.com>
+
+ * ieee1284_ops.c (parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr): Actually do something useful.
+
+2001-12-07 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (dmaval): Don't use DMA by default. It seems to be
+ too buggy at the moment. Use 'dma=auto' to restore the previous
+ behaviour.
+
+2001-12-03 Rich Liu <Rich.Liu@ite.com.tw>
+
+ * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port
+ serial board, not a serial+parallel.
+
+2001-11-30 Niels Kristian Bech Jensen <nkbj@image.dk>
+
+ * parport_pc.c: Fix compiler warning.
+
2001-12-06 Tim Waugh <twaugh@redhat.com>
* ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 1000fe088..fa32e7696 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -128,7 +128,7 @@ int parport_poll_peripheral(struct parport *port,
return 0;
if (signal_pending (current))
return -EINTR;
- if (current->need_resched)
+ if (need_resched())
break;
if (i >= 2)
udelay (5);
diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c
index 8fcd6f2f1..23263479e 100644
--- a/drivers/parport/ieee1284_ops.c
+++ b/drivers/parport/ieee1284_ops.c
@@ -136,7 +136,7 @@ size_t parport_ieee1284_write_compat (struct parport *port,
/* Let another process run if it needs to. */
if (time_before (jiffies, expire))
if (!parport_yield_blocking (dev)
- && current->need_resched)
+ && need_resched())
schedule ();
}
stop:
@@ -824,35 +824,40 @@ size_t parport_ieee1284_epp_write_addr (struct parport *port,
const void *buffer, size_t len,
int flags)
{
- /* This is untested */
unsigned char *bp = (unsigned char *) buffer;
size_t ret = 0;
+ /* set EPP idle state (just to make sure) with strobe low */
parport_frob_control (port,
PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
PARPORT_CONTROL_SELECT |
- PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_INIT,
PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_SELECT);
+ PARPORT_CONTROL_INIT);
port->ops->data_forward (port);
for (; len > 0; len--, bp++) {
- /* Write data and assert nAStrb. */
+ /* Event 56: Write data and set nAStrb low. */
parport_write_data (port, *bp);
parport_frob_control (port, PARPORT_CONTROL_SELECT,
PARPORT_CONTROL_SELECT);
- if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY, 10))
+ /* Event 58: wait for busy (nWait) to go high */
+ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
break;
+ /* Event 59: set nAStrb high */
parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
- if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+ /* Event 60: wait for busy (nWait) to go low */
+ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY, 5))
break;
ret++;
}
+ /* Event 61: set strobe (nWrite) high */
parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
return ret;
@@ -863,28 +868,36 @@ size_t parport_ieee1284_epp_read_addr (struct parport *port,
void *buffer, size_t len,
int flags)
{
- /* This is untested. */
unsigned char *bp = (unsigned char *) buffer;
unsigned ret = 0;
+ /* Set EPP idle state (just to make sure) with strobe high */
parport_frob_control (port,
PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD, 0);
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
port->ops->data_reverse (port);
for (; len > 0; len--, bp++) {
- parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+ /* Event 64: set nSelectIn (nAStrb) low */
+ parport_frob_control (port, PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
- /* Event 58 */
- if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY, 10))
+ /* Event 58: wait for Busy to go high */
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
break;
+ }
*bp = parport_read_data (port);
+ /* Event 59: set nSelectIn (nAStrb) high */
parport_frob_control (port, PARPORT_CONTROL_SELECT,
PARPORT_CONTROL_SELECT);
- if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+ /* Event 60: wait for Busy to go low */
+ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY, 5))
break;
ret++;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 0c5c82a3b..45e1abded 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -91,7 +91,9 @@ static struct superio_struct { /* For Super-IO chips autodetection */
} superios[NR_SUPERIOS] __devinitdata = { {0,},};
static int user_specified __devinitdata = 0;
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
static int verbose_probing;
+#endif
static int registered_parport;
/* frob_control, but for ECR */
@@ -596,7 +598,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
unsigned char ecrval = inb (ECONTROL (port));
int i = 0;
- if (current->need_resched && time_before (jiffies, expire))
+ if (need_resched() && time_before (jiffies, expire))
/* Can't yield the port. */
schedule ();
@@ -622,7 +624,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
}
ecrval = inb (ECONTROL (port));
if (!(ecrval & (1<<2))) {
- if (current->need_resched &&
+ if (need_resched() &&
time_before (jiffies, expire))
schedule ();
@@ -746,8 +748,7 @@ dump_parport_state ("enter fifo_write_block_dma", port);
}
/* Is serviceIntr set? */
if (!(inb (ECONTROL (port)) & (1<<2))) {
- if (current->need_resched)
- schedule ();
+ cond_resched();
goto false_alarm;
}
@@ -758,9 +759,7 @@ dump_parport_state ("enter fifo_write_block_dma", port);
count = get_dma_residue(port->dma);
release_dma_lock(dmaflag);
- if (current->need_resched)
- /* Can't yield the port. */
- schedule ();
+ cond_resched(); /* Can't yield the port. */
/* Anyone else waiting for the port? */
if (port->waithead) {
@@ -1093,7 +1092,7 @@ dump_parport_state ("rev idle", port);
long int expire = jiffies + port->cad->timeout;
unsigned char ecrval = inb (ECONTROL (port));
- if (current->need_resched && time_before (jiffies, expire))
+ if (need_resched() && time_before (jiffies, expire))
/* Can't yield the port. */
schedule ();
@@ -1130,7 +1129,7 @@ dump_parport_state ("timeout", port);
}
ecrval = inb (ECONTROL (port));
if (!(ecrval & (1<<2))) {
- if (current->need_resched &&
+ if (need_resched() &&
time_before (jiffies, expire)) {
schedule ();
}
@@ -1780,6 +1779,7 @@ static int __devinit parport_PS2_supported(struct parport *pb)
return ok;
}
+#ifdef CONFIG_PARPORT_PC_FIFO
static int __devinit parport_ECP_supported(struct parport *pb)
{
int i;
@@ -1905,6 +1905,7 @@ static int __devinit parport_ECP_supported(struct parport *pb)
return 1;
}
+#endif
static int __devinit parport_ECPPS2_supported(struct parport *pb)
{
@@ -2004,7 +2005,9 @@ static int __devinit parport_ECPEPP_supported(struct parport *pb)
/* Don't bother probing for modes we know we won't use. */
static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+#ifdef CONFIG_PARPORT_PC_FIFO
static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+#endif
static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
@@ -2453,9 +2456,8 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
ite8872set = 0x64e00000;
break;
case 0x6:
- printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n");
- ite8872set = 0x64a00000;
- break;
+ printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+ return 0;
case 0x8:
DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
return 0;
@@ -3007,7 +3009,7 @@ EXPORT_SYMBOL (parport_pc_unregister_port);
static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
static int io_hi[PARPORT_PC_MAX_PORTS+1] =
{ [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
@@ -3024,8 +3026,10 @@ MODULE_PARM_DESC(irq, "IRQ line");
MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
MODULE_PARM_DESC(dma, "DMA channel");
MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(verbose_probing, "i");
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
+MODULE_PARM(verbose_probing, "i");
+#endif
int init_module(void)
{
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 095609cf5..4a30ce9aa 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G" /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GG" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -670,6 +670,9 @@
1. Return an error from narrow boards if passed a 16 byte
CDB. The wide board can already handle 16 byte CDBs.
+ 3.3GG (01/02/02):
+ 1. hacks for lk 2.5 series (D. Gilbert)
+
I. Known Problems/Fix List (XXX)
1. Need to add memory mapping workaround. Test the memory mapping.
@@ -3611,6 +3614,23 @@ typedef struct {
#define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* CONFIG_PROC_FS */
+/*
+ * XXX - Release and acquire the io_request_lock. These macros are needed
+ * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
+ * on entry to SCSI low-level drivers.
+ *
+ * These definitions and all code that uses code should be removed when the
+ * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
+ * SCSI low-level driver detect, queuecommand, and reset entrypoints.
+ *
+ * The interrupt flags values doesn't matter in the macros because the
+ * SCSI mid-level will save and restore the flags values before and after
+ * calling advansys_detect, advansys_queuecommand, and advansys_reset where
+ * these macros are used. We do want interrupts enabled after the lock is
+ * released so an explicit sti() is done. The driver only needs interrupts
+ * disabled when it acquires the per board lock.
+ */
+
/* Asc Library return codes */
#define ASC_TRUE 1
#define ASC_FALSE 0
@@ -4055,6 +4075,7 @@ typedef struct asc_board {
ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
} eep_config;
ulong last_reset; /* Saved last reset time */
+ spinlock_t lock; /* Board spinlock */
#ifdef CONFIG_PROC_FS
/* /proc/scsi/advansys/[0...] */
char *prtbuf; /* /proc print buffer */
@@ -4207,7 +4228,7 @@ STATIC PortAddr _asc_def_iop_base[];
STATIC void advansys_interrupt(int, void *, struct pt_regs *);
STATIC void advansys_select_queue_depths(struct Scsi_Host *,
Scsi_Device *);
-STATIC void asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *);
STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *);
STATIC int adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4800,6 +4821,9 @@ advansys_detect(Scsi_Host_Template *tpnt)
memset(boardp, 0, sizeof(asc_board_t));
boardp->id = asc_board_count - 1;
+ /* Initialize spinlock. */
+ boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */
+
/*
* Handle both narrow and wide boards.
*
@@ -5512,7 +5536,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
}
} else {
ADV_CARR_T *carrp;
- int req_cnt;
+ int req_cnt = 0;
adv_req_t *reqp = NULL;
int sg_cnt = 0;
@@ -5846,7 +5870,9 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
boardp = ASC_BOARDP(shp);
ASC_STATS(shp, queuecommand);
- spin_lock_irqsave(&shp->host_lock, flags);
+ /* host_lock taken by mid-level prior to call but need to protect */
+ /* against own ISR */
+ spin_lock_irqsave(&boardp->lock, flags);
/*
* Block new commands while handling a reset or abort request.
@@ -5863,7 +5889,7 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
* handling.
*/
asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
return 0;
}
@@ -5903,11 +5929,11 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
default:
done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
/* Interrupts could be enabled here. */
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp, 0);
break;
}
+ spin_unlock_irqrestore(&boardp->lock, flags);
- spin_unlock_irqrestore(&shp->host_lock, flags);
return 0;
}
@@ -5953,13 +5979,13 @@ advansys_reset(Scsi_Cmnd *scp)
/*
* Check for re-entrancy.
*/
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
return FAILED;
}
boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
if (ASC_NARROW_BOARD(boardp)) {
/*
@@ -5990,11 +6016,7 @@ advansys_reset(Scsi_Cmnd *scp)
}
ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
- /*
- * Acquire the board lock.
- */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
} else {
/*
@@ -6021,14 +6043,9 @@ advansys_reset(Scsi_Cmnd *scp)
ret = FAILED;
break;
}
- /*
- * Acquire the board lock and ensure all requests completed by the
- * microcode have been processed by calling AdvISR().
- */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
(void) AdvISR(adv_dvc_varp);
}
-
/* Board lock is held. */
/*
@@ -6089,15 +6106,13 @@ advansys_reset(Scsi_Cmnd *scp)
/* Clear reset flag. */
boardp->flags &= ~ASC_HOST_IN_RESET;
-
- /* Release the board. */
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
/*
* Complete all the 'done_scp' requests.
*/
if (done_scp != NULL) {
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp, 0);
}
ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6260,6 +6275,7 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
asc_board_t *boardp;
Scsi_Cmnd *done_scp = NULL, *last_scp = NULL;
Scsi_Cmnd *new_last_scp;
+ struct Scsi_Host *shp;
ASC_DBG(1, "advansys_interrupt: begin\n");
@@ -6268,17 +6284,17 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* AscISR() will call asc_isr_callback().
*/
for (i = 0; i < asc_board_count; i++) {
- struct Scsi_Host *shp = asc_host[i];
+ shp = asc_host[i];
boardp = ASC_BOARDP(shp);
ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
i, (ulong) boardp);
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
if (ASC_NARROW_BOARD(boardp)) {
/*
* Narrow Board
*/
- if (AscIsIntPending(asc_host[i]->io_port)) {
- ASC_STATS(asc_host[i], interrupt);
+ if (AscIsIntPending(shp->io_port)) {
+ ASC_STATS(shp, interrupt);
ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
AscISR(&boardp->dvc_var.asc_dvc_var);
}
@@ -6288,7 +6304,7 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(asc_host[i], interrupt);
+ ASC_STATS(shp, interrupt);
}
}
@@ -6328,7 +6344,7 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
}
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
}
/*
@@ -6337,7 +6353,8 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*
* Complete all requests on the done list.
*/
- asc_scsi_done_list(done_scp);
+
+ asc_scsi_done_list(done_scp, 1);
ASC_DBG(1, "advansys_interrupt: end\n");
return;
@@ -6384,9 +6401,10 @@ advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
* Interrupts can be enabled on entry.
*/
STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
{
Scsi_Cmnd *tscp;
+ ulong flags = 0;
ASC_DBG(2, "asc_scsi_done_list: begin\n");
while (scp != NULL) {
@@ -6395,7 +6413,11 @@ asc_scsi_done_list(Scsi_Cmnd *scp)
REQPNEXT(scp) = NULL;
ASC_STATS(scp->host, done);
ASC_ASSERT(scp->scsi_done != NULL);
+ if (from_isr)
+ spin_lock_irqsave(&scp->host->host_lock, flags);
scp->scsi_done(scp);
+ if (from_isr)
+ spin_unlock_irqrestore(&scp->host->host_lock, flags);
scp = tscp;
}
ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6729,7 +6751,9 @@ asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
slp = (struct scatterlist *) scp->request_buffer;
for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
asc_sg_head.sg_list[sgcnt].addr =
- cpu_to_le32(virt_to_bus(slp->address));
+ cpu_to_le32(virt_to_bus(slp->address ?
+ (unsigned char *)slp->address :
+ (unsigned char *)page_address(slp->page) + slp->offset));
asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
}
@@ -6987,7 +7011,9 @@ adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
{
sg_block->sg_list[i].sg_addr =
- cpu_to_le32(virt_to_bus(slp->address));
+ cpu_to_le32(virt_to_bus(slp->address ?
+ (unsigned char *)slp->address :
+ (unsigned char *)page_address(slp->page) + slp->offset));
sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index fd7222fbd..220f5aab8 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -3,8 +3,19 @@
*
* Copyright (C) 1992 Eric Youngdale
* Simulate a host adapter with 2 disks attached. Do a lot of checking
- * to make sure that we are not getting blocks mixed up, and panic if
+ * to make sure that we are not getting blocks mixed up, and PANIC if
* anything out of the ordinary is seen.
+ *
+ * This version is more generic, simulating a variable number of disk
+ * (or disk like devices) sharing a common amount of RAM (default 8 MB
+ * but can be set at driver/module load time).
+ *
+ * For documentation see http://www.torque.net/sg/sdebug.html
+ *
+ * D. Gilbert (dpg) work for MOD device test [20010421]
+ * dpg, work for devfs large number of disks [20010809]
+ * dpg, make more generic [20011123]
+ * dpg, forked for lk 2.5 series [20011216, 20020101]
*/
#include <linux/config.h>
@@ -18,7 +29,9 @@
#include <linux/string.h>
#include <linux/genhd.h>
#include <linux/fs.h>
+#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -27,190 +40,185 @@
#include "scsi.h"
#include "hosts.h"
-#include "sd.h"
-
#include<linux/stat.h>
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+static char scsi_debug_version_str[] = "Version: 1.57 (20011216)";
+
+#ifndef SCSI_CMD_READ_16
+#define SCSI_CMD_READ_16 0x88
+#endif
+#ifndef SCSI_CMD_WRITE_16
+#define SCSI_CMD_WRITE_16 0x8a
+#endif
+
/* A few options that we want selected */
+#define DEF_NR_FAKE_DEVS 1
+#define DEF_DEV_SIZE_MB 8
+#define DEF_FAKE_BLK0 0
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS 3
-#define N_HEAD 255
-#define N_SECTOR 63
-#define N_CYLINDER 524
+static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
+
+#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+#define N_HEAD 8
+#define N_SECTOR 32
#define DISK_READONLY(TGT) (0)
-#define DISK_REMOVEABLE(TGT) (1)
-#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+#define DISK_REMOVEABLE(TGT) (0)
+#define DEVICE_TYPE(TGT) (TYPE_DISK);
+
+#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+#define STORE_ELEM_ORDER 1
+#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
+#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+
+#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
+
+static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
/* Do not attempt to use a timer to simulate a real disk with latency */
/* Only use this in the actual kernel, not in the simulator. */
#define IMMEDIATE
-/* Skip some consistency checking. Good for benchmarking */
-#define SPEEDY
-/* Read return zeros. Undefine for benchmarking */
-#define CLEAR
-
-/* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL = -1;
-
-#define NR_BLK_DEV 12
-#ifndef MAJOR_NR
-#define MAJOR_NR 8
-#endif
#define START_PARTITION 4
/* Time to wait before completing a command */
#define DISK_SPEED (HZ/10) /* 100ms */
#define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
-#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
static int starts[] =
{N_SECTOR,
N_HEAD * N_SECTOR, /* Single cylinder */
N_HEAD * N_SECTOR * 4,
- CAPACITY, 0};
+ 0 /* CAPACITY */, 0};
static int npart = 0;
-#include "scsi_debug.h"
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
+typedef struct scsi_debug_store_elem {
+ unsigned char * p;
+} Sd_store_elem;
-#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW)
-#define VERIFY_DEBUG(RW)
-#else
+static Sd_store_elem * store_arr = 0;
-#define VERIFY1_DEBUG(RW) \
- if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
- start = 0; \
- if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
- if (bh){ \
- if (bh->b_size != 1024) panic ("Wrong bh size"); \
- if ((bh->b_blocknr << 1) + start != block) \
- { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \
- panic ("Wrong bh block#"); \
- }; \
- if (bh->b_dev != SCpnt->request.rq_dev) \
- panic ("Bad bh target"); \
- };
-
-#define VERIFY_DEBUG(RW) \
- if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \
- start = 0; \
- if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \
- if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
- if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \
- if (SCpnt->request.sector + start != block) panic("Wrong block."); \
- if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
- if (SCpnt->request.bh){ \
- if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
- if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \
- { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \
- panic ("Wrong bh block#"); \
- }; \
- if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
- panic ("Bad bh target");\
- };
-#endif
+typedef struct sdebug_dev_info {
+ Scsi_Device * sdp;
+ unsigned short host_no;
+ unsigned short id;
+ char reset;
+ char sb_index;
+} Sdebug_dev_info;
+static Sdebug_dev_info * devInfop;
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
+
+static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
+
+#include "scsi_debug.h"
typedef void (*done_fct_t) (Scsi_Cmnd *);
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
+static volatile done_fct_t * do_done = 0;
struct Scsi_Host * SHpnt = NULL;
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip);
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip);
static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
static void scsi_debug_intr_handle(unsigned long);
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key,
+ int asc, int asq, int inbandLen);
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
-static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
-
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] =
-{0,};
+static struct timer_list * timeout = 0;
+static Scsi_Cmnd ** SCint = 0;
/*
* Semaphore used to simulate bus lockups.
*/
static int scsi_debug_lockup = 0;
-static char sense_buffer[128] =
-{0,};
+#define NUM_SENSE_BUFFS 4
+#define SENSE_BUFF_LEN 32
+static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
+
+static int made_block0 = 0;
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
+static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
+ Scsi_Cmnd * SCpnt)
{
int i;
- unsigned int *lpnt;
- struct scatterlist *sgpnt = NULL;
- printk("use_sg: %d", SCpnt->use_sg);
- if (SCpnt->use_sg) {
- sgpnt = (struct scatterlist *) SCpnt->buffer;
- for (i = 0; i < SCpnt->use_sg; i++) {
- printk(":%p %d\n",
- (page_address(sgpnt[i].page) + sgpnt[i].offset),
- sgpnt[i].length);
- };
- } else {
- printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
- lpnt = (int *) SCpnt->request.buffer;
- if (lpnt)
- printk(" (Alt %x) ", lpnt[15]);
- };
- lpnt = (unsigned int *) SCpnt;
- for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
- if ((i & 7) == 0)
- printk("\n");
- printk("%x ", *lpnt++);
- };
- printk("\n");
- if (flag == 0)
- return;
+ struct partition *p;
+
+ memset(buff, 0, bufflen);
+ *((unsigned short *) (buff + 510)) = 0xAA55;
+ p = (struct partition *) (buff + 0x1be);
+ i = 0;
+ while (starts[i + 1]) {
+ int start_cyl, end_cyl;
+
+ start_cyl = starts[i] / N_HEAD / N_SECTOR;
+ end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+ p->boot_ind = 0;
+
+ p->head = (i == 0 ? 1 : 0);
+ p->sector = 1 | ((start_cyl >> 8) << 6);
+ p->cyl = (start_cyl & 0xff);
+
+ p->end_head = N_HEAD - 1;
+ p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+ p->end_cyl = (end_cyl & 0xff);
+
+ p->start_sect = starts[i];
+ p->nr_sects = starts[i + 1] - starts[i];
+ p->sys_ind = 0x83; /* Linux ext2 partition */
+ p++;
+ i++;
+ }
+ if (!npart)
+ npart = i;
+ made_block0 = 1;
+ i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
+ memcpy(store_arr[0].p, buff, i);
}
int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
unchar *cmd = (unchar *) SCpnt->cmnd;
- struct partition *p;
int block;
- struct buffer_head *bh = NULL;
+ int upper_blk;
unsigned char *buff;
- int nbytes, sgcount;
int scsi_debug_errsts;
- struct scatterlist *sgpnt;
int target = SCpnt->target;
int bufflen = SCpnt->request_bufflen;
- unsigned long flags;
- int i;
- sgcount = 0;
- sgpnt = NULL;
-
-#ifdef CONFIG_SMP
- /*
- * The io_request_lock *must* be held at this point.
- */
- if( io_request_lock.lock == 0 )
- {
- printk("Warning - io_request_lock is not held in queuecommand\n");
- }
-#endif
+ unsigned long iflags;
+ int i, num, capac;
+ Sdebug_dev_info * devip = NULL;
+ char * sbuff;
/*
- * If we are being notified of the mid-level reposessing a command due to timeout,
- * just return.
+ * If we are being notified of the mid-level reposessing a command
+ * due to timeout, just return.
*/
if (done == NULL) {
return 0;
}
- DEB(if (target >= NR_FAKE_DISKS) {
- SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;
- }
- );
buff = (unsigned char *) SCpnt->request_buffer;
@@ -218,252 +226,201 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
* If a command comes for the ID of the host itself, just print
* a silly message and return.
*/
- if( target == 7 ) {
+ if(target == 7) {
printk("How do you do!\n");
SCpnt->result = 0;
done(SCpnt);
return 0;
}
- if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+ if ((target > 7) || (SCpnt->lun != 0)) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
- if (SCrst[target] != 0 && !scsi_debug_lockup) {
- SCrst[target] = 0;
- memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
- SCpnt->sense_buffer[0] = 0x70;
- SCpnt->sense_buffer[2] = UNIT_ATTENTION;
- SCpnt->result = (CHECK_CONDITION << 1);
- done(SCpnt);
+#if 0
+ printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+ (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
+ SCpnt->device, (int)(unsigned char)*cmd);
+#endif
+ if (NULL == SCpnt->device->hostdata) {
+ devip = devInfoReg(SCpnt->device);
+ if (NULL == devip) {
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
+ }
+ SCpnt->device->hostdata = devip;
}
+ devip = SCpnt->device->hostdata;
+
switch (*cmd) {
- case REQUEST_SENSE:
+ case REQUEST_SENSE: /* mandatory */
SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
-#ifndef DEBUG
- {
- int i;
- printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
- for (i = 0; i < 12; i++)
- printk("%d ", sense_buffer[i]);
- printk("\n");
- };
-#endif
- memset(buff, 0, bufflen);
- memcpy(buff, sense_buffer, bufflen);
- memset(sense_buffer, 0, sizeof(sense_buffer));
+ if (devip) {
+ sbuff = &sense_buffers[(int)devip->sb_index][0];
+ devip->sb_index = 0;
+ }
+ else
+ sbuff = &sense_buffers[0][0];
+ memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ?
+ bufflen : SENSE_BUFF_LEN);
+ memset(sbuff, 0, SENSE_BUFF_LEN);
+ sbuff[0] = 0x70;
SCpnt->result = 0;
done(SCpnt);
return 0;
case START_STOP:
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
scsi_debug_errsts = 0;
break;
case ALLOW_MEDIUM_REMOVAL:
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
if (cmd[4]) {
- SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+ SCSI_LOG_LLQUEUE(2, printk(
+ "Medium removal inhibited..."));
} else {
- SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+ SCSI_LOG_LLQUEUE(2,
+ printk("Medium removal enabled..."));
}
scsi_debug_errsts = 0;
break;
- case INQUIRY:
+ case INQUIRY: /* mandatory */
SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
memset(buff, 0, bufflen);
buff[0] = DEVICE_TYPE(target);
- buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
- buff[2] = 1;
- buff[4] = 33 - 5;
- memcpy(&buff[8], "Foo Inc", 7);
- memcpy(&buff[16], "XYZZY", 5);
- memcpy(&buff[32], "1", 1);
+ buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;
+ /* Removable disk */
+ buff[2] = 2; /* claim SCSI 2 */
+ buff[4] = 36 - 5;
+ memcpy(&buff[8], "Linux ", 8);
+ memcpy(&buff[16], "scsi_debug ", 16);
+ memcpy(&buff[32], "0002", 4);
+ scsi_debug_errsts = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+ if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+ SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+#endif
+ break;
+ case SEND_DIAGNOSTIC: /* mandatory */
+ SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
+ if (buff)
+ memset(buff, 0, bufflen);
scsi_debug_errsts = 0;
break;
- case TEST_UNIT_READY:
+ case TEST_UNIT_READY: /* mandatory */
SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
if (buff)
memset(buff, 0, bufflen);
scsi_debug_errsts = 0;
break;
case READ_CAPACITY:
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
SHpnt = SCpnt->host;
- if (NR_REAL < 0)
- NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
memset(buff, 0, bufflen);
- buff[0] = (CAPACITY >> 24);
- buff[1] = (CAPACITY >> 16) & 0xff;
- buff[2] = (CAPACITY >> 8) & 0xff;
- buff[3] = CAPACITY & 0xff;
+ capac = CAPACITY - 1;
+ buff[0] = (capac >> 24);
+ buff[1] = (capac >> 16) & 0xff;
+ buff[2] = (capac >> 8) & 0xff;
+ buff[3] = capac & 0xff;
buff[4] = 0;
buff[5] = 0;
- buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */
- buff[7] = SIZE(target) & 0xff;
+ buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ buff[7] = SECT_SIZE_PER(target) & 0xff;
scsi_debug_errsts = 0;
break;
+ case SCSI_CMD_READ_16: /* SBC-2 */
+ case READ_12:
case READ_10:
case READ_6:
-#ifdef DEBUG
- printk("Read...");
-#endif
- if ((*cmd) == READ_10)
- block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
- else
- block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
- VERIFY_DEBUG(READ);
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
- {
- int delay = SCSI_SETUP_LATENCY;
-
- delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
- if (delay)
- usleep(delay);
- };
-#endif
-
-#ifdef DEBUG
- printk("(r%d)", SCpnt->request.nr_sectors);
-#endif
- nbytes = bufflen;
- if (SCpnt->use_sg) {
- sgcount = 0;
- sgpnt = (struct scatterlist *) buff;
- buff = (page_address(sgpnt[sgcount].page) +
- sgpnt[sgcount].offset);
- bufflen = sgpnt[sgcount].length;
- bh = SCpnt->request.bh;
- };
- scsi_debug_errsts = 0;
- do {
- VERIFY1_DEBUG(READ);
- /* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
- memset(buff, 0, bufflen);
-#endif
- /* If this is block 0, then we want to read the partition table for this
- * device. Let's make one up */
- if (block == 0) {
- int i;
- memset(buff, 0, bufflen);
- *((unsigned short *) (buff + 510)) = 0xAA55;
- p = (struct partition *) (buff + 0x1be);
- i = 0;
- while (starts[i + 1]) {
- int start_cyl, end_cyl;
-
- start_cyl = starts[i] / N_HEAD / N_SECTOR;
- end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
- p->boot_ind = 0;
-
- p->head = (i == 0 ? 1 : 0);
- p->sector = 1 | ((start_cyl >> 8) << 6);
- p->cyl = (start_cyl & 0xff);
-
- p->end_head = N_HEAD - 1;
- p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
- p->end_cyl = (end_cyl & 0xff);
-
- p->start_sect = starts[i];
- p->nr_sects = starts[i + 1] - starts[i];
- p->sys_ind = 0x81; /* Linux partition */
- p++;
- i++;
- };
- if (!npart)
- npart = i;
- scsi_debug_errsts = 0;
- break;
- };
-#ifdef DEBUG
- if (SCpnt->use_sg)
- printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
- SCpnt->request.current_nr_sectors);
-#endif
-
-#if 0
- /* Simulate a disk change */
- if (block == 0xfff0) {
- sense_buffer[0] = 0x70;
- sense_buffer[2] = UNIT_ATTENTION;
- starts[0] += 10;
- starts[1] += 10;
- starts[2] += 10;
-
-#ifdef DEBUG
- {
- int i;
- printk("scsi_debug: Filling sense buffer:");
- for (i = 0; i < 12; i++)
- printk("%d ", sense_buffer[i]);
- printk("\n");
- };
-#endif
- scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
- break;
- } /* End phony disk change code */
-#endif
-
-#ifdef CLEAR
- memcpy(buff, &target, sizeof(target));
- memcpy(buff + sizeof(target), cmd, 24);
- memcpy(buff + 60, &block, sizeof(block));
- memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
-#endif
- nbytes -= bufflen;
- if (SCpnt->use_sg) {
-#ifdef CLEAR
- memcpy(buff + 128, bh, sizeof(struct buffer_head));
-#endif
- block += bufflen >> 9;
- bh = bh->b_reqnext;
- sgcount++;
- if (nbytes) {
- if (!bh)
- panic("Too few blocks for linked request.");
- buff = (page_address(sgpnt[sgcount].page) +
- sgpnt[sgcount].offset);
- bufflen = sgpnt[sgcount].length;
- };
- }
- } while (nbytes);
-
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
+ upper_blk = 0;
+ if ((*cmd) == SCSI_CMD_READ_16) {
+ upper_blk = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ block = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ num = cmd[13] + (cmd[12] << 8) +
+ (cmd[11] << 16) + (cmd[10] << 24);
+ }
+ else if ((*cmd) == READ_12) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ }
+ else if ((*cmd) == READ_10) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[8] + (cmd[7] << 8);
+ }
+ else {
+ block = cmd[3] + (cmd[2] << 8) +
+ ((cmd[1] & 0x1f) << 16);
+ num = cmd[4];
+ }
+ if (scsi_debug_read(SCpnt, upper_blk, block, num,
+ &scsi_debug_errsts, devip))
+ break;
SCpnt->result = 0;
- (done) (SCpnt);
+/* calls bottom half in upper layers before return from scsi_do_...() */
+ (done) (SCpnt);
return 0;
-
- if (SCpnt->use_sg && !scsi_debug_errsts)
- if (bh)
- scsi_dump(SCpnt, 0);
- break;
+ case SCSI_CMD_WRITE_16: /* SBC-2 */
+ case WRITE_12:
case WRITE_10:
case WRITE_6:
-#ifdef DEBUG
- printk("Write\n");
-#endif
- if ((*cmd) == WRITE_10)
- block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
- else
- block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
- VERIFY_DEBUG(WRITE);
- /* printk("(w%d)",SCpnt->request.nr_sectors); */
- if (SCpnt->use_sg) {
- if ((bufflen >> 9) != SCpnt->request.nr_sectors)
- panic("Trying to write wrong number of blocks\n");
- sgpnt = (struct scatterlist *) buff;
- buff = (page_address(sgpnt[sgcount].page) +
- sgpnt[sgcount].offset);
- };
-#if 0
- if (block != *((unsigned long *) (buff + 60))) {
- printk("%x %x :", block, *((unsigned long *) (buff + 60)));
- scsi_dump(SCpnt, 1);
- panic("Bad block written.\n");
- };
-#endif
- scsi_debug_errsts = 0;
- break;
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
+ upper_blk = 0;
+ if ((*cmd) == SCSI_CMD_WRITE_16) {
+ upper_blk = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ block = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ num = cmd[13] + (cmd[12] << 8) +
+ (cmd[11] << 16) + (cmd[10] << 24);
+ }
+ else if ((*cmd) == WRITE_12) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ }
+ else if ((*cmd) == WRITE_10) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[8] + (cmd[7] << 8);
+ }
+ else {
+ block = cmd[3] + (cmd[2] << 8) +
+ ((cmd[1] & 0x1f) << 16);
+ num = cmd[4];
+ }
+ if (scsi_debug_write(SCpnt, upper_blk, block, num,
+ &scsi_debug_errsts, devip))
+ break;
+ SCpnt->result = 0;
+/* calls bottom half in upper layers before return from scsi_do_...() */
+ (done) (SCpnt);
+ return 0;
case MODE_SENSE:
/*
* Used to detect write protected status.
@@ -472,26 +429,36 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
memset(buff, 0, 6);
break;
default:
+#if 0
SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
- };
+#else
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
+ scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
+ break;
+#endif
+ }
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mailbox_lock, iflags);
for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
if (timeout[i].function == NULL)
break;
- };
+ }
/*
- * If all of the slots are full, just return 1. The new error handling scheme
- * allows this, and the mid-level should queue things.
+ * If all of the slots are full, just return 1. The new error
+ * handling scheme allows this, and the mid-level should queue things.
*/
if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
return 1;
}
SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
@@ -503,7 +470,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
do_done[i] = done;
scsi_debug_intr_handle(i); /* No timer - do this one right away */
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
#else
SCpnt->result = scsi_debug_errsts;
@@ -513,16 +480,190 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
SCint[i] = SCpnt;
do_done[i] = done;
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
add_timer(&timeout[i]);
if (!done)
- panic("scsi_debug_queuecommand: done can't be NULL\n");
+ printk("scsi_debug_queuecommand: done can't be NULL\n");
#if 0
- printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
+ printk("Sending command (%d %x %d %d)...", i, done,
+ timeout[i].expires, jiffies);
+#endif
+#endif
+
+ return 0;
+}
+
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+{
+ if (devip->reset) {
+ devip->reset = 0;
+ mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
+ SCpnt->result = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ return 1;
+ }
+ return 0;
+}
+
+static inline
+unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp)
+{
+ if (NULL == sclp)
+ return NULL;
+ else
+ return (unsigned char *)page_address(sclp->page) +
+ sclp->offset;
+}
+
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip)
+{
+ unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+ int nbytes, sgcount;
+ struct scatterlist *sgpnt = NULL;
+ int bufflen = SCpnt->request_bufflen;
+ unsigned long iflags;
+
+ if (upper_blk || (block + num > CAPACITY)) {
+ *errstsp = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+ return 1;
+ }
+#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
+ {
+ int delay = SCSI_SETUP_LATENCY;
+
+ delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+ if (delay)
+ usleep(delay);
+ }
#endif
+
+ read_lock_irqsave(&sdebug_atomic_rw, iflags);
+ sgcount = 0;
+ nbytes = bufflen;
+ /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n",
+ block, bufflen); */
+ if (SCpnt->use_sg) {
+ sgcount = 0;
+ sgpnt = (struct scatterlist *) buff;
+ buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+ bufflen = sgpnt[sgcount].length;
+ }
+ *errstsp = 0;
+ do {
+ int resid, k, off, len, rem, blk;
+ unsigned char * bp;
+
+ /* If this is block 0, then we want to read the partition
+ * table for this device. Let's make one up */
+ if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
+ scsi_debug_mkblock0(buff, bufflen, SCpnt);
+ *errstsp = 0;
+ break;
+ }
+ bp = buff;
+ blk = block;
+ for (resid = bufflen; resid > 0; resid -= len) {
+ k = blk / SECT_PER_ELEM;
+ off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+ rem = STORE_ELEM_SIZE - off;
+ len = (resid > rem) ? rem : resid;
+/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
+ "=%d len=%d sgcount=%d\n", blk, k,
+ off, rem, resid, len, sgcount); */
+ memcpy(bp, store_arr[k].p + off, len);
+ bp += len;
+ blk += len / SECT_SIZE;
+ }
+#if 0
+ /* Simulate a disk change */
+ if (block == 0xfff0) {
+ sense_buffer[0] = 0x70;
+ sense_buffer[2] = UNIT_ATTENTION;
+ starts[0] += 10;
+ starts[1] += 10;
+ starts[2] += 10;
+
+ *errstsp = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+ return 1;
+ } /* End phony disk change code */
#endif
+ nbytes -= bufflen;
+ if (SCpnt->use_sg) {
+ block += bufflen >> POW2_SECT_SIZE;
+ sgcount++;
+ if (nbytes) {
+ buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+ bufflen = sgpnt[sgcount].length;
+ }
+ }
+ else if (nbytes > 0)
+ printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+ } while (nbytes);
+ read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+ return 0;
+}
+
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip)
+{
+ unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+ int nbytes, sgcount;
+ struct scatterlist *sgpnt = NULL;
+ int bufflen = SCpnt->request_bufflen;
+ unsigned long iflags;
+
+ if (upper_blk || (block + num > CAPACITY)) {
+ *errstsp = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+ return 1;
+ }
+
+ write_lock_irqsave(&sdebug_atomic_rw, iflags);
+ sgcount = 0;
+ nbytes = bufflen;
+ if (SCpnt->use_sg) {
+ sgcount = 0;
+ sgpnt = (struct scatterlist *) buff;
+ buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+ bufflen = sgpnt[sgcount].length;
+ }
+ *errstsp = 0;
+ do {
+ int resid, k, off, len, rem, blk;
+ unsigned char * bp;
+
+ bp = buff;
+ blk = block;
+ for (resid = bufflen; resid > 0; resid -= len) {
+ k = blk / SECT_PER_ELEM;
+ off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+ rem = STORE_ELEM_SIZE - off;
+ len = (resid > rem) ? rem : resid;
+ memcpy(store_arr[k].p + off, bp, len);
+ bp += len;
+ blk += len / SECT_SIZE;
+ }
+ nbytes -= bufflen;
+ if (SCpnt->use_sg) {
+ block += bufflen >> POW2_SECT_SIZE;
+ sgcount++;
+ if (nbytes) {
+ buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+ bufflen = sgpnt[sgcount].length;
+ }
+ }
+ else if (nbytes > 0)
+ printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+ } while (nbytes);
+ write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
return 0;
}
@@ -573,10 +714,6 @@ static void scsi_debug_intr_handle(unsigned long indx)
{
Scsi_Cmnd *SCtmp;
void (*my_done) (Scsi_Cmnd *);
-#ifdef DEBUG
- int to;
-#endif
-
#if 0
del_timer(&timeout[indx]);
#endif
@@ -591,59 +728,219 @@ static void scsi_debug_intr_handle(unsigned long indx)
printk("scsi_debug_intr_handle: Unexpected interrupt\n");
return;
}
-#ifdef DEBUG
+#if 0
printk("In intr_handle...");
printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
#endif
my_done(SCtmp);
-#ifdef DEBUG
+#if 0
printk("Called done.\n");
#endif
}
+static int initialized = 0;
+
+static int do_init(void)
+{
+ int sz;
+
+ starts[3] = CAPACITY;
+ sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
+ store_arr = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == store_arr)
+ return 1;
+ memset(store_arr, 0, sz);
+
+ sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
+ do_done = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == do_done)
+ goto out;
+ memset((void *)do_done, 0, sz);
+
+ sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
+ timeout = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == timeout)
+ goto out;
+ memset(timeout, 0, sz);
+
+ sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
+ SCint = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == SCint)
+ goto out;
+ memset(SCint, 0, sz);
+
+ return 0;
+
+out:
+ if (store_arr)
+ kfree(store_arr);
+ if (do_done)
+ kfree((void *)do_done);
+ if (timeout)
+ kfree(timeout);
+ if (SCint)
+ kfree(SCint);
+ return 1;
+}
+
+static void do_end(void)
+{
+ kfree(SCint);
+ kfree(timeout);
+ kfree((void *)do_done);
+ kfree(store_arr);
+}
+
int scsi_debug_detect(Scsi_Host_Template * tpnt)
{
- int i;
+ int k, num, sz;
+
+ if (0 == initialized) {
+ ++initialized;
+ sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
+ devInfop = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == devInfop) {
+ printk("scsi_debug_detect: out of memory, 0.5\n");
+ return 0;
+ }
+ memset(devInfop, 0, sz);
+ if (do_init()) {
+ printk("scsi_debug_detect: out of memory, 0\n");
+ return 0;
+ }
+ for (k = 0; k < STORE_ELEMENTS; ++k) {
+ store_arr[k].p = (unsigned char *)
+ __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
+ if (0 == store_arr[k].p)
+ goto detect_err;
+ memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
+ }
+ for (k = 0; k < NUM_SENSE_BUFFS; ++k)
+ sense_buffers[k][0] = 0x70;
+ for (k = 0; k < NR_HOSTS_PRESENT; k++) {
+ tpnt->proc_name = "scsi_debug"; /* In the loop??? */
+ scsi_register(tpnt, 0);
+ }
+ return NR_HOSTS_PRESENT;
+ }
+ else {
+ printk("scsi_debug_detect: called again\n");
+ return 0;
+ }
- for (i = 0; i < NR_HOSTS_PRESENT; i++) {
- tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */
- scsi_register(tpnt, 0);
+detect_err:
+ num = k;
+ for (k = 0; k < STORE_ELEMENTS; ++k) {
+ if (0 != store_arr[k].p) {
+ free_pages((unsigned long)store_arr[k].p,
+ STORE_ELEM_ORDER);
+ store_arr[k].p = NULL;
+ }
}
- return NR_HOSTS_PRESENT;
+ printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
+ (int)(num * STORE_ELEM_SIZE),
+ (int)(scsi_debug_dev_size_mb * 1024 * 1024));
+ return 0;
+}
+
+
+static int num_releases = 0;
+
+int scsi_debug_release(struct Scsi_Host * hpnt)
+{
+ int k;
+
+ scsi_unregister(hpnt);
+ if (++num_releases != NR_HOSTS_PRESENT)
+ return 0;
+
+ for (k = 0; k < STORE_ELEMENTS; ++k) {
+ if (0 != store_arr[k].p) {
+ free_pages((unsigned long)store_arr[k].p,
+ STORE_ELEM_ORDER);
+ store_arr[k].p = NULL;
+ }
+ }
+ do_end();
+ kfree(devInfop);
+ return 0;
+}
+
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+{
+ int k;
+ unsigned short host_no, id;
+ Sdebug_dev_info * devip;
+
+ host_no = sdp->host->host_no;
+ id = (unsigned short)sdp->id;
+ for (k = 0; k < scsi_debug_num_devs; ++k) {
+ devip = &devInfop[k];
+ if (devip->sdp && (host_no == devip->host_no) &&
+ (id == devip->id)) {
+ devip->sdp = sdp; /* overwrite previous sdp */
+ return devip;
+ }
+ if (NULL == devip->sdp) {
+ devip->sdp = sdp;
+ devip->host_no = host_no;
+ devip->id = id;
+ devip->reset = 1;
+ devip->sb_index = 0;
+ return devip;
+ }
+ }
+ return NULL;
+}
+
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key,
+ int asc, int asq, int inbandLen)
+{
+ char * sbuff;
+ if ((index < 0) || (index >= NUM_SENSE_BUFFS))
+ return;
+ if (devip)
+ devip->sb_index = index;
+ sbuff = &sense_buffers[index][0];
+ memset(sbuff, 0, SENSE_BUFF_LEN);
+ sbuff[0] = 0x70;
+ sbuff[2] = key;
+ sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+ sbuff[12] = asc;
+ sbuff[13] = asq;
}
int scsi_debug_abort(Scsi_Cmnd * SCpnt)
{
-#if 0
+#if 1
+ ++num_aborts;
+ return SUCCESS;
+#else
int j;
void (*my_done) (Scsi_Cmnd *);
- unsigned long flags;
-#endif
-
- DEB(printk("scsi_debug_abort\n"));
-#if 0
+ unsigned long iflags;
SCpnt->result = SCpnt->abort_reason << 16;
for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
if (SCpnt == SCint[j]) {
my_done = do_done[j];
my_done(SCpnt);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mailbox_lock, iflags);
timeout[j] = 0;
SCint[j] = NULL;
do_done[j] = NULL;
- restore_flags(flags);
- };
- };
-#endif
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
+ }
+ }
return SCSI_ABORT_SNOOZE;
+#endif
}
int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
{
+ /* int size = disk->capacity; */
info[0] = N_HEAD;
info[1] = N_SECTOR;
info[2] = N_CYLINDER;
@@ -652,35 +949,130 @@ int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
return 0;
}
+#if 0
int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
{
int i;
- unsigned long flags;
+ unsigned long iflags;
void (*my_done) (Scsi_Cmnd *);
printk("Bus unlocked by reset - %d\n", why);
scsi_debug_lockup = 0;
- DEB(printk("scsi_debug_reset called\n"));
for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
if (SCint[i] == NULL)
continue;
SCint[i]->result = DID_RESET << 16;
my_done = do_done[i];
my_done(SCint[i]);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mailbox_lock, iflags);
SCint[i] = NULL;
do_done[i] = NULL;
timeout[i].function = NULL;
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
}
return SCSI_RESET_SUCCESS;
}
+#endif
+
+int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+{
+ Scsi_Device * sdp;
+ int k;
+
+ ++num_dev_resets;
+ if (SCpnt && ((sdp = SCpnt->device))) {
+ for (k = 0; k < scsi_debug_num_devs; ++k) {
+ if (sdp->hostdata == (devInfop + k))
+ break;
+ }
+ if (k < scsi_debug_num_devs)
+ devInfop[k].reset = 1;
+ }
+ return SUCCESS;
+}
-const char *scsi_debug_info(void)
+int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
{
- static char buffer[] = " "; /* looks nicer without anything here */
- return buffer;
+ Scsi_Device * sdp;
+ struct Scsi_Host * hp;
+ int k;
+
+ ++num_bus_resets;
+ if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+ for (k = 0; k < scsi_debug_num_devs; ++k) {
+ if (hp == devInfop[k].sdp->host)
+ devInfop[k].reset = 1;
+ }
+ }
+ return SUCCESS;
+}
+
+int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+{
+ int k;
+
+ ++num_host_resets;
+ for (k = 0; k < scsi_debug_num_devs; ++k)
+ devInfop[k].reset = 1;
+
+ return SUCCESS;
+}
+
+#ifndef MODULE
+static int __init scsi_debug_num_devs_setup(char *str)
+{
+ int tmp;
+
+ if (get_option(&str, &tmp) == 1) {
+ if (tmp > 0)
+ scsi_debug_num_devs = tmp;
+ return 1;
+ } else {
+ printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+ "(<n> can be from 1 to around 2000)\n");
+ return 0;
+ }
+}
+
+__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
+
+static int __init scsi_debug_dev_size_mb_setup(char *str)
+{
+ int tmp;
+
+ if (get_option(&str, &tmp) == 1) {
+ if (tmp > 0)
+ scsi_debug_dev_size_mb = tmp;
+ return 1;
+ } else {
+ printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+ " (<n> is number of MB ram shared by all devs\n");
+ return 0;
+ }
+}
+
+__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+#endif
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_PARM(scsi_debug_num_devs, "i");
+MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_dev_size_mb, "i");
+MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+static char sdebug_info[256];
+
+const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+ sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+ "dev_size_mb=%d\n", scsi_debug_version_str,
+ scsi_debug_num_devs, scsi_debug_dev_size_mb);
+ return sdebug_info;
}
/* scsi_debug_proc_info
@@ -730,10 +1122,20 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
}
begin = 0;
- pos = len = sprintf(buffer,
- "This driver is not a real scsi driver, but it plays one on TV.\n"
+ pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
+ "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n"
+ "cylinders=%d, heads=%d, sectors=%d\n"
+ "number of aborts=%d, device_reset=%d, bus_resets=%d, "
+ "host_resets=%d\n",
+ scsi_debug_version_str, scsi_debug_num_devs,
+ scsi_debug_dev_size_mb, SECT_SIZE,
+ N_CYLINDER, N_HEAD, N_SECTOR,
+ num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+#if 0
+ "This driver is not a real scsi driver, but it plays one on TV.\n"
"It is very handy for debugging specific problems because you\n"
"can simulate a variety of error conditions\n");
+#endif
if (pos < offset) {
len = 0;
begin = pos;
@@ -746,44 +1148,8 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
return (len);
}
-#ifdef CONFIG_USER_DEBUG
-/*
- * This is a hack for the user space emulator. It allows us to
- * "insert" arbitrary numbers of additional drivers.
- */
-void *scsi_debug_get_handle(void)
-{
- static Scsi_Host_Template driver_copy = SCSI_DEBUG;
- void *rtn;
- rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
- if(rtn==NULL)
- return NULL;
- memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
- return rtn;
-}
-#endif
-
/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG;
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
#include "scsi_module.c"
-/*
- * Overrides for Emacs so that we almost 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: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
index b0135317a..bf3815b62 100644
--- a/drivers/scsi/scsi_debug.h
+++ b/drivers/scsi/scsi_debug.h
@@ -8,34 +8,41 @@ int scsi_debug_command(Scsi_Cmnd *);
int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int scsi_debug_abort(Scsi_Cmnd *);
int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
+int scsi_debug_bus_reset(Scsi_Cmnd *);
+int scsi_debug_dev_reset(Scsi_Cmnd *);
+int scsi_debug_host_reset(Scsi_Cmnd *);
int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+const char * scsi_debug_info(struct Scsi_Host *);
#ifndef NULL
#define NULL 0
#endif
-
-#define SCSI_DEBUG_MAILBOXES 1
-
/*
- * Allow the driver to reject commands. Thus we accept only one, but
- * and the mid-level will queue the remainder.
+ * This driver is written for the lk 2.5 series
*/
#define SCSI_DEBUG_CANQUEUE 255
-#define SCSI_DEBUG {proc_info: scsi_debug_proc_info, \
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
+#define SCSI_DEBUG_TEMPLATE \
+ {proc_info: scsi_debug_proc_info, \
name: "SCSI DEBUG", \
+ info: scsi_debug_info, \
detect: scsi_debug_detect, \
+ release: scsi_debug_release, \
queuecommand: scsi_debug_queuecommand, \
- abort: scsi_debug_abort, \
- reset: scsi_debug_reset, \
+ eh_abort_handler: scsi_debug_abort, \
+ eh_bus_reset_handler: scsi_debug_bus_reset, \
+ eh_device_reset_handler: scsi_debug_device_reset, \
+ eh_host_reset_handler: scsi_debug_host_reset, \
bios_param: scsi_debug_biosparam, \
can_queue: SCSI_DEBUG_CANQUEUE, \
this_id: 7, \
- sg_tablesize: 16, \
+ sg_tablesize: 64, \
cmd_per_lun: 3, \
unchecked_isa_dma: 0, \
use_clustering: ENABLE_CLUSTERING, \
}
+
#endif
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 909b8c6cb..e59074258 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -19,9 +19,9 @@
*/
#include <linux/config.h>
#ifdef CONFIG_PROC_FS
- static char sg_version_str[] = "Version: 3.1.20 (20010814)";
+ static char sg_version_str[] = "Version: 3.5.23 (20020103)";
#endif
- static int sg_version_num = 30120; /* 2 digits for each component */
+ static int sg_version_num = 30523; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -82,6 +82,10 @@ static void sg_proc_cleanup(void);
#include <linux/iobuf.h>
#endif
+#define SG_NEW_KIOVEC 0 /* use alloc_kiovec(), not alloc_kiovec_sz() */
+
+#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
+
int sg_big_buff = SG_DEF_RESERVED_SIZE;
/* N.B. This variable is readable and writeable via
/proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -95,14 +99,8 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
-#define SG_LOW_POOL_THRESHHOLD 30
-#define SG_MAX_POOL_SECTORS 320 /* Max. number of pool sectors to take */
-
-static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS;
-
#define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */
#define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */
-#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */
#define SG_USER_MEM 4 /* memory belongs to user space */
#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
@@ -136,10 +134,10 @@ static struct Scsi_Device_Template sg_template =
typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */
{
unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list */
+ unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
unsigned bufflen; /* Size of (aggregate) data buffer */
unsigned b_malloc_len; /* actual len malloc'ed in buffer */
- void * buffer; /* Data buffer or scatter list,12 bytes each*/
+ void * buffer; /* Data buffer or scatter list + mem_src_arr */
struct kiobuf * kiobp; /* for direct IO information */
char mapped; /* indicates kiobp has locked pages */
char buffer_mem_src; /* heap whereabouts of 'buffer' */
@@ -182,6 +180,7 @@ typedef struct sg_fd /* holds the state of a file descriptor */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
+ char mmap_called; /* 0 -> mmap() never called on this fd */
} Sg_fd; /* 2760 bytes long on i386 */
typedef struct sg_device /* holds the state of each scsi generic device */
@@ -203,7 +202,8 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt);
static int sg_start_req(Sg_request * srp);
static void sg_finish_rem_req(Sg_request * srp);
static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp);
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+ int tablesize);
static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
Sg_request * srp);
static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
@@ -233,13 +233,15 @@ static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);
static Sg_request * sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
static int sg_res_in_use(Sg_fd * sfp);
-static void sg_clr_srpnt(Scsi_Request * SRpnt);
static int sg_ms_to_jif(unsigned int msecs);
-static unsigned sg_jif_to_ms(int jifs);
+static inline unsigned sg_jif_to_ms(int jifs);
static int sg_allow_access(unsigned char opcode, char dev_type);
static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
static Sg_device * sg_get_dev(int dev);
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
#ifdef CONFIG_PROC_FS
static int sg_last_dev(void);
#endif
@@ -337,9 +339,8 @@ static int sg_release(struct inode * inode, struct file * filp)
Sg_device * sdp;
Sg_fd * sfp;
- if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
+ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
return -ENXIO;
- }
SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
sg_fasync(-1, filp, 0); /* remove filp from async notification list */
if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
@@ -615,6 +616,20 @@ static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
sg_remove_request(sfp, srp);
return -ENOSYS;
}
+ if (hp->flags & SG_FLAG_MMAP_IO) {
+ if (hp->dxfer_len > sfp->reserve.bufflen) {
+ sg_remove_request(sfp, srp);
+ return -ENOMEM; /* MMAP_IO size must fit in reserve buffer */
+ }
+ if (hp->flags & SG_FLAG_DIRECT_IO) {
+ sg_remove_request(sfp, srp);
+ return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */
+ }
+ if (sg_res_in_use(sfp)) {
+ sg_remove_request(sfp, srp);
+ return -EBUSY; /* reserve buffer already being used */
+ }
+ }
timeout = sg_ms_to_jif(srp->header.timeout);
if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) {
sg_remove_request(sfp, srp);
@@ -681,7 +696,6 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
srp->my_cmdp = SRpnt;
q = &SRpnt->sr_device->request_queue;
SRpnt->sr_request.rq_dev = sdp->i_rdev;
- SRpnt->sr_request.rq_status = RQ_ACTIVE;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_cmd_len = hp->cmd_len;
if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
@@ -849,7 +863,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
result = get_user(val, (int *)arg);
if (result) return result;
if (val != sfp->reserve.bufflen) {
- if (sg_res_in_use(sfp))
+ if (sg_res_in_use(sfp) || sfp->mmap_called)
return -EBUSY;
sg_remove_scat(&sfp->reserve);
sg_build_reserve(sfp, val);
@@ -1030,6 +1044,146 @@ static int sg_fasync(int fd, struct file * filp, int mode)
return (retval < 0) ? retval : 0;
}
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp)
+{
+ return (sclp && sclp->page) ?
+ (unsigned char *)page_address(sclp->page) + sclp->offset :
+ NULL;
+}
+
+static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+ void * page_ptr;
+ struct page * page;
+ int k, m;
+
+ SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, "
+ "scatg=%d\n", startFinish, rsv_schp->k_use_sg));
+ /* N.B. correction _not_ applied to base page of aech allocation */
+ if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+ struct scatterlist * sclp = rsv_schp->buffer;
+
+ for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+ for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+ page_ptr = sg_scatg2virt(sclp) + m;
+ page = virt_to_page(page_ptr);
+ if (startFinish)
+ get_page(page); /* increment page count */
+ else {
+ if (page_count(page) > 0)
+ put_page_testzero(page); /* decrement page count */
+ }
+ }
+ }
+ }
+ else { /* reserve buffer is just a single allocation */
+ for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+ page_ptr = (unsigned char *)rsv_schp->buffer + m;
+ page = virt_to_page(page_ptr);
+ if (startFinish)
+ get_page(page); /* increment page count */
+ else {
+ if (page_count(page) > 0)
+ put_page_testzero(page); /* decrement page count */
+ }
+ }
+ }
+}
+
+static struct page * sg_vma_nopage(struct vm_area_struct *vma,
+ unsigned long addr, int unused)
+{
+ Sg_fd * sfp;
+ struct page * page = NOPAGE_SIGBUS;
+ void * page_ptr = NULL;
+ unsigned long offset;
+ Sg_scatter_hold * rsv_schp;
+
+ if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data)))
+ return page;
+ rsv_schp = &sfp->reserve;
+ offset = addr - vma->vm_start;
+ if (offset >= rsv_schp->bufflen)
+ return page;
+ SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n",
+ offset, rsv_schp->k_use_sg));
+ if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+ int k;
+ unsigned long sa = vma->vm_start;
+ unsigned long len;
+ struct scatterlist * sclp = rsv_schp->buffer;
+
+ for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+ ++k, ++sclp) {
+ len = vma->vm_end - sa;
+ len = (len < sclp->length) ? len : sclp->length;
+ if (offset < len) {
+ page_ptr = sg_scatg2virt(sclp) + offset;
+ page = virt_to_page(page_ptr);
+ get_page(page); /* increment page count */
+ break;
+ }
+ sa += len;
+ offset -= len;
+ }
+ }
+ else { /* reserve buffer is just a single allocation */
+ page_ptr = (unsigned char *)rsv_schp->buffer + offset;
+ page = virt_to_page(page_ptr);
+ get_page(page); /* increment page count */
+ }
+ return page;
+}
+
+static struct vm_operations_struct sg_mmap_vm_ops = {
+ nopage : sg_vma_nopage,
+};
+
+static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
+{
+ Sg_fd * sfp;
+ unsigned long req_sz = vma->vm_end - vma->vm_start;
+ Sg_scatter_hold * rsv_schp;
+
+ if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data)))
+ return -ENXIO;
+ SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n",
+ (void *)vma->vm_start, (int)req_sz));
+ if (vma->vm_pgoff)
+ return -EINVAL; /* want no offset */
+ rsv_schp = &sfp->reserve;
+ if (req_sz > rsv_schp->bufflen)
+ return -ENOMEM; /* cannot map more than reserved buffer */
+
+ if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+ int k;
+ unsigned long sa = vma->vm_start;
+ unsigned long len;
+ struct scatterlist * sclp = rsv_schp->buffer;
+
+ for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+ ++k, ++sclp) {
+ if (0 != sclp->offset)
+ return -EFAULT; /* non page aligned memory ?? */
+ len = vma->vm_end - sa;
+ len = (len < sclp->length) ? len : sclp->length;
+ sa += len;
+ }
+ }
+ else { /* reserve buffer is just a single allocation */
+ if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1))
+ return -EFAULT; /* non page aligned memory ?? */
+ }
+ if (0 == sfp->mmap_called) {
+ sg_rb_correct4mmap(rsv_schp, 1); /* do only once per fd lifetime */
+ sfp->mmap_called = 1;
+ }
+ vma->vm_flags |= (VM_RESERVED | VM_IO);
+ vma->vm_private_data = sfp;
+ vma->vm_ops = &sg_mmap_vm_ops;
+ return 0;
+}
+
/* This function is a "bottom half" handler that is called by the
* mid level when a command is completed (or has failed). */
static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
@@ -1076,7 +1230,14 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
srp->data.sglist_len = SRpnt->sr_sglist_len;
srp->data.bufflen = SRpnt->sr_bufflen;
srp->data.buffer = SRpnt->sr_buffer;
- sg_clr_srpnt(SRpnt);
+ /* now clear out request structure */
+ SRpnt->sr_use_sg = 0;
+ SRpnt->sr_sglist_len = 0;
+ SRpnt->sr_bufflen = 0;
+ SRpnt->sr_buffer = NULL;
+ SRpnt->sr_underflow = 0;
+ SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ request blk */
+
srp->my_cmdp = NULL;
srp->done = 1;
read_unlock(&sg_dev_arr_lock);
@@ -1121,14 +1282,15 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
if (NULL == sfp->headrp) {
SCSI_LOG_TIMEOUT(1,
printk("sg...bh: already closed, final cleanup\n"));
- sg_remove_sfp(sdp, sfp);
+ if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
+ sdp->device->access_count--;
+ if (sdp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+ }
+ if (sg_template.module)
+ __MOD_DEC_USE_COUNT(sg_template.module);
sfp = NULL;
}
- sdp->device->access_count--;
- if (sg_template.module)
- __MOD_DEC_USE_COUNT(sg_template.module);
- if (sdp->device->host->hostt->module)
- __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
}
else if (srp && srp->orphan) {
if (sfp->keep_orphan)
@@ -1152,6 +1314,7 @@ static struct file_operations sg_fops = {
poll: sg_poll,
ioctl: sg_ioctl,
open: sg_open,
+ mmap: sg_mmap,
release: sg_release,
fasync: sg_fasync,
};
@@ -1176,7 +1339,7 @@ static int sg_init()
if(!sg_registered) {
if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
{
- printk("Unable to get major %d for generic SCSI device\n",
+ printk(KERN_ERR "Unable to get major %d for generic SCSI device\n",
SCSI_GENERIC_MAJOR);
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
return 1;
@@ -1189,7 +1352,7 @@ static int sg_init()
sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max *
sizeof(Sg_device *), GFP_ATOMIC);
if (NULL == sg_dev_arr) {
- printk("sg_init: no space for sg_dev_arr\n");
+ printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
return 1;
}
@@ -1212,8 +1375,8 @@ static int __init sg_def_reserved_size_setup(char *str)
sg_big_buff = tmp;
return 1;
} else {
- printk("sg_def_reserved_size : usage sg_def_reserved_size=n "
- "(n could be 65536, 131072 or 262144)\n");
+ printk(KERN_WARNING "sg_def_reserved_size : usage "
+ "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
return 0;
}
}
@@ -1238,7 +1401,7 @@ static int sg_attach(Scsi_Device * scsidp)
if (NULL == tmp_da) {
scsidp->attached--;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- printk("sg_attach: device array cannot be resized\n");
+ printk(KERN_ERR "sg_attach: device array cannot be resized\n");
return 1;
}
memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
@@ -1250,13 +1413,13 @@ static int sg_attach(Scsi_Device * scsidp)
for(k = 0; k < sg_template.dev_max; k++)
if(! sg_dev_arr[k]) break;
- if (k > MINORMASK) {
+ if (k > SG_MAX_DEVS_MASK) {
scsidp->attached--;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- printk("Unable to attach sg device <%d, %d, %d, %d>"
+ printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>"
" type=%d, minor number exceed %d\n", scsidp->host->host_no,
scsidp->channel, scsidp->id, scsidp->lun, scsidp->type,
- MINORMASK);
+ SG_MAX_DEVS_MASK);
return 1;
}
if(k < sg_template.dev_max)
@@ -1266,7 +1429,7 @@ static int sg_attach(Scsi_Device * scsidp)
if (NULL == sdp) {
scsidp->attached--;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- printk("sg_attach: Sg_device cannot be allocated\n");
+ printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
return 1;
}
@@ -1293,8 +1456,8 @@ static int sg_attach(Scsi_Device * scsidp)
case TYPE_WORM:
case TYPE_TAPE: break;
default:
- printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
- " lun %d, type %d\n", k, scsidp->host->host_no,
+ printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel"
+ " %d, id %d, lun %d, type %d\n", k, scsidp->host->host_no,
scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
}
return 0;
@@ -1371,7 +1534,10 @@ static void sg_detach(Scsi_Device * scsidp)
MODULE_AUTHOR("Douglas Gilbert");
MODULE_DESCRIPTION("SCSI generic (sg) driver");
+
+#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
+#endif
MODULE_PARM(def_reserved_size, "i");
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
@@ -1417,9 +1583,8 @@ static int sg_start_req(Sg_request * srp)
if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */
return res;
}
- if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) {
+ if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
sg_link_reserve(sfp, srp, dxfer_len);
- }
else {
res = sg_build_indi(req_schp, sfp, dxfer_len);
if (res) {
@@ -1445,23 +1610,24 @@ static void sg_finish_rem_req(Sg_request * srp)
sg_remove_request(sfp, srp);
}
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+ int tablesize)
{
int mem_src, ret_sz;
- int sg_bufflen = PAGE_SIZE;
int elem_sz = sizeof(struct scatterlist) + sizeof(char);
- int mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+ /* scatter gather array, followed by mem_src_arr (array of chars) */
+ int sg_bufflen = tablesize * elem_sz;
+ int mx_sc_elems = tablesize;
mem_src = SG_HEAP_KMAL;
- schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen,
- &ret_sz, &mem_src);
- schp->buffer_mem_src = (char)mem_src;
+ schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src);
if (! schp->buffer)
return -ENOMEM;
else if (ret_sz != sg_bufflen) {
sg_bufflen = ret_sz;
- mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+ mx_sc_elems = sg_bufflen / elem_sz;
}
+ schp->buffer_mem_src = (char)mem_src;
schp->sglist_len = sg_bufflen;
memset(schp->buffer, 0, sg_bufflen);
return mx_sc_elems; /* number of scat_gath elements allocated */
@@ -1470,13 +1636,15 @@ static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
{
#ifdef SG_ALLOW_DIO_CODE
+ int nbhs = 0;
+
if (schp && schp->kiobp) {
if (schp->mapped) {
unmap_kiobuf(schp->kiobp);
schp->mapped = 0;
}
if (free_also) {
- free_kiovec(1, &schp->kiobp);
+ sg_free_kiovec(1, &schp->kiobp, &nbhs);
schp->kiobp = NULL;
}
}
@@ -1494,10 +1662,12 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
sg_io_hdr_t * hp = &srp->header;
Sg_scatter_hold * schp = &srp->data;
int sg_tablesize = sfp->parentdp->sg_tablesize;
+ int nbhs = 0;
- res = alloc_kiovec(1, &schp->kiobp);
+ res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
if (0 != res) {
- SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res));
+ SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n",
+ res));
return 1;
}
res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0,
@@ -1527,7 +1697,7 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
hp->info |= SG_INFO_DIRECT_IO;
return 0;
}
- mx_sc_elems = sg_build_sgat(schp, sfp);
+ mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
if (mx_sc_elems <= 1) {
sg_unmap_and(schp, 1);
sg_remove_scat(schp);
@@ -1535,7 +1705,7 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
}
mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len;
- (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+ (rem_sz > 0) && (k < mx_sc_elems);
++k, ++sclp) {
offset = (0 == k) ? kp->offset : 0;
num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
@@ -1547,7 +1717,7 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
rem_sz -= num;
SCSI_LOG_TIMEOUT(5,
printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n",
- k, page_address(sclp->page) + sclp->offset, num, mem_src_arr[k]));
+ k, sg_scatg2virt(sclp), num, mem_src_arr[k]));
}
schp->k_use_sg = k;
SCSI_LOG_TIMEOUT(5,
@@ -1569,7 +1739,7 @@ static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
{
int ret_sz, mem_src;
int blk_size = buff_size;
- char * p = NULL;
+ unsigned char * p = NULL;
if ((blk_size < 0) || (! sfp))
return -EFAULT;
@@ -1609,14 +1779,14 @@ static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
char * mem_src_arr;
/* N.B. ret_sz and mem_src carried into this block ... */
- mx_sc_elems = sg_build_sgat(schp, sfp);
+ mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
if (mx_sc_elems < 0)
return mx_sc_elems; /* most likely -ENOMEM */
mem_src_arr = schp->buffer +
(mx_sc_elems * sizeof(struct scatterlist));
for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
- (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+ (rem_sz > 0) && (k < mx_sc_elems);
++k, rem_sz -= ret_sz, ++sclp) {
if (first)
first = 0;
@@ -1628,13 +1798,13 @@ static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
break;
}
sclp->page = virt_to_page(p);
- sclp->offset = ((unsigned long)p & ~PAGE_MASK);
+ sclp->offset = (unsigned long)p & ~PAGE_MASK;
sclp->length = ret_sz;
mem_src_arr[k] = mem_src;
SCSI_LOG_TIMEOUT(5,
printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
- k, page_address(sclp->page) + sclp->offset, ret_sz, mem_src));
+ k, sg_scatg2virt(sclp), ret_sz, mem_src));
} /* end of for loop */
schp->k_use_sg = k;
SCSI_LOG_TIMEOUT(5,
@@ -1664,7 +1834,8 @@ static int sg_write_xfer(Sg_request * srp)
if (schp->bufflen < num_xfer)
num_xfer = schp->bufflen;
}
- if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+ if ((num_xfer <= 0) ||
+ (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
return 0;
SCSI_LOG_TIMEOUT(4,
@@ -1698,15 +1869,15 @@ static int sg_write_xfer(Sg_request * srp)
struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
char * mem_src_arr = sg_get_sgat_msa(schp);
ksglen = (int)sclp->length;
- p = page_address(sclp->page) + sclp->offset;
+ p = sg_scatg2virt(sclp);
for (j = 0, k = 0; j < onum; ++j) {
res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
if (res) return res;
for (; (k < schp->k_use_sg) && p;
- ++k, ++sclp, ksglen = (int)sclp->length,
- p = page_address(sclp->page) + sclp->offset) {
+ ++k, ++sclp, ksglen = (int)sclp->length,
+ p = sg_scatg2virt(sclp)) {
ok = (SG_USER_MEM != mem_src_arr[k]);
if (usglen <= 0)
break;
@@ -1767,7 +1938,7 @@ static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
static char * sg_get_sgat_msa(Sg_scatter_hold * schp)
{
int elem_sz = sizeof(struct scatterlist) + sizeof(char);
- int mx_sc_elems = (schp->sglist_len / elem_sz) - 1;
+ int mx_sc_elems = schp->sglist_len / elem_sz;
return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);
}
@@ -1780,13 +1951,14 @@ static void sg_remove_scat(Sg_scatter_hold * schp)
struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
char * mem_src_arr = sg_get_sgat_msa(schp);
- for (k = 0; (k < schp->k_use_sg) && sclp->page; ++k, ++sclp) {
+ for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
mem_src = mem_src_arr[k];
SCSI_LOG_TIMEOUT(5,
printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
- k, page_address(sclp->page) + sclp->offset, sclp->length, mem_src));
- sg_free(page_address(sclp->page) + sclp->offset, sclp->length, mem_src);
+ k, sg_scatg2virt(sclp), sclp->length, mem_src));
+ sg_free(sg_scatg2virt(sclp), sclp->length, mem_src);
sclp->page = NULL;
+ sclp->offset = 0;
sclp->length = 0;
}
sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
@@ -1814,7 +1986,8 @@ static int sg_read_xfer(Sg_request * srp)
if (schp->bufflen < num_xfer)
num_xfer = schp->bufflen;
}
- if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+ if ((num_xfer <= 0) ||
+ (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
return 0;
SCSI_LOG_TIMEOUT(4,
@@ -1848,15 +2021,15 @@ static int sg_read_xfer(Sg_request * srp)
struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
char * mem_src_arr = sg_get_sgat_msa(schp);
ksglen = (int)sclp->length;
- p = page_address(sclp->page) + sclp->offset;
+ p = sg_scatg2virt(sclp);
for (j = 0, k = 0; j < onum; ++j) {
res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
if (res) return res;
for (; (k < schp->k_use_sg) && p;
- ++k, ++sclp, ksglen = (int)sclp->length,
- p = page_address(sclp->page) + sclp->offset) {
+ ++k, ++sclp, ksglen = (int)sclp->length,
+ p = sg_scatg2virt(sclp)) {
ok = (SG_USER_MEM != mem_src_arr[k]);
if (usglen <= 0)
break;
@@ -1897,14 +2070,14 @@ static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer)
int k, num;
struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
- for (k = 0; (k < schp->k_use_sg) && sclp->page; ++k, ++sclp) {
+ for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
num = (int)sclp->length;
if (num > num_read_xfer) {
- __copy_to_user(outp, page_address(sclp->page) + sclp->offset, num_read_xfer);
+ __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer);
break;
}
else {
- __copy_to_user(outp, page_address(sclp->page) + sclp->offset, num);
+ __copy_to_user(outp, sg_scatg2virt(sclp), num);
num_read_xfer -= num;
if (num_read_xfer <= 0)
break;
@@ -1950,7 +2123,7 @@ static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
if (rem <= num) {
if (0 == k) {
req_schp->k_use_sg = 0;
- req_schp->buffer = page_address(sclp->page) + sclp->offset;
+ req_schp->buffer = sg_scatg2virt(sclp);
}
else {
sfp->save_scat_len = num;
@@ -2190,6 +2363,8 @@ static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
if (sfp->reserve.bufflen > 0) {
SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n",
(int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+ if (sfp->mmap_called)
+ sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */
sg_remove_scat(&sfp->reserve);
}
sfp->parentdp = NULL;
@@ -2238,7 +2413,7 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
/* MOD_INC's to inhibit unloading sg and associated adapter driver */
if (sg_template.module)
__MOD_INC_USE_COUNT(sg_template.module);
- if (sdp->device->host->hostt->module)
+ if (sdp->device->host->hostt->module)
__MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
SCSI_LOG_TIMEOUT(1, printk(
"sg_remove_sfp: worrisome, %d writes pending\n", dirty));
@@ -2271,30 +2446,6 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
if (resp && retSzp) *retSzp = rqSz;
return resp;
}
- if (SG_HEAP_POOL == mem_src) {
- int num_sect = rqSz / SG_SECTOR_SZ;
-
- if (0 != (rqSz & SG_SECTOR_MSK)) {
- if (! retSzp)
- return resp;
- ++num_sect;
- rqSz = num_sect * SG_SECTOR_SZ;
- }
- while (num_sect > 0) {
- if ((num_sect <= sg_pool_secs_avail)) {
- resp = kmalloc(rqSz, page_mask);
- if (resp) {
- if (retSzp) *retSzp = rqSz;
- sg_pool_secs_avail -= num_sect;
- return resp;
- }
- }
- if (! retSzp)
- return resp;
- num_sect /= 2; /* try half as many */
- rqSz = num_sect * SG_SECTOR_SZ;
- }
- }
else if (SG_HEAP_PAGE == mem_src) {
int order, a_size;
int resSz = rqSz;
@@ -2312,7 +2463,8 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
if (retSzp) *retSzp = resSz;
}
else
- printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz);
+ printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n",
+ mem_src, rqSz);
return resp;
}
@@ -2331,29 +2483,20 @@ static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
switch (*mem_srcp)
{
case SG_HEAP_PAGE:
- l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
+ l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE;
resp = sg_low_malloc(size, low_dma, l_ms, 0);
if (resp)
break;
resp = sg_low_malloc(size, low_dma, l_ms, &size);
if (! resp) {
- l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
+ l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL;
resp = sg_low_malloc(size, low_dma, l_ms, &size);
- if (! resp) {
- l_ms = SG_HEAP_KMAL;
- resp = sg_low_malloc(size, low_dma, l_ms, &size);
- }
}
if (resp && retSzp) *retSzp = size;
break;
case SG_HEAP_KMAL:
- l_ms = SG_HEAP_PAGE;
+ l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */
resp = sg_low_malloc(size, low_dma, l_ms, 0);
- if (resp)
- break;
- l_ms = SG_HEAP_POOL;
- resp = sg_low_malloc(size, low_dma, l_ms, &size);
- if (resp && retSzp) *retSzp = size;
break;
default:
SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp));
@@ -2366,18 +2509,19 @@ static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
return resp;
}
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
+{
+#if SG_NEW_KIOVEC
+ return alloc_kiovec_sz(nr, bufp, szp);
+#else
+ return alloc_kiovec(nr, bufp);
+#endif
+}
+
static void sg_low_free(char * buff, int size, int mem_src)
{
if (! buff) return;
switch (mem_src) {
- case SG_HEAP_POOL:
- {
- int num_sect = size / SG_SECTOR_SZ;
-
- kfree(buff);
- sg_pool_secs_avail += num_sect;
- }
- break;
case SG_HEAP_KMAL:
kfree(buff); /* size not used */
break;
@@ -2393,7 +2537,7 @@ static void sg_low_free(char * buff, int size, int mem_src)
case SG_USER_MEM:
break; /* nothing to do */
default:
- printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
+ printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
mem_src, buff, size);
break;
}
@@ -2409,14 +2553,13 @@ static void sg_free(char * buff, int size, int mem_src)
sg_low_free(buff, size, mem_src);
}
-static void sg_clr_srpnt(Scsi_Request * SRpnt)
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
{
- SRpnt->sr_use_sg = 0;
- SRpnt->sr_sglist_len = 0;
- SRpnt->sr_bufflen = 0;
- SRpnt->sr_buffer = NULL;
- SRpnt->sr_underflow = 0;
- SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ command blk */
+#if SG_NEW_KIOVEC
+ free_kiovec_sz(nr, bufp, szp);
+#else
+ free_kiovec(nr, bufp);
+#endif
}
static int sg_ms_to_jif(unsigned int msecs)
@@ -2428,7 +2571,7 @@ static int sg_ms_to_jif(unsigned int msecs)
: (((int)msecs / 1000) * HZ);
}
-static unsigned sg_jif_to_ms(int jifs)
+static inline unsigned sg_jif_to_ms(int jifs)
{
if (jifs <= 0)
return 0U;
@@ -2478,8 +2621,8 @@ static Sg_device * sg_get_dev(int dev)
if (sg_dev_arr && (dev >= 0))
{
read_lock_irqsave(&sg_dev_arr_lock, iflags);
- if (dev < sg_template.dev_max)
- sdp = sg_dev_arr[dev];
+ if (dev < sg_template.dev_max)
+ sdp = sg_dev_arr[dev];
read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
}
return sdp;
@@ -2672,7 +2815,7 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
{
Sg_device * sdp;
const sg_io_hdr_t * hp;
- int j, max_dev;
+ int j, max_dev, new_interface;
if (NULL == sg_dev_arr) {
PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
@@ -2681,8 +2824,7 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
max_dev = sg_last_dev();
PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
sg_template.dev_max, max_dev);
- PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n",
- sg_pool_secs_avail, sg_big_buff);
+ PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
for (j = 0; j < max_dev; ++j) {
if ((sdp = sg_get_dev(j))) {
Sg_fd * fp;
@@ -2718,8 +2860,10 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
(int)fp->keep_orphan, (int)fp->closed);
for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
hp = &srp->header;
+ new_interface = (hp->interface_id == '\0') ? 0 : 1;
/* stop indenting so far ... */
- PRINT_PROC(srp->res_used ? " rb>> " :
+ PRINT_PROC(srp->res_used ? ((new_interface &&
+ (SG_FLAG_MMAP_IO & hp->flags)) ? " mmap>> " : " rb>> ") :
((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " "));
blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen;
usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
@@ -2729,8 +2873,8 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
if (srp->done)
PRINT_PROC(" dur=%d", hp->duration);
else
- PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ?
- sg_jif_to_ms(fp->timeout) : hp->timeout),
+ PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout :
+ sg_jif_to_ms(fp->timeout),
sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode);
/* reset indenting */
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 660cf3bc6..a6069580d 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -331,7 +331,7 @@ static int sr_init_command(Scsi_Cmnd * SCpnt)
SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n",
devm,
- (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+ (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
this_count, SCpnt->request.nr_sectors));
SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
diff --git a/drivers/sound/emu10k1/audio.c b/drivers/sound/emu10k1/audio.c
index 0228a725e..f2e6b8d5a 100644
--- a/drivers/sound/emu10k1/audio.c
+++ b/drivers/sound/emu10k1/audio.c
@@ -1098,7 +1098,7 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
static int emu10k1_audio_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct emu10k1_card *card = NULL;
struct list_head *entry;
struct emu10k1_wavedevice *wave_dev;
diff --git a/drivers/sound/emu10k1/midi.c b/drivers/sound/emu10k1/midi.c
index 935b58dc2..b67349ba4 100644
--- a/drivers/sound/emu10k1/midi.c
+++ b/drivers/sound/emu10k1/midi.c
@@ -87,7 +87,7 @@ static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hd
static int emu10k1_midi_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct emu10k1_card *card = NULL;
struct emu10k1_mididevice *midi_dev;
struct list_head *entry;
diff --git a/drivers/sound/emu10k1/mixer.c b/drivers/sound/emu10k1/mixer.c
index ea673d06a..d8f829417 100644
--- a/drivers/sound/emu10k1/mixer.c
+++ b/drivers/sound/emu10k1/mixer.c
@@ -640,7 +640,7 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
static int emu10k1_mixer_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct emu10k1_card *card = NULL;
struct list_head *entry;
diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c
index a860d2889..cdb445562 100644
--- a/drivers/sound/via82cxxx_audio.c
+++ b/drivers/sound/via82cxxx_audio.c
@@ -1995,7 +1995,7 @@ handle_one_block:
/* just to be a nice neighbor */
/* Thomas Sailer:
* But also to ourselves, release semaphore if we do so */
- if (current->need_resched) {
+ if (need_resched()) {
up(&card->syscall_sem);
schedule ();
ret = via_syscall_down (card, nonblock);
@@ -2171,7 +2171,7 @@ handle_one_block:
/* just to be a nice neighbor */
/* Thomas Sailer:
* But also to ourselves, release semaphore if we do so */
- if (current->need_resched) {
+ if (need_resched()) {
up(&card->syscall_sem);
schedule ();
ret = via_syscall_down (card, nonblock);
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 54883b59b..6eaecc1bf 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -46,6 +46,10 @@ ifeq ($(CONFIG_USB_EHCI_HCD),y)
obj-y += hcd/ehci-hcd.o
endif
+ifeq ($(CONFIG_USB_OHCI_HCD),y)
+ obj-y += hcd/ohci-hcd.o
+endif
+
obj-$(CONFIG_USB_UHCI) += usb-uhci.o
obj-$(CONFIG_USB_UHCI_ALT) += uhci.o
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
@@ -85,6 +89,7 @@ obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
mod-subdirs := serial hcd
subdir-$(CONFIG_USB_EHCI_HCD) += hcd
+subdir-$(CONFIG_USB_OHCI_HCD) += hcd
subdir-$(CONFIG_USB_SERIAL) += serial
subdir-$(CONFIG_USB_STORAGE) += storage
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 8fec33785..281b769fd 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -297,13 +297,13 @@ struct usb_audio_state;
#define FLG_CONNECTED 32
struct my_data_urb {
- urb_t urb;
- iso_packet_descriptor_t isoframe[DESCFRAMES];
+ struct urb urb;
+ struct usb_iso_packet_descriptor isoframe[DESCFRAMES];
};
struct my_sync_urb {
- urb_t urb;
- iso_packet_descriptor_t isoframe[SYNCFRAMES];
+ struct urb urb;
+ struct usb_iso_packet_descriptor isoframe[SYNCFRAMES];
};
diff --git a/drivers/usb/auerswald.c b/drivers/usb/auerswald.c
index 073b0c80d..24490c47d 100644
--- a/drivers/usb/auerswald.c
+++ b/drivers/usb/auerswald.c
@@ -176,7 +176,7 @@ struct auerchain; /* forward for circular reference */
typedef struct
{
struct auerchain *chain; /* pointer to the chain to which this element belongs */
- urb_t * urbp; /* pointer to attached urb */
+ struct urb * urbp; /* pointer to attached urb */
void *context; /* saved URB context */
usb_complete_t complete; /* saved URB completion function */
struct list_head list; /* to include element into a list */
@@ -200,7 +200,7 @@ typedef struct
unsigned int len; /* number of characters in data buffer */
unsigned int retries; /* for urb retries */
struct usb_ctrlrequest *dr; /* for setup data in control messages */
- urb_t * urbp; /* USB urb */
+ struct urb * urbp; /* USB urb */
struct auerbufctl *list; /* pointer to list */
struct list_head buff_list; /* reference to next buffer in list */
} auerbuf_t,*pauerbuf_t;
@@ -237,7 +237,7 @@ typedef struct
int open_count; /* count the number of open character channels */
char dev_desc[AUSI_DLEN];/* for storing a textual description */
unsigned int maxControlLength; /* max. Length of control paket (without header) */
- urb_t * inturbp; /* interrupt urb */
+ struct urb * inturbp; /* interrupt urb */
char * intbufp; /* data buffer for interrupt urb */
unsigned int irqsize; /* size of interrupt endpoint 1 */
struct auerchain controlchain; /* for chaining of control messages */
@@ -274,7 +274,7 @@ typedef struct
/*-------------------------------------------------------------------*/
/* Forwards */
-static void auerswald_ctrlread_complete (urb_t * urb);
+static void auerswald_ctrlread_complete (struct urb * urb);
static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
@@ -283,7 +283,7 @@ static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
/* -------------------------- */
/* completion function for chained urbs */
-static void auerchain_complete (urb_t * urb)
+static void auerchain_complete (struct urb * urb)
{
unsigned long flags;
int result;
@@ -350,7 +350,7 @@ static void auerchain_complete (urb_t * urb)
this function may be called from completion context or from user space!
early = 1 -> submit in front of chain
*/
-static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early)
+static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int early)
{
int result;
unsigned long flags;
@@ -424,7 +424,7 @@ static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early)
/* submit function for chained urbs
this function may be called from completion context or from user space!
*/
-static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
{
return auerchain_submit_urb_list (acp, urb, 0);
}
@@ -433,10 +433,10 @@ static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb)
the result is 0 if the urb is cancelled, or -EINPROGRESS if
USB_ASYNC_UNLINK is set and the function is successfully started.
*/
-static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
{
unsigned long flags;
- urb_t * urbp;
+ struct urb * urbp;
pauerchainelement_t acep;
struct list_head *tmp;
@@ -492,7 +492,7 @@ static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb)
static void auerchain_unlink_all (pauerchain_t acp)
{
unsigned long flags;
- urb_t * urbp;
+ struct urb * urbp;
pauerchainelement_t acep;
dbg ("auerchain_unlink_all called");
@@ -598,7 +598,7 @@ ac_fail:/* free the elements */
/* completion handler for synchronous chained URBs */
-static void auerchain_blocking_completion (urb_t *urb)
+static void auerchain_blocking_completion (struct urb *urb)
{
wait_queue_head_t *wakeup = (wait_queue_head_t *)urb->context;
wake_up (wakeup);
@@ -606,7 +606,7 @@ static void auerchain_blocking_completion (urb_t *urb)
/* Starts chained urb and waits for completion or timeout */
-static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length)
+static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
{
DECLARE_WAITQUEUE (wait, current);
DECLARE_WAIT_QUEUE_HEAD (wqh);
@@ -675,7 +675,7 @@ static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsi
{
int ret;
struct usb_ctrlrequest *dr;
- urb_t *urb;
+ struct urb *urb;
int length;
dbg ("auerchain_control_msg");
@@ -858,7 +858,7 @@ static int auerswald_status_retry (int status)
}
/* Completion of asynchronous write block */
-static void auerchar_ctrlwrite_complete (urb_t * urb)
+static void auerchar_ctrlwrite_complete (struct urb * urb)
{
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
@@ -871,7 +871,7 @@ static void auerchar_ctrlwrite_complete (urb_t * urb)
}
/* Completion handler for dummy retry packet */
-static void auerswald_ctrlread_wretcomplete (urb_t * urb)
+static void auerswald_ctrlread_wretcomplete (struct urb * urb)
{
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp;
@@ -910,7 +910,7 @@ static void auerswald_ctrlread_wretcomplete (urb_t * urb)
}
/* completion handler for receiving of control messages */
-static void auerswald_ctrlread_complete (urb_t * urb)
+static void auerswald_ctrlread_complete (struct urb * urb)
{
unsigned int serviceid;
pauerswald_t cp;
@@ -980,7 +980,7 @@ static void auerswald_ctrlread_complete (urb_t * urb)
messages from the USB device.
*/
/* int completion handler. */
-static void auerswald_int_complete (urb_t * urb)
+static void auerswald_int_complete (struct urb * urb)
{
unsigned long flags;
unsigned int channelid;
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 0ddbffdee..d75364cff 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -53,7 +53,7 @@ struct async {
unsigned int signr;
void *userbuffer;
void *userurb;
- urb_t urb;
+ struct urb urb;
};
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -170,7 +170,7 @@ extern inline unsigned int ld2(unsigned int x)
static struct async *alloc_async(unsigned int numisoframes)
{
- unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+ unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
struct async *as = kmalloc(assize, GFP_KERNEL);
if (!as)
return NULL;
diff --git a/drivers/usb/hcd.c b/drivers/usb/hcd.c
index 8d4799ae5..882b4d559 100644
--- a/drivers/usb/hcd.c
+++ b/drivers/usb/hcd.c
@@ -606,7 +606,7 @@ clean_2:
return retval;
}
}
- dev->driver_data = hcd;
+ pci_set_drvdata(dev, hcd);
hcd->driver = driver;
hcd->description = driver->description;
hcd->pdev = dev;
@@ -689,7 +689,7 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
struct usb_hcd *hcd;
struct usb_device *hub;
- hcd = (struct usb_hcd *) dev->driver_data;
+ hcd = pci_get_drvdata(dev);
if (!hcd)
return;
info ("remove: %s, state %x", hcd->bus_name, hcd->state);
@@ -769,7 +769,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
struct usb_hcd *hcd;
int retval;
- hcd = (struct usb_hcd *) dev->driver_data;
+ hcd = pci_get_drvdata(dev);
info ("suspend %s to state %d", hcd->bus_name, state);
pci_save_state (dev, hcd->pci_state);
@@ -798,7 +798,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
struct usb_hcd *hcd;
int retval;
- hcd = (struct usb_hcd *) dev->driver_data;
+ hcd = pci_get_drvdata(dev);
info ("resume %s", hcd->bus_name);
/* guard against multiple resumes (APM bug?) */
@@ -1081,20 +1081,20 @@ static int hcd_unlink_urb (struct urb *urb)
if (!urb)
return -EINVAL;
- // FIXME: add some explicit records to flag the
- // state where the URB is "in periodic completion".
- // Workaround is for driver to set the urb status
- // to "-EINPROGRESS", so it can get through here
- // and unlink from the completion handler.
-
/*
* we contend for urb->status with the hcd core,
* which changes it while returning the urb.
+ *
+ * Caller guaranteed that the urb pointer hasn't been freed, and
+ * that it was submitted. But as a rule it can't know whether or
+ * not it's already been unlinked ... so we respect the reversed
+ * lock sequence needed for the usb_hcd_giveback_urb() code paths
+ * (urb lock, then hcd_data_lock) in case some other CPU is now
+ * unlinking it.
*/
spin_lock_irqsave (&urb->lock, flags);
- if (!urb->hcpriv
- || urb->status != -EINPROGRESS
- || urb->transfer_flags & USB_TIMEOUT_KILLED) {
+ spin_lock (&hcd_data_lock);
+ if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
retval = -EINVAL;
goto done;
}
@@ -1103,6 +1103,8 @@ static int hcd_unlink_urb (struct urb *urb)
retval = -ENODEV;
goto done;
}
+
+ /* giveback clears dev; non-null means it's linked at this level */
dev = urb->dev->hcpriv;
hcd = urb->dev->bus->hcpriv;
if (!dev || !hcd) {
@@ -1110,6 +1112,27 @@ static int hcd_unlink_urb (struct urb *urb)
goto done;
}
+ /* For non-periodic transfers, any status except -EINPROGRESS means
+ * the HCD has already started to unlink this URB from the hardware.
+ * In that case, there's no more work to do.
+ *
+ * For periodic transfers, this is the only way to trigger unlinking
+ * from the hardware. Since we (currently) overload urb->status to
+ * tell the driver to unlink, error status might get clobbered ...
+ * unless that transfer hasn't yet restarted. One such case is when
+ * the URB gets unlinked from its completion handler.
+ *
+ * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+ */
+ switch (usb_pipetype (urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ if (urb->status != -EINPROGRESS) {
+ retval = 0;
+ goto done;
+ }
+ }
+
/* maybe set up to block on completion notification */
if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
urb->status = -ETIMEDOUT;
@@ -1130,6 +1153,7 @@ static int hcd_unlink_urb (struct urb *urb)
/* asynchronous unlink */
urb->status = -ECONNRESET;
}
+ spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags);
if (urb == (struct urb *) hcd->rh_timer.data) {
@@ -1154,6 +1178,7 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
}
goto bye;
done:
+ spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags);
bye:
if (retval)
diff --git a/drivers/usb/hcd/Config.in b/drivers/usb/hcd/Config.in
index 6f64bd8b3..bc1100521 100644
--- a/drivers/usb/hcd/Config.in
+++ b/drivers/usb/hcd/Config.in
@@ -2,6 +2,6 @@
# USB Host Controller Drivers
#
dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-# dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
# dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
diff --git a/drivers/usb/hcd/Makefile b/drivers/usb/hcd/Makefile
index 453c9cc3c..0c99da88a 100644
--- a/drivers/usb/hcd/Makefile
+++ b/drivers/usb/hcd/Makefile
@@ -6,7 +6,7 @@
O_TARGET :=
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
-# obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
+obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
# obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
# Extract lists of the multi-part drivers.
diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
index 41b8f3fd2..f48416cbb 100644
--- a/drivers/usb/hcd/ehci-hcd.c
+++ b/drivers/usb/hcd/ehci-hcd.c
@@ -70,9 +70,15 @@
* Brad Hards
* Rory Bolt
* ...
+ *
+ * HISTORY:
+ * 2002-01-14 Minor cleanup; version synch.
+ * 2002-01-08 Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04 Control/Bulk queuing behaves.
+ * 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
*/
-#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_VERSION "$Revision: 0.26 $"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
@@ -98,9 +104,6 @@ static int log2_irq_thresh = 0; // 0 to 6
MODULE_PARM (log2_irq_thresh, "i");
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
-/* Some A steppings of the NEC controller need soft retries */
-//#define EHCI_SOFT_RETRIES 5 /* after CERR-induced fault */
-
#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/hcd/ehci-hub.c b/drivers/usb/hcd/ehci-hub.c
index 4234fd8f2..798fd6066 100644
--- a/drivers/usb/hcd/ehci-hub.c
+++ b/drivers/usb/hcd/ehci-hub.c
@@ -82,11 +82,12 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ports; i++) {
temp = readl (&ehci->regs->port_status [i]);
if (temp & PORT_OWNER) {
- // get disconnected ports back if no companion driver
- if (temp & PORT_CONNECT)
- continue;
- temp &= ~(PORT_OWNER|PORT_CSC);
- writel (temp, &ehci->regs->port_status [i]);
+ /* don't report this in GetPortStatus */
+ if (temp & PORT_CSC) {
+ temp &= ~PORT_CSC;
+ writel (temp, &ehci->regs->port_status [i]);
+ }
+ continue;
}
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
diff --git a/drivers/usb/hcd/ehci-q.c b/drivers/usb/hcd/ehci-q.c
index d559e8945..df6c07d3d 100644
--- a/drivers/usb/hcd/ehci-q.c
+++ b/drivers/usb/hcd/ehci-q.c
@@ -883,11 +883,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* can't get here without STS_ASS set */
if (ehci->hcd.state != USB_STATE_HALT) {
if (cmd & CMD_PSE)
- writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
- &ehci->regs->command);
+ writel (cmd & ~CMD_ASE, &ehci->regs->command);
else {
ehci_ready (ehci);
- while (!(readl (&ehci->regs->status) & STS_ASS))
+ while (readl (&ehci->regs->status) & STS_ASS)
udelay (100);
}
}
diff --git a/drivers/usb/hcd/ehci-sched.c b/drivers/usb/hcd/ehci-sched.c
index 5a971fee2..62754b5a2 100644
--- a/drivers/usb/hcd/ehci-sched.c
+++ b/drivers/usb/hcd/ehci-sched.c
@@ -381,7 +381,7 @@ static int intr_submit (
vdbg ("qh %p usecs %d period %d starting frame %d.%d",
qh, qh->usecs, period, frame, uframe);
do {
- if (unlikely ((long)ehci->pshadow [frame].ptr)) {
+ if (unlikely (ehci->pshadow [frame].ptr != 0)) {
// FIXME -- just link to the end, before any qh with a shorter period,
// AND handle it already being (implicitly) linked into this frame
BUG ();
@@ -630,7 +630,7 @@ itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
&& ehci->hcd.state != USB_STATE_HALT) {
int i;
- iso_packet_descriptor_t *desc;
+ struct usb_iso_packet_descriptor *desc;
struct ehci_itd *first_itd = urb->hcpriv;
/* update status for this frame's transfers */
diff --git a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c
new file mode 100644
index 000000000..350ae3b6d
--- /dev/null
+++ b/drivers/usb/hcd/ohci-dbg.c
@@ -0,0 +1,236 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under GPL
+ * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+
+#define pipestring(pipe) ({ char *temp; \
+ switch (usb_pipetype (pipe)) { \
+ case PIPE_CONTROL: temp = "CTRL"; break; \
+ case PIPE_BULK: temp = "BULK"; break; \
+ case PIPE_INTERRUPT: temp = "INTR"; break; \
+ default: temp = "ISOC"; break; \
+ }; temp;})
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header
+ */
+static void urb_print (struct urb * urb, char * str, int small)
+{
+ unsigned int pipe= urb->pipe;
+
+ if (!urb->dev || !urb->dev->bus) {
+ dbg("%s URB: no dev", str);
+ return;
+ }
+
+#ifndef OHCI_VERBOSE_DEBUG
+ if (urb->status != 0)
+#endif
+ dbg("%s:[%4x] dev:%d,ep=%d-%c,%s,flags:%4x,len:%d/%d,stat:%d",
+ str,
+ usb_get_current_frame_number (urb->dev),
+ usb_pipedevice (pipe),
+ usb_pipeendpoint (pipe),
+ usb_pipeout (pipe)? 'O': 'I',
+ pipestring (pipe),
+ urb->transfer_flags,
+ urb->actual_length,
+ urb->transfer_buffer_length,
+ urb->status);
+
+#ifdef OHCI_VERBOSE_DEBUG
+ if (!small) {
+ int i, len;
+
+ if (usb_pipecontrol (pipe)) {
+ printk (KERN_DEBUG __FILE__ ": cmd(8):");
+ for (i = 0; i < 8 ; i++)
+ printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+ printk ("\n");
+ }
+ if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+ printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
+ urb->actual_length,
+ urb->transfer_buffer_length);
+ len = usb_pipeout (pipe)?
+ urb->transfer_buffer_length: urb->actual_length;
+ for (i = 0; i < 16 && i < len; i++)
+ printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+ printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+ }
+ }
+#endif
+}
+
+static inline struct ed *
+dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
+
+/* print non-empty branches of the periodic ed tree */
+void ep_print_int_eds (struct ohci_hcd *ohci, char * str)
+{
+ int i, j;
+ __u32 * ed_p;
+ for (i= 0; i < 32; i++) {
+ j = 5;
+ ed_p = &(ohci->hcca->int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):",
+ str, i, i);
+ while (*ed_p != 0 && j--) {
+ struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
+ printk (" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
+ }
+ printk ("\n");
+ }
+}
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ if (value)
+ dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (struct ohci_hcd *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (&regs->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (&regs->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (&regs->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+ // intrdisable always same as intrenable
+ // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
+{
+ __u32 temp, ndp, i;
+
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = roothub_b (controller);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = roothub_status (controller);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ dbg_port (controller, "", i, temp);
+ }
+}
+
+static void ohci_dump (struct ohci_hcd *controller, int verbose)
+{
+ dbg ("OHCI controller %s state", controller->hcd.bus_name);
+
+ // dumps some of the state we know about
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
+
+#endif
+
diff --git a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c
new file mode 100644
index 000000000..0f14a6001
--- /dev/null
+++ b/drivers/usb/hcd/ohci-hcd.c
@@ -0,0 +1,973 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * [ Initialisation is based on Linus' ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ *
+ *
+ * History:
+ *
+ * 2002/01/18 package as a patch for 2.5.3; this should match the
+ * 2.4.17 kernel modulo some bugs being fixed.
+ *
+ * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
+ * from post-2.4.5 patches.
+ * 2001/09/20 USB_ZERO_PACKET support; hcca_dma portability, OPTi warning
+ * 2001/09/07 match PCI PM changes, errnos from Linus' tree
+ * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
+ * pbook pci quirks gone (please fix pbook pci sw!) (db)
+ *
+ * 2001/04/08 Identify version on module load (gb)
+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
+ pci_map_single (db)
+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
+ *
+ * 2000/09/26 fixed races in removing the private portion of the urb
+ * 2000/09/07 disable bulk and control lists when unlinking the last
+ * endpoint descriptor in order to avoid unrecoverable errors on
+ * the Lucent chips. (rwc@sgi)
+ * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
+ * urb unlink probs, indentation fixes
+ * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
+ * device unplugs.
+ * 2000/06/28 use PCI hotplug framework, for better power management
+ * and for Cardbus support (David Brownell)
+ * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
+ * when the controller loses power; handle UE; cleanup; ...
+ *
+ * v5.2 1999/12/07 URB 3rd preview,
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
+ * i386: HUB, Keyboard, Mouse, Printer
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18
+ * v3.0 1999/06/25
+ * v2.1 1999/05/09 code clean up
+ * v2.0 1999/05/04
+ * v1.0 1999/04/27 initial release
+ *
+ * This file is licenced under GPL
+ * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h> /* for in_interrupt () */
+
+#ifndef CONFIG_USB_DEBUG
+ #define CONFIG_USB_DEBUG /* this is still experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "../hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#ifndef CONFIG_PM
+# define CONFIG_PM
+#endif
+#endif
+
+/*
+ * TO DO:
+ *
+ * - "disabled" should be the hcd state
+ * - bandwidth alloc to generic code
+ * - lots more testing!!
+ */
+
+#define DRIVER_VERSION "$Revision: 1.7 $"
+#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
+#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
+
+/*-------------------------------------------------------------------------*/
+
+#define OHCI_USE_NPS // force NoPowerSwitching mode
+// #define OHCI_VERBOSE_DEBUG /* not always helpful */
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define OHCI_UNLINK_TIMEOUT (HZ / 10)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ohci.h"
+
+#include "ohci-hub.c"
+#include "ohci-dbg.c"
+#include "ohci-mem.c"
+#include "ohci-q.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * queue up an urb for anything except the root hub
+ */
+static int ohci_urb_enqueue (
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ int mem_flags
+) {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct ed *ed;
+ urb_priv_t *urb_priv;
+ unsigned int pipe = urb->pipe;
+ int i, size = 0;
+ unsigned long flags;
+ int bustime = 0;
+
+#ifdef OHCI_VERBOSE_DEBUG
+ urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+
+ /* every endpoint has a ed, locate and fill it */
+ if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
+ usb_dec_dev_use (urb->dev);
+ return -ENOMEM;
+ }
+
+ /* for the private part of the URB we need the number of TDs (size) */
+ switch (usb_pipetype (pipe)) {
+ case PIPE_CONTROL:
+ /* 1 TD for setup, 1 for ACK, plus ... */
+ size = 2;
+ /* FALLTHROUGH */
+ case PIPE_BULK:
+ /* one TD for every 4096 Bytes (can be upto 8K) */
+ size += urb->transfer_buffer_length / 4096;
+ /* ... and for any remaining bytes ... */
+ if ((urb->transfer_buffer_length % 4096) != 0)
+ size++;
+ /* ... and maybe a zero length packet to wrap it up */
+ if (size == 0)
+ size++;
+ else if ((urb->transfer_flags & USB_ZERO_PACKET) != 0
+ && (urb->transfer_buffer_length
+ % usb_maxpacket (urb->dev, pipe,
+ usb_pipeout (pipe))) != 0)
+ size++;
+ break;
+ case PIPE_ISOCHRONOUS: /* number of packets from URB */
+ size = urb->number_of_packets;
+ if (size <= 0) {
+ usb_dec_dev_use (urb->dev);
+ return -EINVAL;
+ }
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc [i].actual_length = 0;
+ urb->iso_frame_desc [i].status = -EXDEV;
+ }
+ break;
+ case PIPE_INTERRUPT: /* one TD */
+ size = 1;
+ break;
+ }
+
+ /* allocate the private part of the URB */
+ urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+ mem_flags);
+ if (!urb_priv) {
+ usb_dec_dev_use (urb->dev);
+ return -ENOMEM;
+ }
+ memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
+
+ /* fill the private part of the URB */
+ urb_priv->length = size;
+ urb_priv->ed = ed;
+
+ /* allocate the TDs (updating hash chains) */
+ spin_lock_irqsave (&ohci->lock, flags);
+ for (i = 0; i < size; i++) {
+ urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC);
+ if (!urb_priv->td [i]) {
+ urb_priv->length = i;
+ urb_free_priv (ohci, urb_priv);
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ usb_dec_dev_use (urb->dev);
+ return -ENOMEM;
+ }
+ }
+
+// FIXME: much of this switch should be generic, move to hcd code ...
+
+ /* allocate and claim bandwidth if needed; ISO
+ * needs start frame index if it was't provided.
+ */
+ switch (usb_pipetype (pipe)) {
+ case PIPE_ISOCHRONOUS:
+ if (urb->transfer_flags & USB_ISO_ASAP) {
+ urb->start_frame = ( (ed->state == ED_OPER)
+ ? (ed->last_iso + 1)
+ : (le16_to_cpu (ohci->hcca->frame_no)
+ + 10)) & 0xffff;
+ }
+ /* FALLTHROUGH */
+ case PIPE_INTERRUPT:
+ if (urb->bandwidth == 0) {
+ bustime = usb_check_bandwidth (urb->dev, urb);
+ }
+ if (bustime < 0) {
+ urb_free_priv (ohci, urb_priv);
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ usb_dec_dev_use (urb->dev);
+ return bustime;
+ }
+ usb_claim_bandwidth (urb->dev, urb,
+ bustime, usb_pipeisoc (urb->pipe));
+ }
+
+ urb->hcpriv = urb_priv;
+
+ /* link the ed into a chain if is not already */
+ if (ed->state != ED_OPER)
+ ep_link (ohci, ed);
+
+ /* fill the TDs and link it to the ed */
+ td_submit_urb (urb);
+
+ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ return 0;
+}
+
+/*
+ * decouple the URB from the HC queues (TDs, urb_priv); it's
+ * already marked for deletion. reporting is always done
+ * asynchronously, and we might be dealing with an urb that's
+ * almost completed anyway...
+ */
+static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ unsigned long flags;
+
+#ifdef DEBUG
+ urb_print (urb, "UNLINK", 1);
+#endif
+
+ if (!ohci->disabled) {
+ urb_priv_t *urb_priv;
+
+ /* flag the urb's data for deletion in some upcoming
+ * SF interrupt's delete list processing
+ */
+ spin_lock_irqsave (&ohci->lock, flags);
+ urb_priv = urb->hcpriv;
+
+ if (!urb_priv || (urb_priv->state == URB_DEL)) {
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return 0;
+ }
+
+ urb_priv->state = URB_DEL;
+ ed_unlink (urb->dev, urb_priv->ed);
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ } else {
+ /*
+ * with HC dead, we won't respect hc queue pointers
+ * any more ... just clean up every urb's memory.
+ */
+ finish_urb (ohci, urb);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
+ int i;
+ unsigned long flags;
+
+ /* free any eds, and dummy tds, still hanging around */
+ spin_lock_irqsave (&ohci->lock, flags);
+ for (i = 0; i < 32; i++) {
+ struct ed *ed = dev->ep [i];
+ struct td *tdTailP;
+
+ if (!ed)
+ continue;
+
+ ed->state &= ~ED_URB_DEL;
+ if (ohci->disabled && ed->state == ED_OPER)
+ ed->state = ED_UNLINK;
+ switch (ed->state) {
+ case ED_NEW:
+ break;
+ case ED_UNLINK:
+ tdTailP = dma_to_td (ohci,
+ le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+ td_free (ohci, tdTailP); /* free dummy td */
+ hash_free_ed (ohci, ed);
+ break;
+
+ case ED_OPER:
+ default:
+ err ("illegal ED %d state in free_config, %d",
+ i, ed->state);
+#ifdef DEBUG
+ BUG ();
+#endif
+ }
+ ed_free (ohci, ed);
+ }
+ spin_unlock_irqrestore (&ohci->lock, flags);
+}
+
+static int ohci_get_frame (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ dbg ("%s: ohci_get_frame", hcd->bus_name);
+ return le16_to_cpu (ohci->hcca->frame_no);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (struct ohci_hcd *ohci)
+{
+ int timeout = 30;
+ int smm_timeout = 50; /* 0,5 sec */
+
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_INTR_OC, &ohci->regs->intrenable);
+ writel (OHCI_OCR, &ohci->regs->cmdstatus);
+ dbg ("USB HC TakeOver from SMM");
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+ wait_ms (10);
+ if (--smm_timeout == 0) {
+ err ("USB HC TakeOver failed!");
+ return -1;
+ }
+ }
+ }
+
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+ dbg ("USB HC reset_hc %s: ctrl = 0x%x ;",
+ ohci->hcd.bus_name,
+ readl (&ohci->regs->control));
+
+ /* Reset USB (needed by some controllers) */
+ writel (0, &ohci->regs->control);
+
+ /* HC Reset requires max 10 ms delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ if (--timeout == 0) {
+ err ("USB HC reset timed out!");
+ return -1;
+ }
+ udelay (1);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub
+ */
+static int hc_start (struct ohci_hcd *ohci)
+{
+ __u32 mask;
+ unsigned int fminterval;
+ struct usb_device *udev;
+
+ spin_lock_init (&ohci->lock);
+ ohci->disabled = 1;
+ ohci->sleeping = 0;
+
+ /* Tell the controller where the control and bulk lists are
+ * The lists are empty now. */
+
+ writel (0, &ohci->regs->ed_controlhead);
+ writel (0, &ohci->regs->ed_bulkhead);
+
+ /* a reset clears this */
+ writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
+
+ fminterval = 0x2edf;
+ writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+ writel (fminterval, &ohci->regs->fminterval);
+ writel (0x628, &ohci->regs->lsthresh);
+
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* Choose the interrupts we care about now, others later on demand */
+ mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ writel (mask, &ohci->regs->intrstatus);
+ writel (mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+ /* required for AMD-756 and some Mac platforms */
+ writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+ &ohci->regs->roothub.a);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+ // POTPGT delay is bits 24-31, in 2 ms units.
+ mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+ /* connect the virtual root hub */
+ ohci->hcd.bus->root_hub = udev = usb_alloc_dev (NULL, ohci->hcd.bus);
+ ohci->hcd.state = USB_STATE_READY;
+ if (!udev) {
+ ohci->disabled = 1;
+// FIXME cleanup
+ return -ENOMEM;
+ }
+
+ usb_connect (udev);
+ udev->speed = USB_SPEED_FULL;
+ if (usb_new_device (udev) != 0) {
+ usb_free_dev (udev);
+ ohci->disabled = 1;
+// FIXME cleanup
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static void ohci_irq (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct ohci_regs *regs = ohci->regs;
+ int ints;
+
+ if ((ohci->hcca->done_head != 0)
+ && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
+ ints = OHCI_INTR_WDH;
+ } else if ((ints = (readl (&regs->intrstatus)
+ & readl (&regs->intrenable))) == 0) {
+ return;
+ }
+
+ // dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
+
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, %s disabled", hcd->bus_name);
+ // e.g. due to PCI Master/Target Abort
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+ hc_reset (ohci);
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ writel (OHCI_INTR_WDH, &regs->intrdisable);
+ dl_done_list (ohci, dl_reverse_done_list (ohci));
+ writel (OHCI_INTR_WDH, &regs->intrenable);
+ }
+
+ if (ints & OHCI_INTR_SO) {
+ dbg ("USB Schedule overrun");
+ writel (OHCI_INTR_SO, &regs->intrenable);
+ }
+
+ // FIXME: this assumes SOF (1/ms) interrupts don't get lost...
+ if (ints & OHCI_INTR_SF) {
+ unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
+ writel (OHCI_INTR_SF, &regs->intrdisable);
+ if (ohci->ed_rm_list [!frame] != NULL) {
+ dl_del_list (ohci, !frame);
+ }
+ if (ohci->ed_rm_list [frame] != NULL)
+ writel (OHCI_INTR_SF, &regs->intrenable);
+ }
+
+ writel (ints, &regs->intrstatus);
+ writel (OHCI_INTR_MIE, &regs->intrenable);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ohci_stop (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ dbg ("%s: stop %s controller%s",
+ hcd->bus_name,
+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+ ohci->disabled ? " (disabled)" : ""
+ );
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+
+ if (!ohci->disabled)
+ hc_reset (ohci);
+
+ ohci_mem_cleanup (ohci);
+
+#ifdef CONFIG_PCI
+ pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
+ ohci->hcca, ohci->hcca_dma);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
+
+#ifdef CONFIG_PCI
+ if (hcd->pdev) {
+ ohci->hcca = pci_alloc_consistent (hcd->pdev,
+ sizeof *ohci->hcca, &ohci->hcca_dma);
+ if (!ohci->hcca)
+ return -ENOMEM;
+
+ /* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+ if (hcd->pdev->vendor == 0x1022
+ && hcd->pdev->device == 0x740c) {
+ ohci->flags = OHCI_QUIRK_AMD756;
+ info ("%s: AMD756 erratum 4 workaround",
+ hcd->bus_name);
+ }
+
+ /* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip. Evidently control and bulk lists
+ * can get confused. (B&W G3 models, and ...)
+ */
+ else if (hcd->pdev->vendor == 0x1045
+ && hcd->pdev->device == 0xc861) {
+ info ("%s: WARNING: OPTi workarounds unavailable",
+ hcd->bus_name);
+ }
+ }
+#else
+# error "where's hcca coming from?"
+#endif /* CONFIG_PCI */
+
+ memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+ if ((ret = ohci_mem_init (ohci)) < 0) {
+ ohci_stop (hcd);
+ return ret;
+ }
+ ohci->regs = hcd->regs;
+
+ if (hc_reset (ohci) < 0) {
+ ohci_stop (hcd);
+ return -ENODEV;
+ }
+
+ if (hc_start (ohci) < 0) {
+ err ("can't start %s", ohci->hcd.bus_name);
+ ohci_stop (hcd);
+ return -EBUSY;
+ }
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+
+static int ohci_suspend (struct usb_hcd *hcd, u32 state)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ unsigned long flags;
+ u16 cmd;
+
+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+ dbg ("can't suspend %s (state is %s)", hcd->bus_name,
+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+ return -EIO;
+ }
+
+ /* act as if usb suspend can always be used */
+ dbg ("%s: suspend to %d", hcd->bus_name, state);
+ ohci->sleeping = 1;
+
+ /* First stop processing */
+ spin_lock_irqsave (&ohci->lock, flags);
+ ohci->hc_control &=
+ ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+ writel (ohci->hc_control, &ohci->regs->control);
+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ (void) readl (&ohci->regs->intrstatus);
+ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ /* Wait a frame or two */
+ mdelay (1);
+ if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+ mdelay (1);
+
+ #ifdef CONFIG_PMAC_PBOOK
+ if (_machine == _MACH_Pmac)
+ disable_irq (ohci->irq);
+ /* else, 2.4 assumes shared irqs -- don't disable */
+ #endif
+
+ /* Enable remote wakeup */
+ writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,
+ &ohci->regs->intrenable);
+
+ /* Suspend chip and let things settle down a bit */
+ ohci->hc_control = OHCI_USB_SUSPEND;
+ writel (ohci->hc_control, &ohci->regs->control);
+ (void) readl (&ohci->regs->control);
+ mdelay (500); /* No schedule here ! */
+
+ switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+ case OHCI_USB_RESET:
+ dbg ("%s suspend->reset ?", hcd->bus_name);
+ break;
+ case OHCI_USB_RESUME:
+ dbg ("%s suspend->resume ?", hcd->bus_name);
+ break;
+ case OHCI_USB_OPER:
+ dbg ("%s suspend->operational ?", hcd->bus_name);
+ break;
+ case OHCI_USB_SUSPEND:
+ dbg ("%s suspended", hcd->bus_name);
+ break;
+ }
+
+ /* In some rare situations, Apple's OHCI have happily trashed
+ * memory during sleep. We disable its bus master bit during
+ * suspend
+ */
+ pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
+ cmd &= ~PCI_COMMAND_MASTER;
+ pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+ {
+ struct device_node *of_node;
+
+ /* Disable USB PAD & cell clock */
+ of_node = pci_device_to_OF_node (hcd->pdev);
+ if (of_node)
+ pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+ }
+#endif
+ return 0;
+}
+
+
+// FIXME: this restart logic should be generic,
+// and handle full hcd state cleanup
+
+/* controller died; cleanup debris, then restart */
+/* must not be called from interrupt context */
+
+static int hc_restart (struct ohci_hcd *ohci)
+{
+ int temp;
+ int i;
+
+ ohci->disabled = 1;
+ ohci->sleeping = 0;
+ if (ohci->hcd.bus->root_hub)
+ usb_disconnect (&ohci->hcd.bus->root_hub);
+
+ /* empty the interrupt branches */
+ for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load [i] = 0;
+ for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
+
+ /* no EDs to remove */
+ ohci->ed_rm_list [0] = NULL;
+ ohci->ed_rm_list [1] = NULL;
+
+ /* empty control and bulk lists */
+ ohci->ed_isotail = NULL;
+ ohci->ed_controltail = NULL;
+ ohci->ed_bulktail = NULL;
+
+ if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
+ err ("can't restart %s, %d", ohci->hcd.bus_name, temp);
+ return temp;
+ } else
+ dbg ("restart %s completed", ohci->hcd.bus_name);
+ return 0;
+}
+
+static int ohci_resume (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int temp;
+ int retval = 0;
+ unsigned long flags;
+
+#ifdef CONFIG_PMAC_PBOOK
+ {
+ struct device_node *of_node;
+
+ /* Re-enable USB PAD & cell clock */
+ of_node = pci_device_to_OF_node (hcd->pdev);
+ if (of_node)
+ pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+ }
+#endif
+ /* did we suspend, or were we powered off? */
+ ohci->hc_control = readl (&ohci->regs->control);
+ temp = ohci->hc_control & OHCI_CTRL_HCFS;
+
+#ifdef DEBUG
+ /* the registers may look crazy here */
+ ohci_dump_status (ohci);
+#endif
+
+ /* Re-enable bus mastering */
+ pci_set_master (ohci->hcd.pdev);
+
+ switch (temp) {
+
+ case OHCI_USB_RESET: // lost power
+ info ("USB restart: %s", hcd->bus_name);
+ retval = hc_restart (ohci);
+ break;
+
+ case OHCI_USB_SUSPEND: // host wakeup
+ case OHCI_USB_RESUME: // remote wakeup
+ info ("USB continue: %s from %s wakeup", hcd->bus_name,
+ (temp == OHCI_USB_SUSPEND)
+ ? "host" : "remote");
+ ohci->hc_control = OHCI_USB_RESUME;
+ writel (ohci->hc_control, &ohci->regs->control);
+ (void) readl (&ohci->regs->control);
+ mdelay (20); /* no schedule here ! */
+ /* Some controllers (lucent) need a longer delay here */
+ mdelay (15);
+
+ temp = readl (&ohci->regs->control);
+ temp = ohci->hc_control & OHCI_CTRL_HCFS;
+ if (temp != OHCI_USB_RESUME) {
+ err ("controller %s won't resume", hcd->bus_name);
+ ohci->disabled = 1;
+ retval = -EIO;
+ break;
+ }
+
+ /* Some chips likes being resumed first */
+ writel (OHCI_USB_OPER, &ohci->regs->control);
+ (void) readl (&ohci->regs->control);
+ mdelay (3);
+
+ /* Then re-enable operations */
+ spin_lock_irqsave (&ohci->lock, flags);
+ ohci->disabled = 0;
+ ohci->sleeping = 0;
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ if (!ohci->ed_rm_list [0] && !ohci->ed_rm_list [1]) {
+ if (ohci->ed_controltail)
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ if (ohci->ed_bulktail)
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ }
+ hcd->state = USB_STATE_READY;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* trigger a start-frame interrupt (why?) */
+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+
+ /* Check for a pending done list */
+ writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
+ (void) readl (&ohci->regs->intrdisable);
+ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ #ifdef CONFIG_PMAC_PBOOK
+ if (_machine == _MACH_Pmac)
+ enable_irq (ohci->irq);
+ #endif
+ if (ohci->hcca->done_head)
+ dl_done_list (ohci, dl_reverse_done_list (ohci));
+ writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
+
+// writel (OHCI_BLF, &ohci->regs->cmdstatus);
+// writel (OHCI_CLF, &ohci->regs->cmdstatus);
+ohci_dump_status (ohci);
+dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
+ break;
+
+ default:
+ warn ("odd PCI resume for %s", hcd->bus_name);
+ }
+ return retval;
+}
+
+#endif /* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const char hcd_name [] = "ohci-hcd";
+
+static const struct hc_driver ohci_driver = {
+ description: hcd_name,
+
+ /*
+ * generic hardware linkage
+ */
+ irq: ohci_irq,
+ flags: HCD_MEMORY | HCD_USB11,
+
+ /*
+ * basic lifecycle operations
+ */
+ start: ohci_start,
+#ifdef CONFIG_PM
+ suspend: ohci_suspend,
+ resume: ohci_resume,
+#endif
+ stop: ohci_stop,
+
+ /*
+ * memory lifecycle (except per-request)
+ */
+ hcd_alloc: ohci_hcd_alloc,
+ hcd_free: ohci_hcd_free,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ urb_enqueue: ohci_urb_enqueue,
+ urb_dequeue: ohci_urb_dequeue,
+ free_config: ohci_free_config,
+
+ /*
+ * scheduling support
+ */
+ get_frame_number: ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ hub_status_data: ohci_hub_status_data,
+ hub_control: ohci_hub_control,
+};
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_LICENSE ("GPL");
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* There do exist non-PCI implementations of OHCI ...
+ * Examples include the SA-1111 (ARM) and some MIPS
+ * and related hardware.
+ */
+
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+ /* handle any USB OHCI controller */
+ class: (PCI_CLASS_SERIAL_USB << 8) | 0x10,
+ class_mask: ~0,
+ driver_data: (unsigned long) &ohci_driver,
+
+ /* no matter who makes it */
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+
+ }, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ohci_pci_driver = {
+ name: (char *) hcd_name,
+ id_table: pci_ids,
+
+ probe: usb_hcd_pci_probe,
+ remove: usb_hcd_pci_remove,
+
+#ifdef CONFIG_PM
+ suspend: usb_hcd_pci_suspend,
+ resume: usb_hcd_pci_resume,
+#endif
+};
+
+
+static int __init ohci_hcd_init (void)
+{
+ dbg (DRIVER_INFO);
+ dbg ("block sizes: ed %d td %d",
+ sizeof (struct ed), sizeof (struct td));
+ return pci_module_init (&ohci_pci_driver);
+}
+module_init (ohci_hcd_init);
+
+/*-------------------------------------------------------------------------*/
+
+static void __exit ohci_hcd_cleanup (void)
+{
+ pci_unregister_driver (&ohci_pci_driver);
+}
+module_exit (ohci_hcd_cleanup);
+
+#endif /* CONFIG_PCI */
+
diff --git a/drivers/usb/hcd/ohci-hub.c b/drivers/usb/hcd/ohci-hub.c
new file mode 100644
index 000000000..f54fcd4f3
--- /dev/null
+++ b/drivers/usb/hcd/ohci-hub.c
@@ -0,0 +1,267 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under GPL
+ * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * OHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect. AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define read_roothub(hc, register, mask) ({ \
+ u32 temp = readl (&hc->regs->roothub.register); \
+ if (hc->flags & OHCI_QUIRK_AMD756) \
+ while (temp & mask) \
+ temp = readl (&hc->regs->roothub.register); \
+ temp; })
+
+static u32 roothub_a (struct ohci_hcd *hc)
+ { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci_hcd *hc)
+ { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci_hcd *hc)
+ { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+/*-------------------------------------------------------------------------*/
+
+#define dbg_port(hc,label,num,value) \
+ dbg ("%s: %s roothub.portstatus [%d] " \
+ "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", \
+ hc->hcd.bus_name, label, num, temp, \
+ (temp & RH_PS_PRSC) ? " PRSC" : "", \
+ (temp & RH_PS_OCIC) ? " OCIC" : "", \
+ (temp & RH_PS_PSSC) ? " PSSC" : "", \
+ (temp & RH_PS_PESC) ? " PESC" : "", \
+ (temp & RH_PS_CSC) ? " CSC" : "", \
+ \
+ (temp & RH_PS_LSDA) ? " LSDA" : "", \
+ (temp & RH_PS_PPS) ? " PPS" : "", \
+ (temp & RH_PS_PRS) ? " PRS" : "", \
+ (temp & RH_PS_POCI) ? " POCI" : "", \
+ (temp & RH_PS_PSS) ? " PSS" : "", \
+ \
+ (temp & RH_PS_PES) ? " PES" : "", \
+ (temp & RH_PS_CCS) ? " CCS" : "" \
+ );
+
+
+/*-------------------------------------------------------------------------*/
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ports, i, changed = 0, length = 1;
+
+ ports = roothub_a (ohci) & RH_A_NDP;
+ if (ports > MAX_ROOT_PORTS) {
+ err ("%s: bogus NDP=%d", hcd->bus_name, ports);
+ err ("rereads as NDP=%d",
+ readl (&ohci->regs->roothub.a) & RH_A_NDP);
+ /* retry later; "should not happen" */
+ return 0;
+ }
+
+ /* init status */
+ if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
+ buf [0] = changed = 1;
+ else
+ buf [0] = 0;
+ if (ports > 7) {
+ buf [1] = 0;
+ length++;
+ }
+
+ /* look at each port */
+ for (i = 0; i < ports; i++) {
+ u32 status = roothub_portstatus (ohci, i);
+
+ status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+ | RH_PS_OCIC | RH_PS_PRSC;
+ if (status) {
+ changed = 1;
+ set_bit (i + 1, buf);
+ }
+ }
+ return changed ? length : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ohci_hub_descriptor (
+ struct ohci_hcd *ohci,
+ struct usb_hub_descriptor *desc
+) {
+ u32 rh = roothub_a (ohci);
+ int ports = rh & RH_A_NDP;
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ temp = 0;
+ if (rh & RH_A_PSM) /* per-port power switching? */
+ temp |= 0x0001;
+ if (rh & RH_A_NOCP) /* no overcurrent reporting? */
+ temp |= 0x0010;
+ else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */
+ temp |= 0x0008;
+ desc->wHubCharacteristics = cpu_to_le16 (temp);
+
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ rh = roothub_b (ohci);
+ desc->bitmap [0] = rh & RH_B_DR;
+ if (ports > 7) {
+ desc->bitmap [1] = (rh & RH_B_DR) >> 8;
+ desc->bitmap [2] = desc->bitmap [3] = 0xff;
+ } else
+ desc->bitmap [1] = 0xff;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hub_control (
+ struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char *buf,
+ u16 wLength
+) {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ports;
+ u32 temp;
+ int retval = 0;
+
+ // if (port request)
+ ports = roothub_a (ohci) & RH_A_NDP;
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ writel (RH_HS_OCIC, &ohci->regs->roothub.status);
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ temp = RH_PS_CCS;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ temp = RH_PS_PESC;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ temp = RH_PS_POCI;
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ temp = RH_PS_PSSC;
+ break;
+ case USB_PORT_FEAT_POWER:
+ temp = RH_PS_LSDA;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ temp = RH_PS_CSC;
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ temp = RH_PS_OCIC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ temp = RH_PS_PRSC;
+ break;
+ default:
+ goto error;
+ }
+ writel (temp, &ohci->regs->roothub.portstatus [wIndex]);
+ // readl (&ohci->regs->roothub.portstatus [wIndex]);
+ break;
+ case GetHubDescriptor:
+ ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);
+ break;
+ case GetHubStatus:
+ temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
+ *(u32 *) buf = cpu_to_le32 (temp);
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = roothub_portstatus (ohci, wIndex);
+ *(u32 *) buf = cpu_to_le32 (temp);
+
+#ifndef OHCI_VERBOSE_DEBUG
+ if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
+#endif
+ dbg_port (ohci, "GetStatus", wIndex + 1, temp);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ // FIXME: this can be cleared, yes?
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ writel (RH_PS_PSS,
+ &ohci->regs->roothub.portstatus [wIndex]);
+ break;
+ case USB_PORT_FEAT_POWER:
+ writel (RH_PS_PPS,
+ &ohci->regs->roothub.portstatus [wIndex]);
+ break;
+ case USB_PORT_FEAT_RESET:
+ temp = readl (&ohci->regs->roothub.portstatus [wIndex]);
+ if (temp & RH_PS_CCS)
+ writel (RH_PS_PRS,
+ &ohci->regs->roothub.portstatus [wIndex]);
+ break;
+ default:
+ goto error;
+ }
+ break;
+
+ default:
+error:
+ /* "protocol stall" on error */
+ retval = -EPIPE;
+ }
+ return retval;
+}
+
diff --git a/drivers/usb/hcd/ohci-mem.c b/drivers/usb/hcd/ohci-mem.c
new file mode 100644
index 000000000..e41c7bdea
--- /dev/null
+++ b/drivers/usb/hcd/ohci-mem.c
@@ -0,0 +1,251 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under GPL
+ * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ * - data used only by the HCD ... kmalloc is fine
+ * - async and periodic schedules, shared by HC and HCD ... these
+ * need to use pci_pool or pci_alloc_consistent
+ * - driver buffers, read/written by HC ... single shot DMA mapped
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_hcd *ohci_hcd_alloc (void)
+{
+ struct ohci_hcd *ohci;
+
+ ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);
+ if (ohci != 0) {
+ memset (ohci, 0, sizeof (struct ohci_hcd));
+ return &ohci->hcd;
+ }
+ return 0;
+}
+
+static void ohci_hcd_free (struct usb_hcd *hcd)
+{
+ kfree (hcd_to_ohci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+# define OHCI_MEM_FLAGS SLAB_POISON
+#else
+# define OHCI_MEM_FLAGS 0
+#endif
+
+#ifndef CONFIG_PCI
+# error "usb-ohci currently requires PCI-based controllers"
+ /* to support non-PCI OHCIs, you need custom bus/mem/... glue */
+#endif
+
+
+/* Recover a TD/ED using its collision chain */
+static inline void *
+dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
+{
+ struct hash_t * scan = entry->head;
+ while (scan && scan->dma != dma)
+ scan = scan->next;
+ return scan->virt;
+}
+
+static inline struct ed *
+dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma)
+{
+ return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),
+ ed_dma);
+}
+
+static inline struct td *
+dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
+{
+ return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),
+ td_dma);
+}
+
+// FIXME: when updating the hashtables this way, mem_flags is unusable...
+
+/* Add a hash entry for a TD/ED; return true on success */
+static int
+hash_add_ed_td (
+ struct hash_list_t *entry,
+ void *virt,
+ dma_addr_t dma,
+ int mem_flags
+)
+{
+ struct hash_t * scan;
+
+ scan = (struct hash_t *) kmalloc (sizeof *scan, mem_flags);
+ if (!scan)
+ return 0;
+
+ if (!entry->tail) {
+ entry->head = entry->tail = scan;
+ } else {
+ entry->tail->next = scan;
+ entry->tail = scan;
+ }
+
+ scan->virt = virt;
+ scan->dma = dma;
+ scan->next = NULL;
+ return 1;
+}
+
+static inline int
+hash_add_ed (struct ohci_hcd *hc, struct ed *ed, int mem_flags)
+{
+ return hash_add_ed_td (&(hc->ed_hash [ED_HASH_FUNC (ed->dma)]),
+ ed, ed->dma, mem_flags);
+}
+
+static inline int
+hash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags)
+{
+ return hash_add_ed_td (&(hc->td_hash [TD_HASH_FUNC (td->td_dma)]),
+ td, td->td_dma, mem_flags);
+}
+
+
+static void
+hash_free_ed_td (struct hash_list_t *entry, void *virt)
+{
+ struct hash_t *scan, *prev;
+ scan = prev = entry->head;
+
+ // Find and unlink hash entry
+ while (scan && scan->virt != virt) {
+ prev = scan;
+ scan = scan->next;
+ }
+ if (scan) {
+ if (scan == entry->head) {
+ if (entry->head == entry->tail)
+ entry->head = entry->tail = NULL;
+ else
+ entry->head = scan->next;
+ } else if (scan == entry->tail) {
+ entry->tail = prev;
+ prev->next = NULL;
+ } else
+ prev->next = scan->next;
+ kfree(scan);
+ }
+}
+
+static inline void
+hash_free_ed (struct ohci_hcd *hc, struct ed * ed)
+{
+ hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
+}
+
+static inline void
+hash_free_td (struct ohci_hcd *hc, struct td * td)
+{
+ hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
+}
+
+
+static int ohci_mem_init (struct ohci_hcd *ohci)
+{
+ ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
+ sizeof (struct td),
+ 32 /* byte alignment */,
+ 0 /* no page-crossing issues */,
+ GFP_KERNEL | OHCI_MEM_FLAGS);
+ if (!ohci->td_cache)
+ return -ENOMEM;
+ ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
+ sizeof (struct ed),
+ 16 /* byte alignment */,
+ 0 /* no page-crossing issues */,
+ GFP_KERNEL | OHCI_MEM_FLAGS);
+ if (!ohci->ed_cache) {
+ pci_pool_destroy (ohci->td_cache);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void ohci_mem_cleanup (struct ohci_hcd *ohci)
+{
+ if (ohci->td_cache) {
+ pci_pool_destroy (ohci->td_cache);
+ ohci->td_cache = 0;
+ }
+ if (ohci->ed_cache) {
+ pci_pool_destroy (ohci->ed_cache);
+ ohci->ed_cache = 0;
+ }
+}
+
+/* TDs ... */
+static struct td *
+td_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+ dma_addr_t dma;
+ struct td *td;
+
+ td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
+ if (td) {
+ td->td_dma = dma;
+ /* hash it for later reverse mapping */
+ if (!hash_add_td (hc, td, mem_flags)) {
+ pci_pool_free (hc->td_cache, td, dma);
+ return NULL;
+ }
+ }
+ return td;
+}
+
+static inline void
+td_free (struct ohci_hcd *hc, struct td *td)
+{
+ hash_free_td (hc, td);
+ pci_pool_free (hc->td_cache, td, td->td_dma);
+}
+
+
+/* EDs ... */
+static struct ed *
+ed_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+ dma_addr_t dma;
+ struct ed *ed;
+
+ ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
+ if (ed) {
+ memset (ed, 0, sizeof (*ed));
+ ed->dma = dma;
+ /* hash it for later reverse mapping */
+ if (!hash_add_ed (hc, ed, mem_flags)) {
+ pci_pool_free (hc->ed_cache, ed, dma);
+ return NULL;
+ }
+ }
+ return ed;
+}
+
+static inline void
+ed_free (struct ohci_hcd *hc, struct ed *ed)
+{
+ hash_free_ed (hc, ed);
+ pci_pool_free (hc->ed_cache, ed, ed->dma);
+}
+
diff --git a/drivers/usb/hcd/ohci-q.c b/drivers/usb/hcd/ohci-q.c
new file mode 100644
index 000000000..f89cdc554
--- /dev/null
+++ b/drivers/usb/hcd/ohci-q.c
@@ -0,0 +1,1000 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under GPL
+ * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
+ */
+
+static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
+{
+ int last = urb_priv->length - 1;
+
+ if (last >= 0) {
+ int i;
+ struct td *td = urb_priv->td [0];
+#ifdef CONFIG_PCI
+ int len = td->urb->transfer_buffer_length;
+ int dir = usb_pipeout (td->urb->pipe)
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE;
+
+ /* unmap CTRL URB setup buffer (always td 0) */
+ if (usb_pipecontrol (td->urb->pipe)) {
+ pci_unmap_single (hc->hcd.pdev,
+ td->data_dma, 8, PCI_DMA_TODEVICE);
+
+ /* CTRL data buffer starts at td 1 if len > 0 */
+ if (len && last > 0)
+ td = urb_priv->td [1];
+ }
+ /* else: ISOC, BULK, INTR data buffer starts at td 0 */
+
+ /* unmap data buffer */
+ if (len && td->data_dma)
+ pci_unmap_single (hc->hcd.pdev,
+ td->data_dma, len, dir);
+#else
+# warning "assuming no buffer unmapping is needed"
+#endif
+
+ for (i = 0; i <= last; i++) {
+ td = urb_priv->td [i];
+ if (td)
+ td_free (hc, td);
+ }
+ }
+
+ kfree (urb_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * URB goes back to driver, and isn't reissued.
+ * It's completely gone from HC data structures, so no locking
+ * is needed ... or desired! (Giveback can call back to hcd.)
+ */
+static inline void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+{
+ if (urb->hcpriv) {
+ urb_free_priv (ohci, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
+ usb_hcd_giveback_urb (&ohci->hcd, urb);
+}
+
+static void td_submit_urb (struct urb *urb);
+
+/*
+ * URB is reported to driver, is reissued if it's periodic.
+ */
+static int return_urb (struct ohci_hcd *hc, struct urb *urb)
+{
+ urb_priv_t *urb_priv = urb->hcpriv;
+ struct urb *urbt;
+ unsigned long flags;
+ int i;
+
+#ifdef DEBUG
+ if (!urb_priv) {
+ err ("already unlinked!");
+ BUG ();
+ }
+
+ /* just to be sure */
+ if (!urb->complete) {
+ err ("no completion!");
+ BUG ();
+ }
+#endif
+
+#ifdef OHCI_VERBOSE_DEBUG
+ urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+
+// FIXME: but if urb->status says it was was unlinked ...
+
+ switch (usb_pipetype (urb->pipe)) {
+ case PIPE_INTERRUPT:
+#ifdef CONFIG_PCI
+ pci_unmap_single (hc->hcd.pdev,
+ urb_priv->td [0]->data_dma,
+ urb->transfer_buffer_length,
+ usb_pipeout (urb->pipe)
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE);
+#endif
+ urb->complete (urb);
+
+ /* implicitly requeued */
+ urb->actual_length = 0;
+ urb->status = -EINPROGRESS;
+ if (urb_priv->state != URB_DEL) {
+ spin_lock_irqsave (&hc->lock, flags);
+ td_submit_urb (urb);
+ spin_unlock_irqrestore (&hc->lock, flags);
+ }
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ for (urbt = urb->next;
+ urbt && (urbt != urb);
+ urbt = urbt->next)
+ continue;
+ if (urbt) { /* send the reply and requeue URB */
+#ifdef CONFIG_PCI
+// FIXME this style unmap is only done on this route ...
+ pci_unmap_single (hc->hcd.pdev,
+ urb_priv->td [0]->data_dma,
+ urb->transfer_buffer_length,
+ usb_pipeout (urb->pipe)
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE);
+#endif
+ urb->complete (urb);
+ spin_lock_irqsave (&hc->lock, flags);
+ urb->actual_length = 0;
+ urb->status = -EINPROGRESS;
+ urb->start_frame = urb_priv->ed->last_iso + 1;
+ if (urb_priv->state != URB_DEL) {
+ for (i = 0; i < urb->number_of_packets;
+ i++) {
+ urb->iso_frame_desc [i]
+ .actual_length = 0;
+ urb->iso_frame_desc [i]
+ .status = -EXDEV;
+ }
+ td_submit_urb (urb);
+ }
+// FIXME if not deleted, should have been "finished"
+ spin_unlock_irqrestore (&hc->lock, flags);
+
+ } else { /* not reissued */
+ finish_urb (hc, urb);
+ }
+ break;
+
+ /*
+ * C/B requests that get here are never reissued.
+ */
+ case PIPE_BULK:
+ case PIPE_CONTROL:
+ finish_urb (hc, urb);
+ break;
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* search for the right branch to insert an interrupt ed into the int tree
+ * do some load balancing;
+ * returns the branch and
+ * sets the interval to interval = 2^integer (ld (interval))
+ */
+static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
+{
+ int i, branch = 0;
+
+ /* search for the least loaded interrupt endpoint branch */
+ for (i = 0; i < NUM_INTS ; i++)
+ if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+ branch = i;
+
+ branch = branch % interval;
+ for (i = branch; i < NUM_INTS; i += interval)
+ ohci->ohci_int_load [i] += load;
+
+ return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* 2^int ( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{
+ int i;
+
+ for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++)
+ continue;
+ return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree
+ * in order to process it sequentially the indexes of the branches have
+ * to be mapped the mapping reverses the bits of a word of num_bits length
+ */
+static int ep_rev (int num_bits, int word)
+{
+ int i, wout = 0;
+
+ for (i = 0; i < num_bits; i++)
+ wout |= (( (word >> i) & 1) << (num_bits - i - 1));
+ return wout;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
+{
+ int int_branch, i;
+ int inter, interval, load;
+ __u32 *ed_p;
+ volatile struct ed *ed = edi;
+
+ ed->state = ED_OPER;
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ed->hwNextED = 0;
+ if (ohci->ed_controltail == NULL) {
+ writel (ed->dma, &ohci->regs->ed_controlhead);
+ } else {
+ ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
+ }
+ ed->ed_prev = ohci->ed_controltail;
+ if (!ohci->ed_controltail
+ && !ohci->ed_rm_list [0]
+ && !ohci->ed_rm_list [1]
+ && !ohci->sleeping
+ ) {
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_controltail = edi;
+ break;
+
+ case PIPE_BULK:
+ ed->hwNextED = 0;
+ if (ohci->ed_bulktail == NULL) {
+ writel (ed->dma, &ohci->regs->ed_bulkhead);
+ } else {
+ ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
+ }
+ ed->ed_prev = ohci->ed_bulktail;
+ if (!ohci->ed_bulktail
+ && !ohci->ed_rm_list [0]
+ && !ohci->ed_rm_list [1]
+ && !ohci->sleeping
+ ) {
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_bulktail = edi;
+ break;
+
+ case PIPE_INTERRUPT:
+ load = ed->int_load;
+ interval = ep_2_n_interval (ed->int_period);
+ ed->int_interval = interval;
+ int_branch = ep_int_balance (ohci, interval, load);
+ ed->int_branch = int_branch;
+
+ for (i = 0; i < ep_rev (6, interval); i += inter) {
+ inter = 1;
+ for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]);
+ (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval);
+ ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED))
+ inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+ ed->hwNextED = *ed_p;
+ *ed_p = cpu_to_le32 (ed->dma);
+ }
+#ifdef DEBUG
+ ep_print_int_eds (ohci, "LINK_INT");
+#endif
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ ed->hwNextED = 0;
+ ed->int_interval = 1;
+ if (ohci->ed_isotail != NULL) {
+ ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
+ ed->ed_prev = ohci->ed_isotail;
+ } else {
+ for ( i = 0; i < NUM_INTS; i += inter) {
+ inter = 1;
+ for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]);
+ *ed_p != 0;
+ ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED))
+ inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+ *ed_p = cpu_to_le32 (ed->dma);
+ }
+ ed->ed_prev = NULL;
+ }
+ ohci->ed_isotail = edi;
+#ifdef DEBUG
+ ep_print_int_eds (ohci, "LINK_ISO");
+#endif
+ break;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed
+ */
+static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{
+ int int_branch;
+ int i;
+ int inter;
+ int interval;
+ __u32 *ed_p;
+
+ ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (le32_to_cpup (&ed->hwNextED),
+ &ohci->regs->ed_controlhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_controltail == ed) {
+ ohci->ed_controltail = ed->ed_prev;
+ } else {
+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+ ->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_BULK:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (le32_to_cpup (&ed->hwNextED),
+ &ohci->regs->ed_bulkhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_bulktail == ed) {
+ ohci->ed_bulktail = ed->ed_prev;
+ } else {
+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+ ->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ int_branch = ed->int_branch;
+ interval = ed->int_interval;
+
+ for (i = 0; i < ep_rev (6, interval); i += inter) {
+ for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]), inter = 1;
+ (*ed_p != 0) && (*ed_p != ed->hwNextED);
+ ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED),
+ inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {
+ if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ }
+ }
+ for (i = int_branch; i < NUM_INTS; i += interval)
+ ohci->ohci_int_load [i] -= ed->int_load;
+#ifdef DEBUG
+ ep_print_int_eds (ohci, "UNLINK_INT");
+#endif
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ if (ohci->ed_isotail == ed)
+ ohci->ed_isotail = ed->ed_prev;
+ if (ed->hwNextED != 0)
+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+ ->ed_prev = ed->ed_prev;
+
+ if (ed->ed_prev != NULL) {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ } else {
+ for (i = 0; i < NUM_INTS; i++) {
+ for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]);
+ *ed_p != 0;
+ ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
+ // inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+ if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ }
+ }
+ }
+#ifdef DEBUG
+ ep_print_int_eds (ohci, "UNLINK_ISO");
+#endif
+ break;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* (re)init an endpoint; this _should_ be done once at the
+ * usb_set_configuration command, but the USB stack is a bit stateless
+ * so we do it at every transaction.
+ * if the state of the ed is ED_NEW then a dummy td is added and the
+ * state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are set even though most of them should
+ * not change
+ */
+static struct ed *ep_add_ed (
+ struct usb_device *udev,
+ unsigned int pipe,
+ int interval,
+ int load,
+ int mem_flags
+) {
+ struct ohci_hcd *ohci = hcd_to_ohci (udev->bus->hcpriv);
+ struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
+ struct td *td;
+ struct ed *ed;
+ unsigned ep;
+ unsigned long flags;
+
+ spin_lock_irqsave (&ohci->lock, flags);
+
+ ep = usb_pipeendpoint (pipe) << 1;
+ if (!usb_pipecontrol (pipe) && usb_pipeout (pipe))
+ ep |= 1;
+ if (!(ed = dev->ep [ep])) {
+ ed = ed_alloc (ohci, SLAB_ATOMIC);
+ if (!ed) {
+ /* out of memory */
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return NULL;
+ }
+ dev->ep [ep] = ed;
+ }
+
+ if (ed->state & ED_URB_DEL) {
+ /* pending unlink request */
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return NULL;
+ }
+
+ if (ed->state == ED_NEW) {
+ ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+ /* dummy td; end of td list for ed */
+ td = td_alloc (ohci, SLAB_ATOMIC);
+ if (!td) {
+ /* out of memory */
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return NULL;
+ }
+ ed->hwTailP = cpu_to_le32 (td->td_dma);
+ ed->hwHeadP = ed->hwTailP;
+ ed->state = ED_UNLINK;
+ ed->type = usb_pipetype (pipe);
+ }
+
+ ohci->dev [usb_pipedevice (pipe)] = udev;
+
+// FIXME: don't do this if it's linked to the HC,
+// we might clobber data toggle or other state ...
+
+ ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
+ | usb_pipeendpoint (pipe) << 7
+ | (usb_pipeisoc (pipe)? 0x8000: 0)
+ | (usb_pipecontrol (pipe)
+ ? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+ | (udev->speed == USB_SPEED_LOW) << 13
+ | usb_maxpacket (udev, pipe, usb_pipeout (pipe))
+ << 16);
+
+ if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+ ed->int_period = interval;
+ ed->int_load = load;
+ }
+
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return ed;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* request unlinking of an endpoint from an operational HC.
+ * put the ep on the rm_list and stop the bulk or ctrl list
+ * real work is done at the next start frame (SF) hardware interrupt
+ */
+static void ed_unlink (struct usb_device *usb_dev, struct ed *ed)
+{
+ unsigned int frame;
+ struct ohci_hcd *ohci = hcd_to_ohci (usb_dev->bus->hcpriv);
+
+ /* already pending? */
+ if (ed->state & ED_URB_DEL)
+ return;
+ ed->state |= ED_URB_DEL;
+
+ ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL: /* stop control list */
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel (ohci->hc_control,
+ &ohci->regs->control);
+ break;
+ case PIPE_BULK: /* stop bulk list */
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel (ohci->hc_control,
+ &ohci->regs->control);
+ break;
+ }
+
+ frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
+ ed->ed_rm_list = ohci->ed_rm_list [frame];
+ ohci->ed_rm_list [frame] = ed;
+
+ /* enable SOF interrupt */
+ if (!ohci->sleeping) {
+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+ }
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void
+td_fill (struct ohci_hcd *ohci, unsigned int info,
+ dma_addr_t data, int len,
+ struct urb *urb, int index)
+{
+ volatile struct td *td, *td_pt;
+ urb_priv_t *urb_priv = urb->hcpriv;
+
+ if (index >= urb_priv->length) {
+ err ("internal OHCI error: TD index > length");
+ return;
+ }
+
+ /* use this td as the next dummy */
+ td_pt = urb_priv->td [index];
+ td_pt->hwNextTD = 0;
+
+ /* fill the old dummy TD */
+ td = urb_priv->td [index] = dma_to_td (ohci,
+ le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
+
+ td->ed = urb_priv->ed;
+ td->next_dl_td = NULL;
+ td->index = index;
+ td->urb = urb;
+ td->data_dma = data;
+ if (!len)
+ data = 0;
+
+ td->hwINFO = cpu_to_le32 (info);
+ if ((td->ed->type) == PIPE_ISOCHRONOUS) {
+ td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
+ td->ed->last_iso = info & 0xffff;
+ } else {
+ td->hwCBP = cpu_to_le32 (data);
+ }
+ if (data)
+ td->hwBE = cpu_to_le32 (data + len - 1);
+ else
+ td->hwBE = 0;
+ td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
+ td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
+
+ /* append to queue */
+ td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+static void td_submit_urb (struct urb *urb)
+{
+ urb_priv_t *urb_priv = urb->hcpriv;
+ struct ohci_hcd *ohci = hcd_to_ohci (urb->dev->bus->hcpriv);
+ dma_addr_t data;
+ int data_len = urb->transfer_buffer_length;
+ int cnt = 0;
+ __u32 info = 0;
+ unsigned int toggle = 0;
+
+ /* OHCI handles the DATA-toggles itself, we just use the
+ * USB-toggle bits for resetting
+ */
+ if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+ usb_pipeout (urb->pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+ usb_pipeout (urb->pipe), 1);
+ }
+
+ urb_priv->td_cnt = 0;
+
+ if (data_len) {
+#ifdef CONFIG_PCI
+ data = pci_map_single (ohci->hcd.pdev,
+ urb->transfer_buffer, data_len,
+ usb_pipeout (urb->pipe)
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE
+ );
+#else
+# error "what dma addr to use"
+#endif
+ } else
+ data = 0;
+
+ switch (usb_pipetype (urb->pipe)) {
+ case PIPE_BULK:
+ info = usb_pipeout (urb->pipe)
+ ? TD_CC | TD_DP_OUT
+ : TD_CC | TD_DP_IN ;
+ while (data_len > 4096) {
+ td_fill (ohci,
+ info | (cnt? TD_T_TOGGLE:toggle),
+ data, 4096, urb, cnt);
+ data += 4096; data_len -= 4096; cnt++;
+ }
+ info = usb_pipeout (urb->pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle),
+ data, data_len, urb, cnt);
+ cnt++;
+ if ((urb->transfer_flags & USB_ZERO_PACKET)
+ && cnt < urb_priv->length) {
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle),
+ 0, 0, urb, cnt);
+ cnt++;
+ }
+ /* start bulk list */
+ if (!ohci->sleeping)
+ writel (OHCI_BLF, &ohci->regs->cmdstatus);
+ break;
+
+ case PIPE_INTERRUPT:
+ info = TD_CC | toggle;
+ info |= usb_pipeout (urb->pipe)
+ ? TD_DP_OUT
+ : TD_R | TD_DP_IN;
+ td_fill (ohci, info, data, data_len, urb, cnt++);
+ break;
+
+ case PIPE_CONTROL:
+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+ td_fill (ohci, info,
+#ifdef CONFIG_PCI
+ pci_map_single (ohci->hcd.pdev,
+ urb->setup_packet, 8,
+ PCI_DMA_TODEVICE),
+#else
+# error "what dma addr to use"
+#endif
+ 8, urb, cnt++);
+ if (data_len > 0) {
+ info = TD_CC | TD_R | TD_T_DATA1;
+ info |= usb_pipeout (urb->pipe)
+ ? TD_DP_OUT
+ : TD_DP_IN;
+ /* NOTE: mishandles transfers >8K, some >4K */
+ td_fill (ohci, info, data, data_len,
+ urb, cnt++);
+ }
+ info = usb_pipeout (urb->pipe)
+ ? TD_CC | TD_DP_IN | TD_T_DATA1
+ : TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill (ohci, info, data, 0, urb, cnt++);
+ /* start control list */
+ if (!ohci->sleeping)
+ writel (OHCI_CLF, &ohci->regs->cmdstatus);
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+ td_fill (ohci, TD_CC | TD_ISO
+ | ((urb->start_frame + cnt) & 0xffff),
+ data + urb->iso_frame_desc [cnt].offset,
+ urb->iso_frame_desc [cnt].length, urb, cnt);
+ }
+ break;
+ }
+ if (urb_priv->length != cnt)
+ dbg ("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length (struct td *td)
+{
+ __u32 tdINFO, tdBE, tdCBP;
+ __u16 tdPSW;
+ struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
+ int dlen = 0;
+ int cc = 0;
+
+ tdINFO = le32_to_cpup (&td->hwINFO);
+ tdBE = le32_to_cpup (&td->hwBE);
+ tdCBP = le32_to_cpup (&td->hwCBP);
+
+
+ if (tdINFO & TD_ISO) {
+ tdPSW = le16_to_cpu (td->hwPSW [0]);
+ cc = (tdPSW >> 12) & 0xF;
+ if (cc < 0xE) {
+ if (usb_pipeout (urb->pipe)) {
+ dlen = urb->iso_frame_desc [td->index].length;
+ } else {
+ dlen = tdPSW & 0x3ff;
+ }
+ urb->actual_length += dlen;
+ urb->iso_frame_desc [td->index].actual_length = dlen;
+ if (! (urb->transfer_flags & USB_DISABLE_SPD)
+ && (cc == TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+
+ urb->iso_frame_desc [td->index].status
+ = cc_to_error [cc];
+ }
+ } else { /* BULK, INT, CONTROL DATA */
+ if (! (usb_pipetype (urb->pipe) == PIPE_CONTROL &&
+ ((td->index == 0)
+ || (td->index == urb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ urb->actual_length += (td->hwCBP == 0)
+ ? (tdBE - td->data_dma + 1)
+ : (tdCBP - td->data_dma);
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we unreverse the hc-reversed done-list
+ */
+static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
+{
+ __u32 td_list_hc;
+ struct td *td_rev = NULL;
+ struct td *td_list = NULL;
+ urb_priv_t *urb_priv = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave (&ohci->lock, flags);
+
+ td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+ ohci->hcca->done_head = 0;
+
+ while (td_list_hc) {
+ td_list = dma_to_td (ohci, td_list_hc);
+
+ if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
+ urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+ dbg (" USB-error/status: %x : %p",
+ TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
+ td_list);
+ if (td_list->ed->hwHeadP
+ & __constant_cpu_to_le32 (0x1)) {
+ if (urb_priv && ((td_list->index + 1)
+ < urb_priv->length)) {
+ td_list->ed->hwHeadP =
+ (urb_priv->td [urb_priv->length - 1]->hwNextTD
+ & __constant_cpu_to_le32 (0xfffffff0))
+ | (td_list->ed->hwHeadP
+ & __constant_cpu_to_le32 (0x2));
+ urb_priv->td_cnt += urb_priv->length
+ - td_list->index - 1;
+ } else
+ td_list->ed->hwHeadP &=
+ __constant_cpu_to_le32 (0xfffffff2);
+ }
+ }
+
+ td_list->next_dl_td = td_rev;
+ td_rev = td_list;
+ td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
+ }
+ spin_unlock_irqrestore (&ohci->lock, flags);
+ return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* there are some pending requests to unlink
+ * - some URBs/TDs if urb_priv->state == URB_DEL
+ */
+static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
+{
+ unsigned long flags;
+ struct ed *ed;
+ __u32 edINFO;
+ __u32 tdINFO;
+ struct td *td = NULL, *td_next = NULL,
+ *tdHeadP = NULL, *tdTailP;
+ __u32 *td_p;
+ int ctrl = 0, bulk = 0;
+
+ spin_lock_irqsave (&ohci->lock, flags);
+
+ for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) {
+
+ tdTailP = dma_to_td (ohci,
+ le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+ tdHeadP = dma_to_td (ohci,
+ le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+ edINFO = le32_to_cpup (&ed->hwINFO);
+ td_p = &ed->hwHeadP;
+
+ for (td = tdHeadP; td != tdTailP; td = td_next) {
+ struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = td->urb->hcpriv;
+
+ td_next = dma_to_td (ohci,
+ le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+ if ((urb_priv->state == URB_DEL)) {
+ tdINFO = le32_to_cpup (&td->hwINFO);
+ if (TD_CC_GET (tdINFO) < 0xE)
+ dl_transfer_length (td);
+ *td_p = td->hwNextTD | (*td_p
+ & __constant_cpu_to_le32 (0x3));
+
+ /* URB is done; clean up */
+ if (++ (urb_priv->td_cnt) == urb_priv->length)
+// FIXME: we shouldn't hold ohci->lock here, else the
+// completion function can't talk to this hcd ...
+ finish_urb (ohci, urb);
+ } else {
+ td_p = &td->hwNextTD;
+ }
+ }
+
+ ed->state &= ~ED_URB_DEL;
+ tdHeadP = dma_to_td (ohci,
+ le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+
+ if (tdHeadP == tdTailP) {
+ if (ed->state == ED_OPER)
+ ep_unlink (ohci, ed);
+ td_free (ohci, tdTailP);
+ ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+ ed->state = ED_NEW;
+ } else
+ ed->hwINFO &= ~__constant_cpu_to_le32 (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ctrl = 1;
+ break;
+ case PIPE_BULK:
+ bulk = 1;
+ break;
+ }
+ }
+
+ /* maybe reenable control and bulk lists */
+ if (!ohci->disabled) {
+ if (ctrl) /* reset control list */
+ writel (0, &ohci->regs->ed_controlcurrent);
+ if (bulk) /* reset bulk list */
+ writel (0, &ohci->regs->ed_bulkcurrent);
+ if (!ohci->ed_rm_list [!frame]) {
+ if (ohci->ed_controltail)
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ if (ohci->ed_bulktail)
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ }
+
+ ohci->ed_rm_list [frame] = NULL;
+ spin_unlock_irqrestore (&ohci->lock, flags);
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * process normal completions (error or success) and some unlinked eds
+ * this is the main path for handing urbs back to drivers
+ */
+static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
+{
+ struct td *td_list_next = NULL;
+ struct ed *ed;
+ int cc = 0;
+ struct urb *urb;
+ urb_priv_t *urb_priv;
+ __u32 tdINFO, edHeadP, edTailP;
+
+ unsigned long flags;
+
+ while (td_list) {
+ td_list_next = td_list->next_dl_td;
+
+ urb = td_list->urb;
+ urb_priv = urb->hcpriv;
+ tdINFO = le32_to_cpup (&td_list->hwINFO);
+
+ ed = td_list->ed;
+
+ dl_transfer_length (td_list);
+
+ /* error code of transfer */
+ cc = TD_CC_GET (tdINFO);
+ if (cc == TD_CC_STALL)
+ usb_endpoint_halt (urb->dev,
+ usb_pipeendpoint (urb->pipe),
+ usb_pipeout (urb->pipe));
+
+ if (! (urb->transfer_flags & USB_DISABLE_SPD)
+ && (cc == TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+
+ if (++ (urb_priv->td_cnt) == urb_priv->length) {
+ /*
+ * Except for periodic transfers, both branches do
+ * the same thing. Periodic urbs get reissued until
+ * they're "deleted" with usb_unlink_urb.
+ */
+ if ((ed->state & (ED_OPER | ED_UNLINK))
+ && (urb_priv->state != URB_DEL)) {
+ spin_lock (&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = cc_to_error [cc];
+ spin_unlock (&urb->lock);
+ return_urb (ohci, urb);
+ } else
+ finish_urb (ohci, urb);
+ }
+
+ spin_lock_irqsave (&ohci->lock, flags);
+ if (ed->state != ED_NEW) {
+ edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+ edTailP = le32_to_cpup (&ed->hwTailP);
+
+// FIXME: ED_UNLINK is very fuzzy w.r.t. what the hc knows...
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink (ohci, ed);
+ }
+ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ td_list = td_list_next;
+ }
+}
+
diff --git a/drivers/usb/hcd/ohci.h b/drivers/usb/hcd/ohci.h
new file mode 100644
index 000000000..8b2fbff24
--- /dev/null
+++ b/drivers/usb/hcd/ohci.h
@@ -0,0 +1,360 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under GPL
+ * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
+ */
+
+static const int cc_to_error [16] = {
+
+/* map OHCI status to errno values */
+ /* No Error */ 0,
+ /* CRC Error */ -EILSEQ,
+ /* Bit Stuff */ -EPROTO,
+ /* Data Togg */ -EILSEQ,
+ /* Stall */ -EPIPE,
+ /* DevNotResp */ -ETIMEDOUT,
+ /* PIDCheck */ -EPROTO,
+ /* UnExpPID */ -EPROTO,
+ /* DataOver */ -EOVERFLOW,
+ /* DataUnder */ -EREMOTEIO,
+ /* (for hw) */ -EIO,
+ /* (for hw) */ -EIO,
+ /* BufferOver */ -ECOMM,
+ /* BuffUnder */ -ENOSR,
+ /* (for HCD) */ -EALREADY,
+ /* (for HCD) */ -EALREADY
+};
+
+
+/* ED States */
+
+#define ED_NEW 0x00 /* unused, no dummy td */
+#define ED_UNLINK 0x01 /* dummy td, maybe linked to hc */
+#define ED_OPER 0x02 /* dummy td, _is_ linked to hc */
+
+#define ED_URB_DEL 0x08 /* masked in */
+
+/* usb_ohci_ed */
+struct ed {
+ /* first fields are hardware-specified */
+ __u32 hwINFO;
+ __u32 hwTailP;
+ __u32 hwHeadP;
+ __u32 hwNextED;
+
+ struct ed * ed_prev;
+ __u8 int_period;
+ __u8 int_branch;
+ __u8 int_load;
+ __u8 int_interval;
+ __u8 state; // ED_{NEW,UNLINK,OPER}
+ __u8 type;
+ __u16 last_iso;
+ struct ed * ed_rm_list;
+
+ dma_addr_t dma;
+ __u32 unused [3];
+} __attribute((aligned(16)));
+
+
+/* TD info field */
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R 0x00040000
+#define TD_DI 0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_ISO 0x00010000
+#define TD_DEL 0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+ /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+ /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED 0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+ /* first hardware fields are in all tds */
+ __u32 hwINFO;
+ __u32 hwCBP; /* Current Buffer Pointer */
+ __u32 hwNextTD; /* Next TD Pointer */
+ __u32 hwBE; /* Memory Buffer End Pointer */
+
+ __u16 hwPSW [MAXPSW]; /* PSW is only for ISO */
+
+ __u8 unused;
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct urb *urb;
+
+ dma_addr_t td_dma;
+ dma_addr_t data_dma;
+ __u32 unused2 [2];
+} __attribute((aligned(32))); /* iso needs 32 */
+
+#define OHCI_ED_SKIP (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. The host controller is
+ * told the base address of it. It must be 256-byte aligned.
+ */
+#define NUM_INTS 32 /* part of the OHCI standard */
+struct ohci_hcca {
+ __u32 int_table [NUM_INTS]; /* Interrupt ED table */
+ __u16 frame_no; /* current frame number */
+ __u16 pad1; /* set to 0 on each frame_no change */
+ __u32 done_head; /* info returned for an interrupt */
+ u8 reserved_for_hc [116];
+} __attribute((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region. This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+ /* control and status registers */
+ __u32 revision;
+ __u32 control;
+ __u32 cmdstatus;
+ __u32 intrstatus;
+ __u32 intrenable;
+ __u32 intrdisable;
+
+ /* memory pointers */
+ __u32 hcca;
+ __u32 ed_periodcurrent;
+ __u32 ed_controlhead;
+ __u32 ed_controlcurrent;
+ __u32 ed_bulkhead;
+ __u32 ed_bulkcurrent;
+ __u32 donehead;
+
+ /* frame counters */
+ __u32 fminterval;
+ __u32 fmremaining;
+ __u32 fmnumber;
+ __u32 periodicstart;
+ __u32 lsthresh;
+
+ /* Root hub ports */
+ struct ohci_roothub_regs {
+ __u32 a;
+ __u32 b;
+ __u32 status;
+ __u32 portstatus [MAX_ROOT_PORTS];
+ } roothub;
+
+ /* and some optional registers for legacy compatibility */
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+
+/* urb */
+typedef struct urb_priv
+{
+ struct ed *ed;
+ __u16 length; // # tds in this request
+ __u16 td_cnt; // tds already serviced
+ int state;
+ struct td *td [0]; // all TDs in this request
+
+} urb_priv_t;
+
+#define URB_DEL 1
+
+
+/* Hash struct used for TD/ED hashing */
+struct hash_t {
+ void *virt;
+ dma_addr_t dma;
+ struct hash_t *next; // chaining for collision cases
+};
+
+/* List of TD/ED hash entries */
+struct hash_list_t {
+ struct hash_t *head;
+ struct hash_t *tail;
+};
+
+#define TD_HASH_SIZE 64 /* power'o'two */
+#define ED_HASH_SIZE 64 /* power'o'two */
+
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
+#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
+
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+struct ohci_hcd {
+ spinlock_t lock;
+
+ /*
+ * I/O memory used to communicate with the HC (uncached);
+ */
+ struct ohci_regs *regs;
+
+ /*
+ * main memory used to communicate with the HC (uncached)
+ */
+ struct ohci_hcca *hcca;
+ dma_addr_t hcca_dma;
+
+ struct ed *ed_rm_list [2]; /* to be removed */
+
+ struct ed *ed_bulktail; /* last in bulk list */
+ struct ed *ed_controltail; /* last in ctrl list */
+ struct ed *ed_isotail; /* last in iso list */
+
+#ifdef CONFIG_PCI
+ struct pci_pool *td_cache;
+ struct pci_pool *ed_cache;
+ struct hash_list_t td_hash [TD_HASH_SIZE];
+ struct hash_list_t ed_hash [ED_HASH_SIZE];
+#endif
+
+ /*
+ * driver state
+ */
+ int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
+ int ohci_int_load [NUM_INTS];
+ u32 hc_control; /* copy of hc control reg */
+ struct usb_device *dev [128];
+
+ unsigned long flags; /* for HC bugs */
+#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
+
+ /*
+ * framework state
+ */
+ struct usb_hcd hcd;
+};
+
+#define hcd_to_ohci(hcd_ptr) list_entry(hcd_ptr, struct ohci_hcd, hcd)
+
diff --git a/drivers/usb/hpusbscsi.c b/drivers/usb/hpusbscsi.c
index b96e10329..95b3394d3 100644
--- a/drivers/usb/hpusbscsi.c
+++ b/drivers/usb/hpusbscsi.c
@@ -272,7 +272,7 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
if (!srb->bufflen) {
usb_callback = simple_command_callback;
} else {
- if (srb->use_sg) {
+ if (likely(srb->use_sg)) {
usb_callback = scatter_gather_callback;
hpusbscsi->fragment = 0;
} else {
@@ -288,10 +288,6 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
TRACE_STATE;
- if (hpusbscsi->state != HP_STATE_FREE) {
- printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
- return 1; /* This must not happen */
- }
/* We zero the sense buffer to avoid confusing user space */
memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
@@ -313,10 +309,10 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
hpusbscsi->srb = srb;
res = usb_submit_urb(&hpusbscsi->dataurb);
- if (res) {
+ if (unlikely(res)) {
hpusbscsi->state = HP_STATE_FREE;
TRACE_STATE;
- if (callback) {
+ if (likely(callback != NULL)) {
srb->result = DID_ERROR;
callback(srb);
}
@@ -355,7 +351,7 @@ static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
static void handle_usb_error (struct hpusbscsi *hpusbscsi)
{
- if (hpusbscsi->scallback != NULL) {
+ if (likely(hpusbscsi->scallback != NULL)) {
hpusbscsi->srb->result = DID_ERROR;
hpusbscsi->scallback(hpusbscsi->srb);
}
@@ -367,8 +363,8 @@ static void control_interrupt_callback (struct urb *u)
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
- if(u->status < 0) {
- if (hpusbscsi->state != HP_STATE_FREE)
+ if(unlikely(u->status < 0)) {
+ if (likely(hpusbscsi->state != HP_STATE_FREE))
handle_usb_error(hpusbscsi);
return;
}
@@ -402,7 +398,7 @@ DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
static void simple_command_callback(struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
- if (u->status<0) {
+ if (unlikely(u->status<0)) {
handle_usb_error(hpusbscsi);
return;
}
@@ -411,7 +407,7 @@ static void simple_command_callback(struct urb *u)
TRACE_STATE;
hpusbscsi->state = HP_STATE_WAIT;
} else {
- if (hpusbscsi->scallback != NULL)
+ if (likely(hpusbscsi->scallback != NULL))
hpusbscsi->scallback(hpusbscsi->srb);
hpusbscsi->state = HP_STATE_FREE;
TRACE_STATE;
@@ -426,7 +422,7 @@ static void scatter_gather_callback(struct urb *u)
int res;
DEBUG("Going through scatter/gather\n");
- if (u->status < 0) {
+ if (unlikely(u->status < 0)) {
handle_usb_error(hpusbscsi);
return;
}
@@ -453,7 +449,7 @@ static void scatter_gather_callback(struct urb *u)
);
res = usb_submit_urb(u);
- if (res)
+ if (unlikely(res))
hpusbscsi->state = HP_STATE_ERROR;
TRACE_STATE;
}
@@ -462,20 +458,20 @@ static void simple_done (struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
- if (u->status < 0) {
+ if (unlikely(u->status < 0)) {
handle_usb_error(hpusbscsi);
return;
}
DEBUG("Data transfer done\n");
TRACE_STATE;
if (hpusbscsi->state != HP_STATE_PREMATURE) {
- if (u->status < 0)
+ if (unlikely(u->status < 0))
hpusbscsi->state = HP_STATE_ERROR;
else
hpusbscsi->state = HP_STATE_WAIT;
TRACE_STATE;
} else {
- if (hpusbscsi->scallback != NULL)
+ if (likely(hpusbscsi->scallback != NULL))
hpusbscsi->scallback(hpusbscsi->srb);
hpusbscsi->state = HP_STATE_FREE;
}
@@ -486,7 +482,7 @@ static void simple_payload_callback (struct urb *u)
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
int res;
- if (u->status<0) {
+ if (unlikely(u->status<0)) {
handle_usb_error(hpusbscsi);
return;
}
@@ -502,7 +498,7 @@ static void simple_payload_callback (struct urb *u)
);
res = usb_submit_urb(u);
- if (res) {
+ if (unlikely(res)) {
handle_usb_error(hpusbscsi);
return;
}
@@ -511,10 +507,11 @@ static void simple_payload_callback (struct urb *u)
hpusbscsi->state = HP_STATE_WORKING;
TRACE_STATE;
} else {
- if (hpusbscsi->scallback != NULL)
+ if (likely(hpusbscsi->scallback != NULL))
hpusbscsi->scallback(hpusbscsi->srb);
hpusbscsi->state = HP_STATE_FREE;
TRACE_STATE;
}
}
+
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 78b9f1926..f741f808a 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -557,6 +557,10 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
dbg("port %d, portstatus %x, change %x, %s", port + 1,
portstatus, portchange, portspeed (portstatus));
+ /* Device went away? */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return 1;
+
/* bomb out completely if something weird happened */
if ((portchange & USB_PORT_STAT_C_CONNECTION))
return -1;
diff --git a/drivers/usb/ibmcam.h b/drivers/usb/ibmcam.h
index b2511dbdc..6a5e1cd02 100644
--- a/drivers/usb/ibmcam.h
+++ b/drivers/usb/ibmcam.h
@@ -147,7 +147,7 @@ struct usb_device;
struct ibmcam_sbuf {
char *data;
- urb_t *urb;
+ struct urb *urb;
};
struct ibmcam_frame {
diff --git a/drivers/usb/kaweth.c b/drivers/usb/kaweth.c
index a26100655..046674d34 100644
--- a/drivers/usb/kaweth.c
+++ b/drivers/usb/kaweth.c
@@ -953,7 +953,7 @@ struct usb_api_data {
/*-------------------------------------------------------------------*
* completion handler for compatibility wrappers (sync control/bulk) *
*-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
{
struct usb_api_data *awd = (struct usb_api_data *)urb->context;
@@ -966,7 +966,7 @@ static void usb_api_blocking_completion(urb_t *urb)
*-------------------------------------------------------------------*/
// Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
DECLARE_WAITQUEUE(wait, current);
struct usb_api_data awd;
@@ -1017,7 +1017,7 @@ int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
struct usb_ctrlrequest *cmd, void *data, int len,
int timeout)
{
- urb_t *urb;
+ struct urb *urb;
int retv;
int length;
diff --git a/drivers/usb/microtek.c b/drivers/usb/microtek.c
index fb16a6484..d74b70273 100644
--- a/drivers/usb/microtek.c
+++ b/drivers/usb/microtek.c
@@ -320,11 +320,6 @@ static inline void mts_debug_dump(struct mts_desc* dummy)
#endif
-
-/* static inline int mts_is_aborting(struct mts_desc* desc) {
- return (atomic_read(&desc->context.do_abort));
-} */
-
static inline void mts_urb_abort(struct mts_desc* desc) {
MTS_DEBUG_GOT_HERE();
mts_debug_dump(desc);
@@ -504,7 +499,7 @@ void mts_int_submit_urb (struct urb* transfer,
transfer->status = 0;
res = usb_submit_urb( transfer );
- if ( res ) {
+ if ( unlikely(res) ) {
MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
context->srb->result = DID_ERROR << 16;
mts_transfer_cleanup(transfer);
@@ -518,7 +513,7 @@ static void mts_transfer_cleanup( struct urb *transfer )
{
MTS_INT_INIT();
- if ( context->final_callback )
+ if ( likely(context->final_callback != NULL) )
context->final_callback(context->srb);
}
@@ -556,7 +551,7 @@ static void mts_data_done( struct urb* transfer )
if ( context->data_length != transfer->actual_length ) {
context->srb->resid = context->data_length - transfer->actual_length;
- } else if ( transfer->status ) {
+ } else if ( unlikely(transfer->status) ) {
context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
}
@@ -571,7 +566,7 @@ static void mts_command_done( struct urb *transfer )
{
MTS_INT_INIT();
- if ( transfer->status ) {
+ if ( unlikely(transfer->status) ) {
if (transfer->status == -ENOENT) {
/* We are being killed */
MTS_DEBUG_GOT_HERE();
@@ -605,7 +600,7 @@ static void mts_do_sg (struct urb* transfer)
MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
- if (transfer->status) {
+ if (unlikely(transfer->status)) {
context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
mts_transfer_cleanup(transfer);
}
@@ -704,7 +699,7 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
srb->result = DID_BAD_TARGET << 16;
- if(callback)
+ if(likely(callback != NULL))
callback(srb);
goto out;
@@ -726,11 +721,11 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
res=usb_submit_urb(&desc->urb);
- if(res){
+ if(unlikely(res)){
MTS_ERROR("error %d submitting URB\n",(int)res);
srb->result = DID_ERROR << 16;
- if(callback)
+ if(likely(callback != NULL))
callback(srb);
}
@@ -1063,3 +1058,4 @@ MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index 7a44e9310..5a61edd2c 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -3875,7 +3875,7 @@ ov511_postprocess(struct usb_ov511 *ov511, struct ov511_frame *frame)
**********************************************************************/
static int
-ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
+ov511_move_data(struct usb_ov511 *ov511, struct urb *urb)
{
unsigned char *cdata;
int data_size, num, offset, i, totlen = 0;
@@ -4108,7 +4108,7 @@ check_middle:
}
static int
-ov518_move_data(struct usb_ov511 *ov511, urb_t *urb)
+ov518_move_data(struct usb_ov511 *ov511, struct urb *urb)
{
unsigned char *cdata;
int i, data_size, totlen = 0;
@@ -4369,7 +4369,7 @@ ov511_isoc_irq(struct urb *urb)
static int
ov511_init_isoc(struct usb_ov511 *ov511)
{
- urb_t *urb;
+ struct urb *urb;
int fx, err, n, size;
PDEBUG(3, "*** Initializing capture ***");
diff --git a/drivers/usb/ov511.h b/drivers/usb/ov511.h
index a3f55f7e5..0bdf18885 100644
--- a/drivers/usb/ov511.h
+++ b/drivers/usb/ov511.h
@@ -366,7 +366,7 @@ struct ov511_i2c_struct {
struct ov511_sbuf {
char *data;
- urb_t *urb;
+ struct urb *urb;
};
enum {
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 5b1b9fb66..ce187fb48 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -94,7 +94,7 @@ MODULE_DEVICE_TABLE (usb, pegasus_ids);
static int update_eth_regs_async( pegasus_t * );
/* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback( urb_t *urb )
+static void ctrl_callback( struct urb *urb )
{
pegasus_t *pegasus = urb->context;
diff --git a/drivers/usb/se401.c b/drivers/usb/se401.c
index c6747eb9c..7029693e2 100644
--- a/drivers/usb/se401.c
+++ b/drivers/usb/se401.c
@@ -610,7 +610,7 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
*/
static int se401_start_stream(struct usb_se401 *se401)
{
- urb_t *urb;
+ struct urb *urb;
int err=0, i;
se401->streaming=1;
diff --git a/drivers/usb/se401.h b/drivers/usb/se401.h
index e1fd7d241..861210147 100644
--- a/drivers/usb/se401.h
+++ b/drivers/usb/se401.h
@@ -197,8 +197,8 @@ struct usb_se401 {
char *fbuf; /* Videodev buffer area */
- urb_t *urb[SE401_NUMSBUF];
- urb_t *inturb;
+ struct urb *urb[SE401_NUMSBUF];
+ struct urb *inturb;
int button;
int buttonpressed;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ff4e8e101..d323a742f 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -138,6 +138,7 @@ static __devinitdata struct usb_device_id id_table_sio [] = {
static __devinitdata struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+ { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */
};
@@ -145,6 +146,7 @@ static __devinitdata struct usb_device_id id_table_8U232AM [] = {
static __devinitdata struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+ { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 321ae1914..5254d4924 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -22,6 +22,8 @@
#define FTDI_VID 0x0403 /* Vendor Id */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
+#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
+#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index d7968e619..de7463529 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2456,7 +2456,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
{
struct edgeport_serial *edge_serial = (struct edgeport_serial *)edge_port->port->serial->private;
int status = 0;
- urb_t *urb;
+ struct urb *urb;
int timeout;
usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index d73a7c3a7..7672fc1c5 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -2,6 +2,7 @@
* USB IR Dongle driver
*
* Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.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
@@ -20,6 +21,12 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * 2002_Jan_14 gb
+ * Added module parameter to force specific number of XBOFs.
+ * Added ir_xbof_change().
+ * Reorganized read_bulk_callback error handling.
+ * Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
+ *
* 2001_Nov_08 greg kh
* Changed the irda_usb_find_class_desc() function based on comments and
* code from Martin Diehl.
@@ -62,13 +69,15 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "USB IR Dongle driver"
/* if overridden by the user, then use their value for the size of the read and
* write urbs */
static int buffer_size = 0;
+/* if overridden by the user, then use the specified number of XBOFs */
+static int xbof = -1;
static int ir_startup (struct usb_serial *serial);
static int ir_open (struct usb_serial_port *port, struct file *filep);
@@ -78,6 +87,9 @@ static void ir_write_bulk_callback (struct urb *urb);
static void ir_read_bulk_callback (struct urb *urb);
static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static u8 ir_baud = 0;
+static u8 ir_xbof = 0;
+static u8 ir_add_bof = 0;
static __devinitdata struct usb_device_id id_table [] = {
{ USB_DEVICE(0x050f, 0x0180) }, /* KC Technology, KC-180 */
@@ -148,14 +160,16 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
- dbg(__FUNCTION__ " - ret=%d", ret);
+ dbg("%s - ret=%d", __FUNCTION__, ret);
if (ret < sizeof(*desc)) {
- dbg(__FUNCTION__ " - class descriptor read %s (%d)",
- (ret<0) ? "failed" : "too short", ret);
+ dbg("%s - class descriptor read %s (%d)",
+ __FUNCTION__,
+ (ret<0) ? "failed" : "too short",
+ ret);
goto error;
}
if (desc->bDescriptorType != USB_DT_IRDA) {
- dbg(__FUNCTION__ " - bad class descriptor type");
+ dbg("%s - bad class descriptor type", __FUNCTION__);
goto error;
}
@@ -166,6 +180,28 @@ error:
return NULL;
}
+
+static u8 ir_xbof_change(u8 xbof)
+{
+ u8 result;
+ /* reference irda-usb.c */
+ switch(xbof) {
+ case 48: result = 0x10; break;
+ case 28:
+ case 24: result = 0x20; break;
+ default:
+ case 12: result = 0x30; break;
+ case 5:
+ case 6: result = 0x40; break;
+ case 3: result = 0x50; break;
+ case 2: result = 0x60; break;
+ case 1: result = 0x70; break;
+ case 0: result = 0x80; break;
+ }
+ return(result);
+}
+
+
static int ir_startup (struct usb_serial *serial)
{
struct irda_class_desc *irda_desc;
@@ -175,16 +211,30 @@ static int ir_startup (struct usb_serial *serial)
err ("IRDA class descriptor not found, device not bound");
return -ENODEV;
}
- dbg (__FUNCTION__" - Baud rates supported: %s%s%s%s%s%s%s%s%s",
- (irda_desc->wBaudRate & 0x0001) ? "2400 " : "",
- irda_desc->wBaudRate & 0x0002 ? "9600 " : "",
- irda_desc->wBaudRate & 0x0004 ? "19200 " : "",
- irda_desc->wBaudRate & 0x0008 ? "38400 " : "",
- irda_desc->wBaudRate & 0x0010 ? "57600 " : "",
- irda_desc->wBaudRate & 0x0020 ? "115200 " : "",
- irda_desc->wBaudRate & 0x0040 ? "576000 " : "",
- irda_desc->wBaudRate & 0x0080 ? "1152000 " : "",
- irda_desc->wBaudRate & 0x0100 ? "4000000 " : "");
+
+ dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+ __FUNCTION__,
+ (irda_desc->wBaudRate & 0x0001) ? " 2400" : "",
+ (irda_desc->wBaudRate & 0x0002) ? " 9600" : "",
+ (irda_desc->wBaudRate & 0x0004) ? " 19200" : "",
+ (irda_desc->wBaudRate & 0x0008) ? " 38400" : "",
+ (irda_desc->wBaudRate & 0x0010) ? " 57600" : "",
+ (irda_desc->wBaudRate & 0x0020) ? " 115200" : "",
+ (irda_desc->wBaudRate & 0x0040) ? " 576000" : "",
+ (irda_desc->wBaudRate & 0x0080) ? " 1152000" : "",
+ (irda_desc->wBaudRate & 0x0100) ? " 4000000" : "");
+
+ switch( irda_desc->bmAdditionalBOFs ) {
+ case 0x01: ir_add_bof = 48; break;
+ case 0x02: ir_add_bof = 24; break;
+ case 0x04: ir_add_bof = 12; break;
+ case 0x08: ir_add_bof = 6; break;
+ case 0x10: ir_add_bof = 3; break;
+ case 0x20: ir_add_bof = 2; break;
+ case 0x40: ir_add_bof = 1; break;
+ case 0x80: ir_add_bof = 0; break;
+ default:
+ }
kfree (irda_desc);
@@ -200,7 +250,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
if (port_paranoia_check (port, __FUNCTION__))
return -ENODEV;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
down (&port->sem);
@@ -211,7 +261,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
/* override the default buffer sizes */
buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!buffer) {
- err (__FUNCTION__ " - out of memory.");
+ err ("%s - out of memory.", __FUNCTION__);
return -ENOMEM;
}
kfree (port->read_urb->transfer_buffer);
@@ -220,7 +270,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!buffer) {
- err (__FUNCTION__ " - out of memory.");
+ err ("%s - out of memory.", __FUNCTION__);
return -ENOMEM;
}
kfree (port->write_urb->transfer_buffer);
@@ -230,13 +280,18 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
}
/* Start reading from the device */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ir_read_bulk_callback, port);
+ usb_fill_bulk_urb (
+ port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ ir_read_bulk_callback,
+ port);
+ port->read_urb->transfer_flags = USB_QUEUE_BULK;
result = usb_submit_urb(port->read_urb);
if (result)
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
}
up (&port->sem);
@@ -251,7 +306,7 @@ static void ir_close (struct usb_serial_port *port, struct file * filp)
if (port_paranoia_check (port, __FUNCTION__))
return;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
@@ -276,11 +331,12 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned
{
unsigned char *transfer_buffer;
int result;
+ int transfer_size;
- dbg(__FUNCTION__ " - port = %d, count = %d", port->number, count);
+ dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count);
if (!port->tty) {
- err (__FUNCTION__ " - no tty???");
+ err ("%s - no tty???", __FUNCTION__);
return 0;
}
@@ -288,37 +344,49 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned
return 0;
if (port->write_urb->status == -EINPROGRESS) {
- dbg (__FUNCTION__ " - already writing");
+ dbg ("%s - already writing", __FUNCTION__);
return 0;
}
+ transfer_buffer = port->write_urb->transfer_buffer;
+ transfer_size = min(count, port->bulk_out_size - 1);
+
/*
- * The first byte of the packet we send to the device contains a BOD
- * and baud rate change. So we set it to 0.
+ * The first byte of the packet we send to the device contains an
+ * inband header which indicates an additional number of BOFs and
+ * a baud rate change.
+ *
* See section 5.4.2.2 of the USB IrDA spec.
*/
- transfer_buffer = port->write_urb->transfer_buffer;
- count = min (port->bulk_out_size-1, count);
+ *transfer_buffer = ir_xbof | ir_baud;
+ ++transfer_buffer;
+
if (from_user) {
- if (copy_from_user (&transfer_buffer[1], buf, count))
+ if (copy_from_user (transfer_buffer, buf, transfer_size))
return -EFAULT;
} else {
- memcpy (&transfer_buffer[1], buf, count);
+ memcpy (transfer_buffer, buf, transfer_size);
}
- /* use 12 XBOF's as default */
- transfer_buffer[0] = 0x30;
+ usb_fill_bulk_urb (
+ port->write_urb,
+ port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer,
+ transfer_size + 1,
+ ir_write_bulk_callback,
+ port);
- usb_serial_debug_data (__FILE__, __FUNCTION__, count+1, transfer_buffer);
+ port->write_urb->transfer_flags
+ = USB_QUEUE_BULK
+ | USB_ZERO_PACKET;
- port->write_urb->transfer_buffer_length = count + 1;
- port->write_urb->dev = port->serial->dev;
- port->write_urb->transfer_flags |= USB_ZERO_PACKET;
result = usb_submit_urb (port->write_urb);
if (result)
- err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
else
- result = count;
+ result = transfer_size;
return result;
}
@@ -330,13 +398,19 @@ static void ir_write_bulk_callback (struct urb *urb)
if (port_paranoia_check (port, __FUNCTION__))
return;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
- dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
}
+ usb_serial_debug_data (
+ __FILE__,
+ __FUNCTION__,
+ urb->actual_length,
+ urb->transfer_buffer);
+
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
@@ -354,34 +428,87 @@ static void ir_read_bulk_callback (struct urb *urb)
if (port_paranoia_check (port, __FUNCTION__))
return;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if (!serial) {
- dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
- if (urb->status) {
- dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ if (!port->open_count) {
+ dbg("%s - port closed.", __FUNCTION__);
return;
}
- usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+ switch (urb->status) {
+
+ case 0: /* Successful */
+
+ /*
+ * The first byte of the packet we get from the device
+ * contains a busy indicator and baud rate change.
+ * See section 5.4.1.2 of the USB IrDA spec.
+ */
+ if((*data & 0x0f) > 0) ir_baud = *data & 0x0f;
+
+ usb_serial_debug_data (
+ __FILE__,
+ __FUNCTION__,
+ urb->actual_length,
+ data);
+
+ /*
+ * Bypass flip-buffers, and feed the ldisc directly
+ * due to our potentally large buffer size. Since we
+ * used to set low_latency, this is exactly what the
+ * tty layer did anyway :)
+ */
+ tty = port->tty;
+
+ tty->ldisc.receive_buf(
+ tty,
+ data+1,
+ NULL,
+ urb->actual_length-1);
+
+ /*
+ * No break here.
+ * We want to resubmit the urb so we can read
+ * again.
+ */
+
+ case -EPROTO: /* taking inspiration from pl2303.c */
+
+ /* Continue trying to always read */
+ usb_fill_bulk_urb (
+ port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ ir_read_bulk_callback,
+ port);
+
+ port->read_urb->transfer_flags = USB_QUEUE_BULK;
+
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err("%s - failed resubmitting read urb, error %d",
+ __FUNCTION__,
+ result);
+
+ break ;
+
+ default:
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__,
+ urb->status);
+ break ;
- /* Bypass flip-buffers, and feed the ldisc directly due to our
- * potentally large buffer size. Since we used to set low_latency,
- * this is exactly what the tty layer did anyway :) */
- tty = port->tty;
- tty->ldisc.receive_buf(tty, data+1, NULL, urb->actual_length-1);
+ }
- /* Continue trying to always read */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ir_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb);
- if (result)
- err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
return;
}
@@ -390,12 +517,11 @@ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_te
unsigned char *transfer_buffer;
unsigned int cflag;
int result;
- u8 baud;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if ((!port->tty) || (!port->tty->termios)) {
- dbg(__FUNCTION__" - no tty structures");
+ dbg("%s - no tty structures", __FUNCTION__);
return;
}
@@ -404,44 +530,70 @@ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_te
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg(__FUNCTION__ " - nothing to change...");
+ dbg("%s - nothing to change...", __FUNCTION__);
return;
}
}
/* All we can change is the baud rate */
if (cflag & CBAUD) {
- dbg (__FUNCTION__ " - asking for baud %d", tty_get_baud_rate(port->tty));
+
+ dbg ("%s - asking for baud %d",
+ __FUNCTION__,
+ tty_get_baud_rate(port->tty));
+
/*
* FIXME, we should compare the baud request against the
* capability stated in the IR header that we got in the
* startup funtion.
*/
switch (cflag & CBAUD) {
- case B2400: baud = SPEED_2400; break;
- case B9600: baud = SPEED_9600; break;
- case B19200: baud = SPEED_19200; break;
- case B38400: baud = SPEED_38400; break;
- case B57600: baud = SPEED_57600; break;
- case B115200: baud = SPEED_115200; break;
- case B576000: baud = SPEED_576000; break;
- case B1152000: baud = SPEED_1152000; break;
- case B4000000: baud = SPEED_4000000; break;
+ case B2400: ir_baud = SPEED_2400; break;
default:
- err ("ir-usb driver does not support the baudrate (%d) requested", tty_get_baud_rate(port->tty));
- return;
+ case B9600: ir_baud = SPEED_9600; break;
+ case B19200: ir_baud = SPEED_19200; break;
+ case B38400: ir_baud = SPEED_38400; break;
+ case B57600: ir_baud = SPEED_57600; break;
+ case B115200: ir_baud = SPEED_115200; break;
+ case B576000: ir_baud = SPEED_576000; break;
+ case B1152000: ir_baud = SPEED_1152000; break;
+ case B4000000: ir_baud = SPEED_4000000; break;
}
-
+
+ if (xbof == -1) {
+ ir_xbof = ir_xbof_change(ir_add_bof);
+ } else {
+ ir_xbof = ir_xbof_change(xbof) ;
+ }
+
+ /* Notify the tty driver that the termios have changed. */
+ port->tty->ldisc.set_termios(port->tty, NULL);
+
/* FIXME need to check to see if our write urb is busy right
- * now, or use a urb pool. */
- /* send the baud change out on an "empty" data packet */
+ * now, or use a urb pool.
+ *
+ * send the baud change out on an "empty" data packet
+ */
transfer_buffer = port->write_urb->transfer_buffer;
- transfer_buffer[0] = baud;
- port->write_urb->transfer_buffer_length = 1;
- port->write_urb->dev = port->serial->dev;
+ *transfer_buffer = ir_xbof | ir_baud;
+
+ usb_fill_bulk_urb (
+ port->write_urb,
+ port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer,
+ 1,
+ ir_write_bulk_callback,
+ port);
+
+ port->write_urb->transfer_flags
+ = USB_QUEUE_BULK
+ | USB_ZERO_PACKET;
+
result = usb_submit_urb (port->write_urb);
if (result)
- err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
}
return;
}
@@ -470,6 +622,8 @@ MODULE_LICENSE("GPL");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
+MODULE_PARM(xbof, "i");
+MODULE_PARM_DESC(xbof, "Force specific number of XBOFs");
MODULE_PARM(buffer_size, "i");
MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index e3062760f..43bc791c6 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -109,11 +109,11 @@ struct keyspan_serial_private {
const keyspan_device_details *device_details;
- urb_t *instat_urb;
+ struct urb *instat_urb;
char instat_buf[INSTAT_BUFLEN];
/* XXX this one probably will need a lock */
- urb_t *glocont_urb;
+ struct urb *glocont_urb;
char glocont_buf[GLOCONT_BUFLEN];
};
@@ -128,18 +128,18 @@ struct keyspan_port_private {
const keyspan_device_details *device_details;
/* Input endpoints and buffer for this port */
- urb_t *in_urbs[2];
+ struct urb *in_urbs[2];
char in_buffer[2][64];
/* Output endpoints and buffer for this port */
- urb_t *out_urbs[2];
+ struct urb *out_urbs[2];
char out_buffer[2][64];
/* Input ack endpoint */
- urb_t *inack_urb;
+ struct urb *inack_urb;
char inack_buffer[1];
/* Output control endpoint */
- urb_t *outcont_urb;
+ struct urb *outcont_urb;
char outcont_buffer[64];
/* Settings for the port */
@@ -178,15 +178,7 @@ struct keyspan_port_private {
/* Functions used by new usb-serial code. */
static int __init keyspan_init (void)
{
- usb_serial_register (&keyspan_usa18x_pre_device);
- usb_serial_register (&keyspan_usa19_pre_device);
- usb_serial_register (&keyspan_usa19w_pre_device);
- usb_serial_register (&keyspan_usa28_pre_device);
- usb_serial_register (&keyspan_usa28x_pre_device);
- usb_serial_register (&keyspan_usa28xa_pre_device);
- usb_serial_register (&keyspan_usa28xb_pre_device);
- usb_serial_register (&keyspan_usa49w_pre_device);
-
+ usb_serial_register (&keyspan_pre_device);
usb_serial_register (&keyspan_usa18x_device);
usb_serial_register (&keyspan_usa19_device);
usb_serial_register (&keyspan_usa19w_device);
@@ -203,15 +195,7 @@ static int __init keyspan_init (void)
static void __exit keyspan_exit (void)
{
- usb_serial_deregister (&keyspan_usa18x_pre_device);
- usb_serial_deregister (&keyspan_usa19_pre_device);
- usb_serial_deregister (&keyspan_usa19w_pre_device);
- usb_serial_deregister (&keyspan_usa28_pre_device);
- usb_serial_deregister (&keyspan_usa28x_pre_device);
- usb_serial_deregister (&keyspan_usa28xa_pre_device);
- usb_serial_deregister (&keyspan_usa28xb_pre_device);
- usb_serial_deregister (&keyspan_usa49w_pre_device);
-
+ usb_serial_deregister (&keyspan_pre_device);
usb_serial_deregister (&keyspan_usa18x_device);
usb_serial_deregister (&keyspan_usa19_device);
usb_serial_deregister (&keyspan_usa19w_device);
@@ -340,7 +324,7 @@ static int keyspan_write(struct usb_serial_port *port, int from_user,
const keyspan_device_details *d_details;
int flip;
int left, todo;
- urb_t *this_urb;
+ struct urb *this_urb;
int err;
p_priv = (struct keyspan_port_private *)(port->private);
@@ -869,7 +853,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
const keyspan_device_details *d_details;
int i, already_active, err;
- urb_t *urb;
+ struct urb *urb;
s_priv = (struct keyspan_serial_private *)(serial->private);
p_priv = (struct keyspan_port_private *)(port->private);
@@ -906,7 +890,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
return (0);
}
-static inline void stop_urb(urb_t *urb)
+static inline void stop_urb(struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS) {
urb->transfer_flags &= ~USB_ASYNC_UNLINK;
@@ -1057,11 +1041,11 @@ static int keyspan_fake_startup (struct usb_serial *serial)
}
/* Helper functions used by keyspan_setup_urbs */
-static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
- int dir, void *ctx, char *buf, int len,
- void (*callback)(urb_t *))
+static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+ void (*callback)(struct urb *))
{
- urb_t *urb;
+ struct urb *urb;
if (endpoint == -1)
return NULL; /* endpoint not needed */
@@ -1082,12 +1066,12 @@ static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
}
static struct callbacks {
- void (*instat_callback)(urb_t *);
- void (*glocont_callback)(urb_t *);
- void (*indat_callback)(urb_t *);
- void (*outdat_callback)(urb_t *);
- void (*inack_callback)(urb_t *);
- void (*outcont_callback)(urb_t *);
+ void (*instat_callback)(struct urb *);
+ void (*glocont_callback)(struct urb *);
+ void (*indat_callback)(struct urb *);
+ void (*outdat_callback)(struct urb *);
+ void (*inack_callback)(struct urb *);
+ void (*outcont_callback)(struct urb *);
} keyspan_callbacks[] = {
{
/* msg_usa26 callbacks */
@@ -1311,7 +1295,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
struct keyspan_port_private *p_priv;
const keyspan_device_details *d_details;
int outcont_urb;
- urb_t *this_urb;
+ struct urb *this_urb;
int err;
dbg ("%s reset=%d\n", __FUNCTION__, reset_port);
@@ -1446,7 +1430,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
const keyspan_device_details *d_details;
- urb_t *this_urb;
+ struct urb *this_urb;
int err;
s_priv = (struct keyspan_serial_private *)(serial->private);
@@ -1532,7 +1516,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
struct keyspan_port_private *p_priv;
const keyspan_device_details *d_details;
int glocont_urb;
- urb_t *this_urb;
+ struct urb *this_urb;
int err;
int device_port;
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index e4cf84a41..b309c0978 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -372,42 +372,15 @@ MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
ID pattern. But, for now, it looks like we need slightly different
behavior for each match. */
-static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+/* usb_device_id table for the pre-firmware download keyspan devices */
+static __devinitdata struct usb_device_id keyspan_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
- { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
{ } /* Terminating entry */
};
@@ -448,10 +421,10 @@ static __devinitdata struct usb_device_id keyspan_usa49w_ids[] = {
};
/* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_pre_device = {
owner: THIS_MODULE,
- name: "Keyspan USA18X - (without firmware)",
- id_table: keyspan_usa18x_pre_ids,
+ name: "Keyspan - (without firmware)",
+ id_table: keyspan_pre_ids,
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
@@ -459,84 +432,6 @@ static struct usb_serial_device_type keyspan_usa18x_pre_device = {
startup: keyspan_fake_startup
};
-static struct usb_serial_device_type keyspan_usa19_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA19 - (without firmware)",
- id_table: keyspan_usa19_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: keyspan_fake_startup
-};
-
-
-static struct usb_serial_device_type keyspan_usa19w_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA19W - (without firmware)",
- id_table: keyspan_usa19w_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: keyspan_fake_startup
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA28 - (without firmware)",
- id_table: keyspan_usa28_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 2,
- startup: keyspan_fake_startup
-};
-
-static struct usb_serial_device_type keyspan_usa28x_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA28X - (without firmware)",
- id_table: keyspan_usa28x_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 2,
- startup: keyspan_fake_startup
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA28XA - (without firmware)",
- id_table: keyspan_usa28xa_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 2,
- startup: keyspan_fake_startup
-};
-
-static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA28XB - (without firmware)",
- id_table: keyspan_usa28xb_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 2,
- startup: keyspan_fake_startup
-};
-
-static struct usb_serial_device_type keyspan_usa49w_pre_device = {
- owner: THIS_MODULE,
- name: "Keyspan USA49W - (without firmware)",
- id_table: keyspan_usa49w_pre_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 4,
- startup: keyspan_fake_startup
-};
static struct usb_serial_device_type keyspan_usa18x_device = {
owner: THIS_MODULE,
@@ -550,8 +445,6 @@ static struct usb_serial_device_type keyspan_usa18x_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
- //write_bulk_callback: Not used - we define our own herbs
- //read_int_callback: keyspan_usa26_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
@@ -574,8 +467,6 @@ static struct usb_serial_device_type keyspan_usa19_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
-// write_bulk_callback: keyspan_write_bulk_callback,
-// read_int_callback: keyspan_usa28_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
@@ -599,8 +490,6 @@ static struct usb_serial_device_type keyspan_usa19w_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
- //write_bulk_callback: Not used - we define our own herbs
- //read_int_callback: keyspan_usa26_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
@@ -640,8 +529,6 @@ static struct usb_serial_device_type keyspan_usa28x_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
-// write_bulk_callback: keyspan_write_bulk_callback,
-// read_int_callback: keyspan_usa26_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
@@ -665,8 +552,6 @@ static struct usb_serial_device_type keyspan_usa28xa_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
-// write_bulk_callback: keyspan_write_bulk_callback,
-// read_int_callback: keyspan_usa26_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
@@ -690,8 +575,6 @@ static struct usb_serial_device_type keyspan_usa49w_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
- //write_bulk_callback: Not used - we define our own herbs
- //read_int_callback: keyspan_usa26_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 486af88dd..c2bc41be7 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $
+ * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -73,7 +73,7 @@ void fix_inquiry_data(Scsi_Cmnd *srb)
data_ptr = (unsigned char *) srb->request_buffer;
/* Change the SCSI revision number */
- data_ptr[2] |= 0x2;
+ data_ptr[2] = (data_ptr[2] & ~7) | 2;
}
/***********************************************************************
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 1f247877e..7b40983c7 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -369,7 +369,7 @@ int usb_stor_clear_halt(struct usb_device *dev, int pipe)
/* This is the completion handler which will wake us up when an URB
* completes.
*/
-static void usb_stor_blocking_completion(urb_t *urb)
+static void usb_stor_blocking_completion(struct urb *urb)
{
struct completion *urb_done_ptr = (struct completion *)urb->context;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 729c5ff60..87ba0ccb0 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Ununsual Devices File
*
- * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $
*
* Current development and maintenance by:
* (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -459,6 +459,14 @@ UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
0 ),
#endif
+/* Submitted by Brian Hall <brihall@bigfoot.com>
+ * Needed for START_STOP flag */
+UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100,
+ "JMTek",
+ "USBDrive",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ US_FL_START_STOP ),
+
/* Reported by Dan Pilone <pilone@slac.com>
* The device needs the flags only.
*/
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index db9ecdad8..0932c1b27 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.69 2001/11/11 03:33:03 mdharm Exp $
+ * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -316,6 +316,13 @@ static int usb_stor_control_thread(void * __us)
*/
daemonize();
+ /* avoid getting signals */
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ sigfillset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
/* set our name for identification purposes */
sprintf(current->comm, "usb-storage-%d", us->host_number);
diff --git a/drivers/usb/stv680.c b/drivers/usb/stv680.c
index c3df86637..fad991e9a 100644
--- a/drivers/usb/stv680.c
+++ b/drivers/usb/stv680.c
@@ -43,6 +43,13 @@
* Took out sharpen function, ran code through
* Lindent, and did other minor tweaks to get
* things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs)
+ * Fixed the problem with webcam crashing after
+ * two pictures. Changed the way pic is halved to
+ * improve quality. Got rid of green line around
+ * frame. Fix brightness reset when changing size
+ * bug. Adjusted gamma filters slightly.
*/
#include <linux/config.h>
@@ -65,7 +72,8 @@
#include "stv680.h"
static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0; /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
static unsigned int debug = 0;
@@ -79,7 +87,7 @@ static unsigned int debug = 0;
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
#define DRIVER_DESC "STV0680 USB Camera Driver"
@@ -88,8 +96,8 @@ MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
MODULE_PARM (debug, "i");
MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
MODULE_PARM (video_nr, "i");
EXPORT_NO_SYMBOLS;
@@ -521,8 +529,15 @@ exit:
stv680->palette = STV_VIDEO_PALETTE;
stv680->depth = 24; /* rgb24 bits */
swapRGB = 0;
- PDEBUG (1, "STV(i): swapRGB is OFF");
-
+ if ((swapRGB_on == 0) && (swapRGB == 0))
+ PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+ else if ((swapRGB_on == 1) && (swapRGB == 1))
+ PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+ else if (swapRGB_on == 1)
+ PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+ else if (swapRGB_on == -1)
+ PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+
if (stv_set_video_mode (stv680) < 0) {
PDEBUG (0, "STV(e): Could not set video mode in stv_init");
return -1;
@@ -543,6 +558,7 @@ static struct proc_dir_entry *stv680_proc_entry = NULL;
extern struct proc_dir_entry *video_proc_entry;
#define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{
@@ -559,7 +575,13 @@ static int stv680_read_proc (char *page, char **start, off_t off, int count, int
out += sprintf (out, "num_frames : %d\n", STV680_NUMFRAMES);
out += sprintf (out, "Current size : %ix%i\n", stv680->vwidth, stv680->vheight);
- out += sprintf (out, "swapRGB : %s\n", YES_NO (swapRGB));
+ if (swapRGB_on == 0)
+ out += sprintf (out, "swapRGB : %s\n", ON_OFF (swapRGB));
+ else if (swapRGB_on == 1)
+ out += sprintf (out, "swapRGB : (forced) on\n");
+ else if (swapRGB_on == -1)
+ out += sprintf (out, "swapRGB : (forced) off\n");
+
out += sprintf (out, "Palette : %i", stv680->palette);
out += sprintf (out, "\n");
@@ -671,9 +693,7 @@ static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
if (stv680->brightness != p->brightness) {
stv680->chgbright = 1;
stv680->brightness = p->brightness;
- } else {
- stv680->chgbright = 0;
- }
+ }
stv680->whiteness = p->whiteness; /* greyscale */
stv680->colour = p->colour;
@@ -746,7 +766,7 @@ static void stv680_video_irq (struct urb *urb)
static int stv680_start_stream (struct usb_stv *stv680)
{
- urb_t *urb;
+ struct urb *urb;
int err = 0, i;
stv680->streaming = 1;
@@ -888,7 +908,7 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
{
int x, y, i;
int w = stv680->cwidth;
- int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+ int vw = stv680->cwidth, vh = stv680->cheight;
unsigned int p = 0;
int colour = 0, bayer = 0;
unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
return;
}
- if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+ if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
vw = 320;
vh = 240;
- vstep = 1;
}
- if ((stv680->vwidth == 352)) {
+ if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
vw = 352;
vh = 288;
- vstep = 1;
}
- if ((stv680->vwidth == 160)) {
- vw = 160;
- vh = 120;
- vstep = 2;
- }
- if ((stv680->vwidth == 176)) {
- vw = 176;
- vh = 144;
- vstep = 2;
- }
- memset (output, 0, 3 * vw * vh); /* clear output matrix. Maybe not necessary. */
+
+ memset (output, 0, 3 * vw * vh); /* clear output matrix. */
for (y = 0; y < vh; y++) {
for (x = 0; x < vw; x++) {
-
- switch (vstep) {
- case 1:
- if (x & 1)
- p = *(raw + y * w + (x >> 1));
- else
- p = *(raw + y * w + (x >> 1) + (w >> 1));
- break;
-
- case 2:
- if (x & 1)
- p = *(raw + ((y * w) << 1) + x);
- else
- p = *(raw + ((y * w) << 1) + x + (w >> 1));
- break;
- }
+ if (x & 1)
+ p = *(raw + y * w + (x >> 1));
+ else
+ p = *(raw + y * w + (x >> 1) + (w >> 1));
if (y & 1)
bayer = 2;
@@ -968,9 +965,10 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
colour = 2;
break;
}
- i = (y * vw + x) * 3; /* output already zeroed out with memset */
+ i = (y * vw + x) * 3;
*(output + i + colour) = (unsigned char) p;
} /* for x */
+
} /* for y */
/****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
(pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
converted to unsigned char. Values are in stv680.h */
+
for (y = 0; y < vh; y++) {
for (x = 0; x < vw; x++) {
i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
} /* for x */
} /* for y - end demosaic */
+ /* fix top and bottom row, left and right side */
+ i = vw * 3;
+ memcpy (output, (output + i), i);
+ memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+ for (y = 0; y < vh; y++) {
+ i = y * vw * 3;
+ memcpy ((output + i), (output + i + 3), 3);
+ memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+ }
+
+ /* process all raw data, then trim to size if necessary */
+ if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) {
+ i = 0;
+ for (y = 0; y < vh; y++) {
+ if (!(y & 1)) {
+ for (x = 0; x < vw; x++) {
+ p = (y * vw + x) * 3;
+ if (!(x & 1)) {
+ *(output + i) = *(output + p);
+ *(output + i + 1) = *(output + p + 1);
+ *(output + i + 2) = *(output + p + 2);
+ i += 3;
+ }
+ } /* for x */
+ }
+ } /* for y */
+ }
+ /* reset to proper width */
+ if ((stv680->vwidth == 160)) {
+ vw = 160;
+ vh = 120;
+ }
+ if ((stv680->vwidth == 176)) {
+ vw = 176;
+ vh = 144;
+ }
+
/* output is RGB; some programs want BGR */
- if (swapRGB == 1) {
+ /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */
+ /* swapRGB_on=-1, never swap */
+ if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
for (y = 0; y < vh; y++) {
for (x = 0; x < vw; x++) {
i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
return -EFAULT;
}
copy_from_user (&p, arg, sizeof (p));
- PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+ PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
if (stv680_set_pict (stv680, &p))
return -EINVAL;
@@ -1309,8 +1347,8 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
if (vm.format != STV_VIDEO_PALETTE) {
PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
vm.format, STV_VIDEO_PALETTE);
- if (vm.format == 3) {
- PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+ if ((vm.format == 3) && (swapRGB_on == 0)) {
+ PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
/* this may fix those apps (e.g., xawtv) that want BGR */
swapRGB = 1;
}
@@ -1320,8 +1358,10 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
return -EINVAL;
}
- if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+ if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+ || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+ PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+ stv680->frame[vm.frame].grabstate);
return -EBUSY;
}
/* Is this according to the v4l spec??? */
diff --git a/drivers/usb/stv680.h b/drivers/usb/stv680.h
index 74abaabb9..3c0bd3ecc 100644
--- a/drivers/usb/stv680.h
+++ b/drivers/usb/stv680.h
@@ -43,7 +43,7 @@
#define USB_PENCAM_PRODUCT_ID 0x0202
#define PENCAM_TIMEOUT 1000
/* fmt 4 */
-#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
static __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -118,7 +118,7 @@ struct usb_stv {
int removed; /* device disconnected */
int streaming; /* Are we streaming video? */
char *fbuf; /* Videodev buffer area */
- urb_t *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */
+ struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */
int curframe; /* Current receiving frame */
struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */
int readcount;
@@ -146,77 +146,78 @@ struct usb_stv {
int nullpackets;
};
-unsigned char red[256] = {
- 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
- 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
- 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
- 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
- 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
- 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
- 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
- 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
- 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
- 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
- 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
- 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
- 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
- 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
- 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
- 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
- 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
- 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
- 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
- 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
- 245, 245, 246, 246
-};
+
+unsigned char red[256] = {
+ 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42,
+ 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69,
+ 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87,
+ 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134,
+ 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143,
+ 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151,
+ 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
+ 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166,
+ 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173,
+ 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179,
+ 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186,
+ 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192,
+ 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197,
+ 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204,
+ 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209,
+ 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
+ 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219,
+ 220, 220, 221, 221
+};
unsigned char green[256] = {
- 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
- 58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
- 92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
- 114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
- 133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
- 148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
- 162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
- 175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
- 187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
- 197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
- 207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
- 217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
- 225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
- 235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
- 243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
- 250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
-};
+ 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
+ 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
+ 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
+ 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
+ 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+ 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
+ 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
+ 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
+ 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
+ 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
+ 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
+ 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
+ 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
+ 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
+ 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
+ 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
+ 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
+ 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
+ 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
+ 245, 245, 246, 246
+};
unsigned char blue[256] = {
- 0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
- 74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
- 116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
- 145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
- 168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
- 187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
- 205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
- 222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
- 236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
- 250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
-};
+ 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51,
+ 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84,
+ 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106,
+ 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124,
+ 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138,
+ 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163,
+ 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174,
+ 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184,
+ 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194,
+ 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203,
+ 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212,
+ 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220,
+ 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
+ 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235,
+ 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242,
+ 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249,
+ 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255
+};
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index de513c7ad..2ced4412d 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -520,7 +520,8 @@ static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct u
lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
- uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
+ uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
/* All qh's in the queue need to link to the next queue */
urbp->qh->link = eurbp->qh->link;
@@ -556,6 +557,7 @@ static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
/* Fix up the toggle for the next URB's */
if (!urbp->queued)
+ /* We set the toggle when we unlink */
toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
else {
/* If we're in the middle of the queue, grab the toggle */
@@ -1683,8 +1685,8 @@ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
/* Control and Isochronous ignore the toggle, so this */
/* is safe for all types */
- if (!(td->status & TD_CTRL_ACTIVE) &&
- (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+ if ((!(td->status & TD_CTRL_ACTIVE) &&
+ (uhci_actual_length(td->status) < uhci_expected_length(td->info)) ||
tmp == head)) {
usb_settoggle(urb->dev, uhci_endpoint(td->info),
uhci_packetout(td->info),
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index e62ca8a87..6720ddfda 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -173,7 +173,7 @@ static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
kfree (urb_priv);
}
-static void urb_rm_priv_locked (urb_t * urb)
+static void urb_rm_priv_locked (struct urb * urb)
{
urb_priv_t * urb_priv = urb->hcpriv;
@@ -207,7 +207,7 @@ static void urb_rm_priv_locked (urb_t * urb)
}
}
-static void urb_rm_priv (urb_t * urb)
+static void urb_rm_priv (struct urb * urb)
{
unsigned long flags;
@@ -224,7 +224,7 @@ static int sohci_get_current_frame_number (struct usb_device * dev);
/* debug| print the main components of an URB
* small: 0) header + data packets 1) just header */
-static void urb_print (urb_t * urb, char * str, int small)
+static void urb_print (struct urb * urb, char * str, int small)
{
unsigned int pipe= urb->pipe;
@@ -453,10 +453,10 @@ static void ohci_dump (ohci_t *controller, int verbose)
/* return a request to the completion handler */
-static int sohci_return_urb (struct ohci *hc, urb_t * urb)
+static int sohci_return_urb (struct ohci *hc, struct urb * urb)
{
urb_priv_t * urb_priv = urb->hcpriv;
- urb_t * urbt;
+ struct urb * urbt;
unsigned long flags;
int i;
@@ -532,7 +532,7 @@ static int sohci_return_urb (struct ohci *hc, urb_t * urb)
/* get a transfer request */
-static int sohci_submit_urb (urb_t * urb)
+static int sohci_submit_urb (struct urb * urb)
{
ohci_t * ohci;
ed_t * ed;
@@ -716,7 +716,7 @@ static int sohci_submit_urb (urb_t * urb)
/* deactivate all TDs and remove the private part of the URB */
/* interrupt callers must use async unlink mode */
-static int sohci_unlink_urb (urb_t * urb)
+static int sohci_unlink_urb (struct urb * urb)
{
unsigned long flags;
ohci_t * ohci;
@@ -1295,7 +1295,7 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
static void
td_fill (ohci_t * ohci, unsigned int info,
dma_addr_t data, int len,
- urb_t * urb, int index)
+ struct urb * urb, int index)
{
volatile td_t * td, * td_pt;
urb_priv_t * urb_priv = urb->hcpriv;
@@ -1343,7 +1343,7 @@ td_fill (ohci_t * ohci, unsigned int info,
/* prepare all TDs of a transfer */
-static void td_submit_urb (urb_t * urb)
+static void td_submit_urb (struct urb * urb)
{
urb_priv_t * urb_priv = urb->hcpriv;
ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
@@ -1452,7 +1452,7 @@ static void dl_transfer_length(td_t * td)
{
__u32 tdINFO, tdBE, tdCBP;
__u16 tdPSW;
- urb_t * urb = td->urb;
+ struct urb * urb = td->urb;
urb_priv_t * urb_priv = urb->hcpriv;
int dlen = 0;
int cc = 0;
@@ -1493,7 +1493,7 @@ static void dl_transfer_length(td_t * td)
/* handle an urb that is being unlinked */
-static void dl_del_urb (urb_t * urb)
+static void dl_del_urb (struct urb * urb)
{
wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
@@ -1582,7 +1582,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
td_p = &ed->hwHeadP;
for (td = tdHeadP; td != tdTailP; td = td_next) {
- urb_t * urb = td->urb;
+ struct urb * urb = td->urb;
urb_priv_t * urb_priv = td->urb->hcpriv;
td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
@@ -1670,7 +1670,7 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
td_t * td_list_next = NULL;
ed_t * ed;
int cc = 0;
- urb_t * urb;
+ struct urb * urb;
urb_priv_t * urb_priv;
__u32 tdINFO, edHeadP, edTailP;
@@ -1846,7 +1846,7 @@ static void rh_int_timer_do (unsigned long ptr)
{
int len;
- urb_t * urb = (urb_t *) ptr;
+ struct urb * urb = (struct urb *) ptr;
ohci_t * ohci = urb->dev->bus->hcpriv;
if (ohci->disabled)
@@ -1875,7 +1875,7 @@ static void rh_int_timer_do (unsigned long ptr)
/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer (urb_t * urb)
+static int rh_init_int_timer (struct urb * urb)
{
ohci_t * ohci = urb->dev->bus->hcpriv;
@@ -1900,7 +1900,7 @@ static int rh_init_int_timer (urb_t * urb)
/* request to virtual root hub */
-static int rh_submit_urb (urb_t * urb)
+static int rh_submit_urb (struct urb * urb)
{
struct usb_device * usb_dev = urb->dev;
ohci_t * ohci = usb_dev->bus->hcpriv;
@@ -2106,7 +2106,7 @@ static int rh_submit_urb (urb_t * urb)
/*-------------------------------------------------------------------------*/
-static int rh_unlink_urb (urb_t * urb)
+static int rh_unlink_urb (struct urb * urb)
{
ohci_t * ohci = urb->dev->bus->hcpriv;
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index ba9758e2d..82457dd58 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -111,7 +111,7 @@ struct td {
__u8 index;
struct ed * ed;
struct td * next_dl_td;
- urb_t * urb;
+ struct urb * urb;
dma_addr_t td_dma;
dma_addr_t data_dma;
@@ -430,12 +430,12 @@ static int ep_unlink(ohci_t * ohci, ed_t * ed);
static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
/* td */
-static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, urb_t * urb, int index);
-static void td_submit_urb(urb_t * urb);
+static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
+static void td_submit_urb(struct urb * urb);
/* root hub */
-static int rh_submit_urb(urb_t * urb);
-static int rh_unlink_urb(urb_t * urb);
-static int rh_init_int_timer(urb_t * urb);
+static int rh_submit_urb(struct urb * urb);
+static int rh_unlink_urb(struct urb * urb);
+static int rh_init_int_timer(struct urb * urb);
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index df729fd09..16009c8e5 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -113,12 +113,12 @@
// Suppress HC interrupt error messages for 5s
#define ERROR_SUPPRESSION_TIME (HZ*5)
-_static int rh_submit_urb (urb_t *urb);
-_static int rh_unlink_urb (urb_t *urb);
+_static int rh_submit_urb (struct urb *urb);
+_static int rh_unlink_urb (struct urb *urb);
_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode);
-_static int process_interrupt (uhci_t *s, urb_t *urb);
-_static int process_iso (uhci_t *s, urb_t *urb, int force);
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
+_static int process_interrupt (uhci_t *s, struct urb *urb);
+_static int process_iso (uhci_t *s, struct urb *urb, int force);
// How much URBs with ->next are walked
#define MAX_NEXT_COUNT 2048
@@ -164,7 +164,7 @@ _static void uhci_switch_timer_int(uhci_t *s)
}
/*-------------------------------------------------------------------*/
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, urb_t *urb)
+_static void enable_desc_loop(uhci_t *s, struct urb *urb)
{
int flags;
@@ -179,7 +179,7 @@ _static void enable_desc_loop(uhci_t *s, urb_t *urb)
spin_unlock_irqrestore (&s->qh_lock, flags);
}
/*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, urb_t *urb)
+_static void disable_desc_loop(uhci_t *s, struct urb *urb)
{
int flags;
@@ -200,7 +200,7 @@ _static void disable_desc_loop(uhci_t *s, urb_t *urb)
}
#endif
/*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
+_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
{
struct list_head *p=&urb->urb_list;
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
@@ -220,7 +220,7 @@ _static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
uhci_switch_timer_int(s);
}
/*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, urb_t *urb)
+_static void queue_urb (uhci_t *s, struct urb *urb)
{
unsigned long flags=0;
@@ -229,7 +229,7 @@ _static void queue_urb (uhci_t *s, urb_t *urb)
spin_unlock_irqrestore (&s->urb_list_lock, flags);
}
/*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, urb_t *urb)
+_static void dequeue_urb (uhci_t *s, struct urb *urb)
{
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
int type;
@@ -693,7 +693,7 @@ _static int init_skel (uhci_t *s)
// LOW LEVEL STUFF
// assembles QHs und TDs for control, bulk and iso
/*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (urb_t *urb)
+_static int uhci_submit_control_urb (struct urb *urb)
{
uhci_desc_t *qh, *td;
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
@@ -809,7 +809,7 @@ fail_unmap_enomem:
// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
-_static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
+_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
{
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
@@ -970,7 +970,7 @@ _static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
looks a bit complicated because of all the bulk queueing goodies
*/
-_static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode)
+_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
{
uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
int now;
@@ -1024,7 +1024,7 @@ _static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mo
urb, priv->prev_queued_urb, priv->next_queued_urb, qh, bqh, priv->next_qh);
if (mode != CLEAN_TRANSFER_DELETION_MARK) { // no work for cleanup at unlink-completion
- urb_t *nurb;
+ struct urb *nurb;
unsigned long flags;
nurb = priv->next_queued_urb;
@@ -1062,7 +1062,7 @@ _static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mo
}
/*-------------------------------------------------------------------*/
// Release bandwidth for Interrupt or Isoc. transfers
-_static void uhci_release_bandwidth(urb_t *urb)
+_static void uhci_release_bandwidth(struct urb *urb)
{
if (urb->bandwidth) {
switch (usb_pipetype(urb->pipe)) {
@@ -1078,7 +1078,7 @@ _static void uhci_release_bandwidth(urb_t *urb)
}
}
-_static void uhci_urb_dma_sync(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
{
if (urb_priv->setup_packet_dma)
pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
@@ -1092,7 +1092,7 @@ _static void uhci_urb_dma_sync(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
PCI_DMA_TODEVICE);
}
-_static void uhci_urb_dma_unmap(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
{
if (urb_priv->setup_packet_dma) {
pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
@@ -1113,7 +1113,7 @@ _static void uhci_urb_dma_unmap(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
*/
-_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb, int mode)
+_static int uhci_unlink_urb_async (uhci_t *s, struct urb *urb, int mode)
{
uhci_desc_t *qh;
urb_priv_t *urb_priv;
@@ -1158,7 +1158,7 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb, int mode)
}
/*-------------------------------------------------------------------*/
// kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
+_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
{
uhci_desc_t *qh;
urb_priv_t *urb_priv;
@@ -1221,7 +1221,7 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
_static void uhci_cleanup_unlink(uhci_t *s, int force)
{
struct list_head *q;
- urb_t *urb;
+ struct urb *urb;
struct usb_device *dev;
int now, type;
urb_priv_t *urb_priv;
@@ -1231,7 +1231,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
while (q != &s->urb_unlinked) {
- urb = list_entry (q, urb_t, urb_list);
+ urb = list_entry (q, struct urb, urb_list);
urb_priv = (urb_priv_t*)urb->hcpriv;
q = urb->urb_list.next;
@@ -1300,7 +1300,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
}
/*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (urb_t *urb)
+_static int uhci_unlink_urb (struct urb *urb)
{
uhci_t *s;
unsigned long flags=0;
@@ -1333,9 +1333,9 @@ _static int uhci_unlink_urb (urb_t *urb)
// In case of ASAP iso transfer, search the URB-list for already queued URBs
// for this EP and calculate the earliest start frame for the new
// URB (easy seamless URB continuation!)
-_static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
+_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
{
- urb_t *u, *last_urb = NULL;
+ struct urb *u, *last_urb = NULL;
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
struct list_head *p;
int ret=-1;
@@ -1345,7 +1345,7 @@ _static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
p=s->urb_list.prev;
for (; p != &s->urb_list; p = p->prev) {
- u = list_entry (p, urb_t, urb_list);
+ u = list_entry (p, struct urb, urb_list);
// look for pending URBs with identical pipe handle
// works only because iso doesn't toggle the data bit!
if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
@@ -1367,7 +1367,7 @@ _static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
/*-------------------------------------------------------------------*/
// adjust start_frame according to scheduling constraints (ASAP etc)
-_static int iso_find_start (urb_t *urb)
+_static int iso_find_start (struct urb *urb)
{
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
unsigned int now;
@@ -1425,7 +1425,7 @@ _static int iso_find_start (urb_t *urb)
// ASAP-flag set implicitely
// if period==0, the transfer is only done once
-_static int uhci_submit_int_urb (urb_t *urb)
+_static int uhci_submit_int_urb (struct urb *urb)
{
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
urb_priv_t *urb_priv = urb->hcpriv;
@@ -1485,7 +1485,7 @@ _static int uhci_submit_int_urb (urb_t *urb)
return 0;
}
/*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (urb_t *urb)
+_static int uhci_submit_iso_urb (struct urb *urb)
{
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
urb_priv_t *urb_priv = urb->hcpriv;
@@ -1578,10 +1578,10 @@ _static int uhci_submit_iso_urb (urb_t *urb)
/*-------------------------------------------------------------------*/
// returns: 0 (no transfer queued), urb* (this urb already queued)
-_static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
+_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
{
struct list_head *p;
- urb_t *tmp;
+ struct urb *tmp;
unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
dbg("search_dev_ep:");
@@ -1589,7 +1589,7 @@ _static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
p=s->urb_list.next;
for (; p != &s->urb_list; p = p->next) {
- tmp = list_entry (p, urb_t, urb_list);
+ tmp = list_entry (p, struct urb, urb_list);
dbg("urb: %p", tmp);
// we can accept this urb if it is not queued at this time
// or if non-iso transfer requests should be scheduled for the same device and pipe
@@ -1602,13 +1602,13 @@ _static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
return 0;
}
/*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (urb_t *urb)
+_static int uhci_submit_urb (struct urb *urb)
{
uhci_t *s;
urb_priv_t *urb_priv;
int ret = 0, type;
unsigned long flags;
- urb_t *queued_urb=NULL;
+ struct urb *queued_urb=NULL;
int bustime;
if (!urb->dev || !urb->dev->bus)
@@ -1762,7 +1762,7 @@ _static int uhci_submit_urb (urb_t *urb)
_static void uhci_check_timeouts(uhci_t *s)
{
struct list_head *p,*p2;
- urb_t *urb;
+ struct urb *urb;
int type;
p = s->urb_list.prev;
@@ -1772,7 +1772,7 @@ _static void uhci_check_timeouts(uhci_t *s)
p2 = p;
p = p->prev;
- urb = list_entry (p2, urb_t, urb_list);
+ urb = list_entry (p2, struct urb, urb_list);
type = usb_pipetype (urb->pipe);
hcpriv = (urb_priv_t*)urb->hcpriv;
@@ -1872,7 +1872,7 @@ _static __u8 root_hub_hub_des[] =
/*-------------------------------------------------------------------------*/
/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-_static int rh_send_irq (urb_t *urb)
+_static int rh_send_irq (struct urb *urb)
{
int len = 1;
int i;
@@ -1899,12 +1899,12 @@ _static int rh_send_irq (urb_t *urb)
/*-------------------------------------------------------------------------*/
/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (urb_t *urb);
+_static int rh_init_int_timer (struct urb *urb);
_static void rh_int_timer_do (unsigned long ptr)
{
int len;
- urb_t *urb = (urb_t*) ptr;
+ struct urb *urb = (struct urb *) ptr;
uhci_t *uhci = urb->dev->bus->hcpriv;
if (uhci->rh.send) {
@@ -1921,7 +1921,7 @@ _static void rh_int_timer_do (unsigned long ptr)
/*-------------------------------------------------------------------------*/
/* Root Hub INTs are polled by this timer, polling interval 20ms */
-_static int rh_init_int_timer (urb_t *urb)
+_static int rh_init_int_timer (struct urb *urb)
{
uhci_t *uhci = urb->dev->bus->hcpriv;
@@ -1955,7 +1955,7 @@ _static int rh_init_int_timer (urb_t *urb)
*************************/
-_static int rh_submit_urb (urb_t *urb)
+_static int rh_submit_urb (struct urb *urb)
{
struct usb_device *usb_dev = urb->dev;
uhci_t *uhci = usb_dev->bus->hcpriv;
@@ -2156,7 +2156,7 @@ _static int rh_submit_urb (urb_t *urb)
}
/*-------------------------------------------------------------------------*/
-_static int rh_unlink_urb (urb_t *urb)
+_static int rh_unlink_urb (struct urb *urb)
{
uhci_t *uhci = urb->dev->bus->hcpriv;
@@ -2214,14 +2214,14 @@ _static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_
unsigned long flags;
struct list_head *p;
struct list_head *p2;
- urb_t *urb;
+ struct urb *urb;
spin_lock_irqsave (&s->urb_list_lock, flags);
p = s->urb_list.prev;
while (p != &s->urb_list) {
p2 = p;
p = p->prev ;
- urb = list_entry (p2, urb_t, urb_list);
+ urb = list_entry (p2, struct urb, urb_list);
dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
//urb->transfer_flags |=USB_ASYNC_UNLINK;
@@ -2271,7 +2271,7 @@ struct usb_operations uhci_device_operations =
uhci_unlink_urb
};
-_static void correct_data_toggles(urb_t *urb)
+_static void correct_data_toggles(struct urb *urb)
{
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe),
!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
@@ -2301,7 +2301,7 @@ _static void correct_data_toggles(urb_t *urb)
* PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
*/
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode)
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
{
int ret = 0;
urb_priv_t *urb_priv = urb->hcpriv;
@@ -2389,7 +2389,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
if (usb_pipetype (urb->pipe) == PIPE_BULK ) { /* toggle correction for short bulk transfers (nonqueued/queued) */
urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
- urb_t *next_queued_urb=priv->next_queued_urb;
+ struct urb *next_queued_urb=priv->next_queued_urb;
if (next_queued_urb) {
urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
@@ -2420,7 +2420,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
return ret;
}
-_static int process_interrupt (uhci_t *s, urb_t *urb)
+_static int process_interrupt (uhci_t *s, struct urb *urb)
{
int i, ret = -EINPROGRESS;
urb_priv_t *urb_priv = urb->hcpriv;
@@ -2517,7 +2517,7 @@ _static int process_interrupt (uhci_t *s, urb_t *urb)
// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
-_static int process_iso (uhci_t *s, urb_t *urb, int mode)
+_static int process_iso (uhci_t *s, struct urb *urb, int mode)
{
int i;
int ret = 0;
@@ -2586,9 +2586,9 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode)
_static int process_urb (uhci_t *s, struct list_head *p)
{
int ret = 0;
- urb_t *urb;
+ struct urb *urb;
- urb=list_entry (p, urb_t, urb_list);
+ urb=list_entry (p, struct urb, urb_list);
//dbg("process_urb: found queued urb: %p", urb);
switch (usb_pipetype (urb->pipe)) {
@@ -2637,7 +2637,7 @@ _static int process_urb (uhci_t *s, struct list_head *p)
#endif
if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) { // process_interrupt does completion on its own
- urb_t *next_urb = urb->next;
+ struct urb *next_urb = urb->next;
int is_ring = 0;
int contains_killed = 0;
int loop_count=0;
diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
index 54499ec6a..1278f3a0e 100644
--- a/drivers/usb/usb-uhci.h
+++ b/drivers/usb/usb-uhci.h
@@ -157,8 +157,8 @@ typedef struct {
dma_addr_t setup_packet_dma;
dma_addr_t transfer_buffer_dma;
unsigned long started;
- urb_t *next_queued_urb; // next queued urb for this EP
- urb_t *prev_queued_urb;
+ struct urb *next_queued_urb; // next queued urb for this EP
+ struct urb *prev_queued_urb;
uhci_desc_t *bottom_qh;
uhci_desc_t *next_qh; // next helper QH
char use_loop;
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index ce267032d..0dff0a587 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1084,12 +1084,13 @@ void usb_inc_dev_use(struct usb_device *dev)
*
* The driver should call usb_free_urb() when it is finished with the urb.
*/
-urb_t *usb_alloc_urb(int iso_packets)
+struct urb *usb_alloc_urb(int iso_packets)
{
- urb_t *urb;
+ struct urb *urb;
- urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ urb = (struct urb *)kmalloc(sizeof(struct urb) +
+ iso_packets * sizeof(struct usb_iso_packet_descriptor),
+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
if (!urb) {
err("alloc_urb: kmalloc failed");
return NULL;
@@ -1110,7 +1111,7 @@ urb_t *usb_alloc_urb(int iso_packets)
* cleaned up with a call to usb_free_urb() when the driver is finished
* with it.
*/
-void usb_free_urb(urb_t* urb)
+void usb_free_urb(struct urb *urb)
{
if (urb)
kfree(urb);
@@ -1171,7 +1172,7 @@ void usb_free_urb(urb_t* urb)
* the periodic request, and bandwidth reservation is being done for
* this controller, submitting such a periodic request will fail.
*/
-int usb_submit_urb(urb_t *urb)
+int usb_submit_urb(struct urb *urb)
{
if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
return urb->dev->bus->op->submit_urb(urb);
@@ -1205,7 +1206,7 @@ int usb_submit_urb(urb_t *urb)
* and the completion function will see status -ECONNRESET. Failure is
* indicated by any other return value.
*/
-int usb_unlink_urb(urb_t *urb)
+int usb_unlink_urb(struct urb *urb)
{
if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
return urb->dev->bus->op->unlink_urb(urb);
@@ -1221,7 +1222,7 @@ struct usb_api_data {
int done;
};
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
{
struct usb_api_data *awd = (struct usb_api_data *)urb->context;
@@ -1231,7 +1232,7 @@ static void usb_api_blocking_completion(urb_t *urb)
}
// Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
DECLARE_WAITQUEUE(wait, current);
struct usb_api_data awd;
@@ -1289,7 +1290,7 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
struct usb_ctrlrequest *cmd, void *data, int len, int timeout)
{
- urb_t *urb;
+ struct urb *urb;
int retv;
int length;
@@ -1376,7 +1377,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
- urb_t *urb;
+ struct urb *urb;
if (len < 0)
return -EINVAL;
@@ -2252,6 +2253,14 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
return -EINVAL;
}
+ /* 9.4.10 says devices don't need this, if the interface
+ only has one alternate setting */
+ if (iface->num_altsetting == 1) {
+ warn("ignoring set_interface for dev %d, iface %d, alt %d",
+ dev->devnum, interface, alternate);
+ return 0;
+ }
+
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
interface, NULL, 0, HZ * 5)) < 0)
diff --git a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c
index d6094f3b0..c5c30d3d1 100644
--- a/drivers/usb/usbvideo.c
+++ b/drivers/usb/usbvideo.c
@@ -1776,7 +1776,7 @@ read_done:
/*
* Make all of the blocks of data contiguous
*/
-static int usbvideo_CompressIsochronous(uvd_t *uvd, urb_t *urb)
+static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
{
char *cdata;
int i, totlen = 0;
@@ -1891,7 +1891,7 @@ int usbvideo_StartDataPump(uvd_t *uvd)
/* We double buffer the Iso lists */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
int j, k;
- urb_t *urb = uvd->sbuf[i].urb;
+ struct urb *urb = uvd->sbuf[i].urb;
urb->dev = dev;
urb->context = uvd;
urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
diff --git a/drivers/usb/usbvideo.h b/drivers/usb/usbvideo.h
index 5ff4cf3ec..17456ed46 100644
--- a/drivers/usb/usbvideo.h
+++ b/drivers/usb/usbvideo.h
@@ -165,7 +165,7 @@ struct usb_device;
/* This structure represents one Isoc request - URB and buffer */
typedef struct {
char *data;
- urb_t *urb;
+ struct urb *urb;
} usbvideo_sbuf_t;
typedef struct {
diff --git a/drivers/usb/vicam.c b/drivers/usb/vicam.c
index dce980c1d..82eef90a5 100644
--- a/drivers/usb/vicam.c
+++ b/drivers/usb/vicam.c
@@ -468,29 +468,23 @@ static int vicam_v4l_open(struct video_device *vdev, int flags)
int err = 0;
dbg("vicam_v4l_open");
-
- MOD_INC_USE_COUNT;
+
down(&vicam->sem);
- if (vicam->open_count) /* Maybe not needed? */
- err = -EBUSY;
+ vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
+ if (!vicam->fbuf)
+ err=-ENOMEM;
else {
- vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
- if (!vicam->fbuf)
- err=-ENOMEM;
- else {
- vicam->open_count = 1;
- }
+ vicam->open_count = 1;
+ }
#ifdef BLINKING
- vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
- info ("led on");
- vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+ vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+ info ("led on");
+ vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
#endif
- }
up(&vicam->sem);
- if (err)
- MOD_DEC_USE_COUNT;
+
return err;
}
@@ -515,7 +509,6 @@ static void vicam_v4l_close(struct video_device *vdev)
up(&vicam->sem);
/* Why does se401.c have a usbdevice check here? */
/* If device is unplugged while open, I guess we only may unregister now */
- MOD_DEC_USE_COUNT;
}
static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock)
@@ -717,6 +710,7 @@ static int vicam_v4l_init(struct video_device *dev)
/* FIXME - vicam_template - important */
static struct video_device vicam_template = {
+ owner: THIS_MODULE,
name: "vicam USB camera",
type: VID_TYPE_CAPTURE,
hardware: VID_HARDWARE_SE401, /* need to ask for own id */
@@ -938,6 +932,7 @@ static void vicam_disconnect(struct usb_device *udev, void *ptr)
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vicam_driver = {
+ owner: THIS_MODULE,
name: "vicam",
probe: vicam_probe,
disconnect: vicam_disconnect,
@@ -984,3 +979,4 @@ static void __exit usb_vicam_exit(void)
module_init(usb_vicam_init);
module_exit(usb_vicam_exit);
+
diff --git a/drivers/usb/vicam.h b/drivers/usb/vicam.h
index 46b4aaddf..b483befbf 100644
--- a/drivers/usb/vicam.h
+++ b/drivers/usb/vicam.h
@@ -68,7 +68,7 @@ struct usb_vicam
/* v4l stuff */
char *camera_name;
char *fbuf;
- urb_t *urb[VICAM_NUMSBUF];
+ struct urb *urb[VICAM_NUMSBUF];
int sizes;
int *width;
int *height;
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 5121d8ddc..1868b6f21 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -550,7 +550,7 @@ int __init vesafb_init(void)
ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
if (ypan || pmi_setpal) {
- pmi_base = (unsigned short*)isa_bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+ pmi_base = (unsigned short*)bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
diff --git a/fs/Makefile.lib b/fs/Makefile.lib
index 0ca1cff14..bbdcfa520 100644
--- a/fs/Makefile.lib
+++ b/fs/Makefile.lib
@@ -1,2 +1,2 @@
-obj-$(CONFIG_FS_JFFS2) += crc32.o
+obj-$(CONFIG_JFFS2_FS) += crc32.o
obj-$(CONFIG_EFI_PARTITION) += crc32.o
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 1ac692e33..bf53d8735 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -419,7 +419,7 @@ prot_to_mode(u32 prot)
void
mode_to_prot(struct inode *inode)
{
- u32 prot = AFFS_INODE->i_protect;
+ u32 prot = AFFS_I(inode)->i_protect;
mode_t mode = inode->i_mode;
if (!(mode & S_IXUSR))
@@ -441,7 +441,7 @@ mode_to_prot(struct inode *inode)
if (mode & S_IWOTH)
prot |= FIBF_OTR_WRITE;
- AFFS_INODE->i_protect = prot;
+ AFFS_I(inode)->i_protect = prot;
}
void
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
index 697c8b47d..919309b10 100644
--- a/fs/affs/bitmap.c
+++ b/fs/affs/bitmap.c
@@ -155,16 +155,16 @@ affs_alloc_block(struct inode *inode, u32 goal)
pr_debug("AFFS: balloc(inode=%lu,goal=%u): ", inode->i_ino, goal);
- if (inode->u.affs_i.i_pa_cnt) {
- pr_debug("%d\n", inode->u.affs_i.i_lastalloc+1);
- inode->u.affs_i.i_pa_cnt--;
- return ++inode->u.affs_i.i_lastalloc;
+ if (AFFS_I(inode)->i_pa_cnt) {
+ pr_debug("%d\n", AFFS_I(inode)->i_lastalloc+1);
+ AFFS_I(inode)->i_pa_cnt--;
+ return ++AFFS_I(inode)->i_lastalloc;
}
if (!goal || goal > AFFS_SB->s_partition_size) {
if (goal)
affs_warning(sb, "affs_balloc", "invalid goal %d", goal);
- //if (!inode->u.affs_i.i_last_block)
+ //if (!AFFS_I(inode)->i_last_block)
// affs_warning(sb, "affs_balloc", "no last alloc block");
goal = AFFS_SB->s_reserved;
}
@@ -233,16 +233,16 @@ find_bit:
bit = ffs(tmp) - 1;
blk += bit + AFFS_SB->s_reserved;
mask2 = mask = 1 << (bit & 31);
- inode->u.affs_i.i_lastalloc = blk;
+ AFFS_I(inode)->i_lastalloc = blk;
/* prealloc as much as possible within this word */
while ((mask2 <<= 1)) {
if (!(tmp & mask2))
break;
- inode->u.affs_i.i_pa_cnt++;
+ AFFS_I(inode)->i_pa_cnt++;
mask |= mask2;
}
- bm->bm_free -= inode->u.affs_i.i_pa_cnt + 1;
+ bm->bm_free -= AFFS_I(inode)->i_pa_cnt + 1;
*data = cpu_to_be32(tmp & ~mask);
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 6a3602298..510dffaf9 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -62,8 +62,8 @@ affs_file_open(struct inode *inode, struct file *filp)
{
if (atomic_read(&filp->f_count) != 1)
return 0;
- pr_debug("AFFS: open(%d)\n", AFFS_INODE->i_opencnt);
- AFFS_INODE->i_opencnt++;
+ pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt);
+ AFFS_I(inode)->i_opencnt++;
return 0;
}
@@ -72,9 +72,9 @@ affs_file_release(struct inode *inode, struct file *filp)
{
if (atomic_read(&filp->f_count) != 0)
return 0;
- pr_debug("AFFS: release(%d)\n", AFFS_INODE->i_opencnt);
- AFFS_INODE->i_opencnt--;
- if (!AFFS_INODE->i_opencnt)
+ pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt);
+ AFFS_I(inode)->i_opencnt--;
+ if (!AFFS_I(inode)->i_opencnt)
affs_free_prealloc(inode);
return 0;
@@ -88,49 +88,49 @@ affs_grow_extcache(struct inode *inode, u32 lc_idx)
u32 lc_max;
int i, j, key;
- if (!AFFS_INODE->i_lc) {
+ if (!AFFS_I(inode)->i_lc) {
char *ptr = (char *)get_zeroed_page(GFP_NOFS);
if (!ptr)
return -ENOMEM;
- AFFS_INODE->i_lc = (u32 *)ptr;
- AFFS_INODE->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
+ AFFS_I(inode)->i_lc = (u32 *)ptr;
+ AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
}
- lc_max = AFFS_LC_SIZE << AFFS_INODE->i_lc_shift;
+ lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift;
- if (AFFS_INODE->i_extcnt > lc_max) {
+ if (AFFS_I(inode)->i_extcnt > lc_max) {
u32 lc_shift, lc_mask, tmp, off;
/* need to recalculate linear cache, start from old size */
- lc_shift = AFFS_INODE->i_lc_shift;
- tmp = (AFFS_INODE->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
+ lc_shift = AFFS_I(inode)->i_lc_shift;
+ tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
for (; tmp; tmp >>= 1)
lc_shift++;
lc_mask = (1 << lc_shift) - 1;
/* fix idx and old size to new shift */
- lc_idx >>= (lc_shift - AFFS_INODE->i_lc_shift);
- AFFS_INODE->i_lc_size >>= (lc_shift - AFFS_INODE->i_lc_shift);
+ lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
+ AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
/* first shrink old cache to make more space */
- off = 1 << (lc_shift - AFFS_INODE->i_lc_shift);
+ off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift);
for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
- AFFS_INODE->i_ac[i] = AFFS_INODE->i_ac[j];
+ AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j];
- AFFS_INODE->i_lc_shift = lc_shift;
- AFFS_INODE->i_lc_mask = lc_mask;
+ AFFS_I(inode)->i_lc_shift = lc_shift;
+ AFFS_I(inode)->i_lc_mask = lc_mask;
}
/* fill cache to the needed index */
- i = AFFS_INODE->i_lc_size;
- AFFS_INODE->i_lc_size = lc_idx + 1;
+ i = AFFS_I(inode)->i_lc_size;
+ AFFS_I(inode)->i_lc_size = lc_idx + 1;
for (; i <= lc_idx; i++) {
if (!i) {
- AFFS_INODE->i_lc[0] = inode->i_ino;
+ AFFS_I(inode)->i_lc[0] = inode->i_ino;
continue;
}
- key = AFFS_INODE->i_lc[i - 1];
- j = AFFS_INODE->i_lc_mask + 1;
+ key = AFFS_I(inode)->i_lc[i - 1];
+ j = AFFS_I(inode)->i_lc_mask + 1;
// unlock cache
for (; j > 0; j--) {
bh = affs_bread(sb, key);
@@ -140,7 +140,7 @@ affs_grow_extcache(struct inode *inode, u32 lc_idx)
affs_brelse(bh);
}
// lock cache
- AFFS_INODE->i_lc[i] = key;
+ AFFS_I(inode)->i_lc[i] = key;
}
return 0;
@@ -182,7 +182,7 @@ affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
affs_adjust_checksum(bh, blocknr - tmp);
mark_buffer_dirty_inode(bh, inode);
- AFFS_INODE->i_extcnt++;
+ AFFS_I(inode)->i_extcnt++;
mark_inode_dirty(inode);
return new_bh;
@@ -192,8 +192,8 @@ static inline struct buffer_head *
affs_get_extblock(struct inode *inode, u32 ext)
{
/* inline the simplest case: same extended block as last time */
- struct buffer_head *bh = AFFS_INODE->i_ext_bh;
- if (ext == AFFS_INODE->i_ext_last)
+ struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
+ if (ext == AFFS_I(inode)->i_ext_last)
atomic_inc(&bh->b_count);
else
/* we have to do more (not inlined) */
@@ -211,13 +211,13 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
u32 lc_idx, lc_off, ac_idx;
u32 tmp, idx;
- if (ext == AFFS_INODE->i_ext_last + 1) {
+ if (ext == AFFS_I(inode)->i_ext_last + 1) {
/* read the next extended block from the current one */
- bh = AFFS_INODE->i_ext_bh;
+ bh = AFFS_I(inode)->i_ext_bh;
ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
- if (ext < AFFS_INODE->i_extcnt)
+ if (ext < AFFS_I(inode)->i_extcnt)
goto read_ext;
- if (ext > AFFS_INODE->i_extcnt)
+ if (ext > AFFS_I(inode)->i_extcnt)
BUG();
bh = affs_alloc_extblock(inode, bh, ext);
if (IS_ERR(bh))
@@ -231,11 +231,11 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
goto read_ext;
}
- if (ext >= AFFS_INODE->i_extcnt) {
+ if (ext >= AFFS_I(inode)->i_extcnt) {
struct buffer_head *prev_bh;
/* allocate a new extended block */
- if (ext > AFFS_INODE->i_extcnt)
+ if (ext > AFFS_I(inode)->i_extcnt)
BUG();
/* get previous extended block */
@@ -251,10 +251,10 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
again:
/* check if there is an extended cache and whether it's large enough */
- lc_idx = ext >> AFFS_INODE->i_lc_shift;
- lc_off = ext & AFFS_INODE->i_lc_mask;
+ lc_idx = ext >> AFFS_I(inode)->i_lc_shift;
+ lc_off = ext & AFFS_I(inode)->i_lc_mask;
- if (lc_idx >= AFFS_INODE->i_lc_size) {
+ if (lc_idx >= AFFS_I(inode)->i_lc_size) {
int err;
err = affs_grow_extcache(inode, lc_idx);
@@ -265,14 +265,14 @@ again:
/* every n'th key we find in the linear cache */
if (!lc_off) {
- ext_key = AFFS_INODE->i_lc[lc_idx];
+ ext_key = AFFS_I(inode)->i_lc[lc_idx];
goto read_ext;
}
/* maybe it's still in the associative cache */
ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
- if (AFFS_INODE->i_ac[ac_idx].ext == ext) {
- ext_key = AFFS_INODE->i_ac[ac_idx].key;
+ if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) {
+ ext_key = AFFS_I(inode)->i_ac[ac_idx].key;
goto read_ext;
}
@@ -281,14 +281,14 @@ again:
idx = ac_idx;
while (--tmp, --lc_off > 0) {
idx = (idx - 1) & AFFS_AC_MASK;
- if (AFFS_INODE->i_ac[idx].ext == tmp) {
- ext_key = AFFS_INODE->i_ac[idx].key;
+ if (AFFS_I(inode)->i_ac[idx].ext == tmp) {
+ ext_key = AFFS_I(inode)->i_ac[idx].key;
goto find_ext;
}
}
/* fall back to the linear cache */
- ext_key = AFFS_INODE->i_lc[lc_idx];
+ ext_key = AFFS_I(inode)->i_lc[lc_idx];
find_ext:
/* read all extended blocks until we find the one we need */
//unlock cache
@@ -304,8 +304,8 @@ find_ext:
/* store it in the associative cache */
// recalculate ac_idx?
- AFFS_INODE->i_ac[ac_idx].ext = ext;
- AFFS_INODE->i_ac[ac_idx].key = ext_key;
+ AFFS_I(inode)->i_ac[ac_idx].ext = ext;
+ AFFS_I(inode)->i_ac[ac_idx].key = ext_key;
read_ext:
/* finally read the right extended block */
@@ -317,9 +317,9 @@ read_ext:
store_ext:
/* release old cached extended block and store the new one */
- affs_brelse(AFFS_INODE->i_ext_bh);
- AFFS_INODE->i_ext_last = ext;
- AFFS_INODE->i_ext_bh = bh;
+ affs_brelse(AFFS_I(inode)->i_ext_bh);
+ AFFS_I(inode)->i_ext_last = ext;
+ AFFS_I(inode)->i_ext_bh = bh;
atomic_inc(&bh->b_count);
return bh;
@@ -341,8 +341,8 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
if (block < 0)
goto err_small;
- if (block >= AFFS_INODE->i_blkcnt) {
- if (block > AFFS_INODE->i_blkcnt || !create)
+ if (block >= AFFS_I(inode)->i_blkcnt) {
+ if (block > AFFS_I(inode)->i_blkcnt || !create)
goto err_big;
} else
create = 0;
@@ -362,8 +362,8 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
if (!blocknr)
goto err_alloc;
bh_result->b_state |= (1UL << BH_New);
- AFFS_INODE->mmu_private += AFFS_SB->s_data_blksize;
- AFFS_INODE->i_blkcnt++;
+ AFFS_I(inode)->mmu_private += AFFS_SB->s_data_blksize;
+ AFFS_I(inode)->i_blkcnt++;
/* store new block */
if (bh_result->b_blocknr)
@@ -418,7 +418,7 @@ static int affs_readpage(struct file *file, struct page *page)
static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page, from, to, affs_get_block,
- &page->mapping->host->u.affs_i.mmu_private);
+ &AFFS_I(page->mapping->host)->mmu_private);
}
static int _affs_bmap(struct address_space *mapping, long block)
{
@@ -593,11 +593,11 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
bidx++;
}
affs_brelse(bh);
- inode->i_size = AFFS_INODE->mmu_private = size;
+ inode->i_size = AFFS_I(inode)->mmu_private = size;
return 0;
out:
- inode->i_size = AFFS_INODE->mmu_private = size;
+ inode->i_size = AFFS_I(inode)->mmu_private = size;
return PTR_ERR(bh);
}
@@ -759,7 +759,7 @@ done:
affs_brelse(bh);
tmp = (page->index << PAGE_CACHE_SHIFT) + from;
if (tmp > inode->i_size)
- inode->i_size = AFFS_INODE->mmu_private = tmp;
+ inode->i_size = AFFS_I(inode)->mmu_private = tmp;
return written;
@@ -787,9 +787,9 @@ affs_free_prealloc(struct inode *inode)
pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
- while (inode->u.affs_i.i_pa_cnt) {
- inode->u.affs_i.i_pa_cnt--;
- affs_free_block(sb, ++inode->u.affs_i.i_lastalloc);
+ while (AFFS_I(inode)->i_pa_cnt) {
+ AFFS_I(inode)->i_pa_cnt--;
+ affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc);
}
}
@@ -814,7 +814,7 @@ affs_truncate(struct inode *inode)
ext = last_blk / AFFS_SB->s_hashsize;
}
- if (inode->i_size > AFFS_INODE->mmu_private) {
+ if (inode->i_size > AFFS_I(inode)->mmu_private) {
struct address_space *mapping = inode->i_mapping;
struct page *page;
u32 size = inode->i_size - 1;
@@ -831,23 +831,23 @@ affs_truncate(struct inode *inode)
page_cache_release(page);
mark_inode_dirty(inode);
return;
- } else if (inode->i_size == AFFS_INODE->mmu_private)
+ } else if (inode->i_size == AFFS_I(inode)->mmu_private)
return;
// lock cache
ext_bh = affs_get_extblock(inode, ext);
- if (AFFS_INODE->i_lc) {
+ if (AFFS_I(inode)->i_lc) {
/* clear linear cache */
- for (i = (ext + 1) >> AFFS_INODE->i_lc_shift; i < AFFS_LC_SIZE; i++)
- AFFS_INODE->i_lc[i] = 0;
+ for (i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; i < AFFS_LC_SIZE; i++)
+ AFFS_I(inode)->i_lc[i] = 0;
/* clear associative cache */
for (i = 0; i < AFFS_AC_SIZE; i++)
- if (AFFS_INODE->i_ac[i].ext >= ext)
- AFFS_INODE->i_ac[i].ext = 0;
+ if (AFFS_I(inode)->i_ac[i].ext >= ext)
+ AFFS_I(inode)->i_ac[i].ext = 0;
}
ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
- blkcnt = AFFS_INODE->i_blkcnt;
+ blkcnt = AFFS_I(inode)->i_blkcnt;
i = 0;
blk = last_blk;
if (inode->i_size) {
@@ -868,13 +868,13 @@ affs_truncate(struct inode *inode)
affs_brelse(ext_bh);
if (inode->i_size) {
- AFFS_INODE->i_blkcnt = last_blk + 1;
- AFFS_INODE->i_extcnt = ext + 1;
+ AFFS_I(inode)->i_blkcnt = last_blk + 1;
+ AFFS_I(inode)->i_extcnt = ext + 1;
} else {
- AFFS_INODE->i_blkcnt = 0;
- AFFS_INODE->i_extcnt = 1;
+ AFFS_I(inode)->i_blkcnt = 0;
+ AFFS_I(inode)->i_extcnt = 1;
}
- AFFS_INODE->mmu_private = inode->i_size;
+ AFFS_I(inode)->mmu_private = inode->i_size;
// unlock cache
while (ext_key) {
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 2104b91b9..b804256a8 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -68,12 +68,20 @@ affs_read_inode(struct inode *inode)
inode->i_size = 0;
inode->i_nlink = 1;
inode->i_mode = 0;
- memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
- init_MUTEX(&AFFS_INODE->i_link_lock);
- init_MUTEX(&AFFS_INODE->i_ext_lock);
- AFFS_INODE->i_extcnt = 1;
- AFFS_INODE->i_ext_last = ~1;
- AFFS_INODE->i_protect = prot;
+ AFFS_I(inode)->i_extcnt = 1;
+ AFFS_I(inode)->i_ext_last = ~1;
+ AFFS_I(inode)->i_protect = prot;
+ AFFS_I(inode)->i_opencnt = 0;
+ AFFS_I(inode)->i_blkcnt = 0;
+ AFFS_I(inode)->i_lc = NULL;
+ AFFS_I(inode)->i_lc_size = 0;
+ AFFS_I(inode)->i_lc_shift = 0;
+ AFFS_I(inode)->i_lc_mask = 0;
+ AFFS_I(inode)->i_ac = NULL;
+ AFFS_I(inode)->i_ext_bh = NULL;
+ AFFS_I(inode)->mmu_private = 0;
+ AFFS_I(inode)->i_lastalloc = 0;
+ AFFS_I(inode)->i_pa_cnt = 0;
if (AFFS_SB->s_flags & SF_SETMODE)
inode->i_mode = AFFS_SB->s_mode;
@@ -136,11 +144,11 @@ affs_read_inode(struct inode *inode)
case ST_FILE:
size = be32_to_cpu(tail->size);
inode->i_mode |= S_IFREG;
- AFFS_INODE->mmu_private = inode->i_size = size;
+ AFFS_I(inode)->mmu_private = inode->i_size = size;
if (inode->i_size) {
- AFFS_INODE->i_blkcnt = (size - 1) /
+ AFFS_I(inode)->i_blkcnt = (size - 1) /
AFFS_SB->s_data_blksize + 1;
- AFFS_INODE->i_extcnt = (AFFS_INODE->i_blkcnt - 1) /
+ AFFS_I(inode)->i_extcnt = (AFFS_I(inode)->i_blkcnt - 1) /
AFFS_SB->s_hashsize + 1;
}
if (tail->link_chain)
@@ -196,7 +204,7 @@ affs_write_inode(struct inode *inode, int unused)
if (tail->stype == be32_to_cpu(ST_ROOT)) {
secs_to_datestamp(inode->i_mtime,&AFFS_ROOT_TAIL(sb, bh)->root_change);
} else {
- tail->protect = cpu_to_be32(AFFS_INODE->i_protect);
+ tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);
tail->size = cpu_to_be32(inode->i_size);
secs_to_datestamp(inode->i_mtime,&tail->change);
if (!(inode->i_ino == AFFS_SB->s_root_block)) {
@@ -255,7 +263,7 @@ affs_put_inode(struct inode *inode)
lock_kernel();
affs_free_prealloc(inode);
if (atomic_read(&inode->i_count) == 1) {
- if (inode->i_size != AFFS_INODE->mmu_private)
+ if (inode->i_size != AFFS_I(inode)->mmu_private)
affs_truncate(inode);
//if (inode->i_nlink)
// affs_clear_inode(inode);
@@ -279,18 +287,18 @@ affs_delete_inode(struct inode *inode)
void
affs_clear_inode(struct inode *inode)
{
- unsigned long cache_page = (unsigned long) inode->u.affs_i.i_lc;
+ unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc;
pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
if (cache_page) {
pr_debug("AFFS: freeing ext cache\n");
- inode->u.affs_i.i_lc = NULL;
- inode->u.affs_i.i_ac = NULL;
+ AFFS_I(inode)->i_lc = NULL;
+ AFFS_I(inode)->i_ac = NULL;
free_page(cache_page);
}
- affs_brelse(AFFS_INODE->i_ext_bh);
- AFFS_INODE->i_ext_last = ~1;
- AFFS_INODE->i_ext_bh = NULL;
+ affs_brelse(AFFS_I(inode)->i_ext_bh);
+ AFFS_I(inode)->i_ext_last = ~1;
+ AFFS_I(inode)->i_ext_bh = NULL;
}
struct inode *
@@ -318,11 +326,20 @@ affs_new_inode(struct inode *dir)
inode->i_ino = block;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
- AFFS_INODE->i_extcnt = 1;
- AFFS_INODE->i_ext_last = ~1;
- init_MUTEX(&AFFS_INODE->i_link_lock);
- init_MUTEX(&AFFS_INODE->i_ext_lock);
+ AFFS_I(inode)->i_opencnt = 0;
+ AFFS_I(inode)->i_blkcnt = 0;
+ AFFS_I(inode)->i_lc = NULL;
+ AFFS_I(inode)->i_lc_size = 0;
+ AFFS_I(inode)->i_lc_shift = 0;
+ AFFS_I(inode)->i_lc_mask = 0;
+ AFFS_I(inode)->i_ac = NULL;
+ AFFS_I(inode)->i_ext_bh = NULL;
+ AFFS_I(inode)->mmu_private = 0;
+ AFFS_I(inode)->i_protect = 0;
+ AFFS_I(inode)->i_lastalloc = 0;
+ AFFS_I(inode)->i_pa_cnt = 0;
+ AFFS_I(inode)->i_extcnt = 1;
+ AFFS_I(inode)->i_ext_last = ~1;
insert_inode_hash(inode);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index b4653c37f..e824a71af 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -78,7 +78,54 @@ affs_write_super(struct super_block *sb)
pr_debug("AFFS: write_super() at %lu, clean=%d\n", CURRENT_TIME, clean);
}
+static kmem_cache_t * affs_inode_cachep;
+
+static struct inode *affs_alloc_inode(struct super_block *sb)
+{
+ struct affs_inode_info *ei;
+ ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void affs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(affs_inode_cachep, AFFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct affs_inode_info *ei = (struct affs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ init_MUTEX(&ei->i_link_lock);
+ init_MUTEX(&ei->i_ext_lock);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ affs_inode_cachep = kmem_cache_create("affs_inode_cache",
+ sizeof(struct affs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (affs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(affs_inode_cachep))
+ printk(KERN_INFO "affs_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations affs_sops = {
+ alloc_inode: affs_alloc_inode,
+ destroy_inode: affs_destroy_inode,
read_inode: affs_read_inode,
write_inode: affs_write_inode,
put_inode: affs_put_inode,
@@ -490,12 +537,23 @@ static DECLARE_FSTYPE_DEV(affs_fs_type, "affs", affs_read_super);
static int __init init_affs_fs(void)
{
- return register_filesystem(&affs_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&affs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_affs_fs(void)
{
unregister_filesystem(&affs_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 244dc64ac..dcbc3a688 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -49,6 +49,8 @@ typedef struct {
} Node;
static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
+static struct vfsmount *bm_mnt;
+static int entry_count = 0;
/*
* Check if we support the binfmt
@@ -390,10 +392,15 @@ static void bm_clear_inode(struct inode *inode)
Node *e = inode->u.generic_ip;
if (e) {
+ struct vfsmount *mnt;
write_lock(&entries_lock);
list_del(&e->list);
+ mnt = bm_mnt;
+ if (!--entry_count)
+ bm_mnt = NULL;
write_unlock(&entries_lock);
kfree(e);
+ mntput(mnt);
}
}
@@ -404,8 +411,7 @@ static void kill_node(Node *e)
write_lock(&entries_lock);
dentry = e->dentry;
if (dentry) {
- list_del(&e->list);
- INIT_LIST_HEAD(&e->list);
+ list_del_init(&e->list);
e->dentry = NULL;
}
write_unlock(&entries_lock);
@@ -484,12 +490,16 @@ static struct file_operations bm_entry_operations = {
write: bm_entry_write,
};
+static struct file_system_type bm_fs_type;
+
/* /register */
static ssize_t bm_register_write(struct file *file, const char *buffer,
size_t count, loff_t *ppos)
{
Node *e;
+ struct inode *inode;
+ struct vfsmount *mnt = NULL;
struct dentry *root, *dentry;
struct super_block *sb = file->f_vfsmnt->mnt_sb;
int err = 0;
@@ -503,31 +513,52 @@ static ssize_t bm_register_write(struct file *file, const char *buffer,
down(&root->d_inode->i_sem);
dentry = lookup_one_len(e->name, root, strlen(e->name));
err = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- down(&root->d_inode->i_zombie);
- if (dentry->d_inode) {
- err = -EEXIST;
- } else {
- struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
- err = -ENOMEM;
+ if (IS_ERR(dentry))
+ goto out;
- if (inode) {
- write_lock(&entries_lock);
+ down(&root->d_inode->i_zombie);
- e->dentry = dget(dentry);
- inode->u.generic_ip = e;
- inode->i_fop = &bm_entry_operations;
- d_instantiate(dentry, inode);
+ err = -EEXIST;
+ if (dentry->d_inode)
+ goto out2;
- list_add(&e->list, &entries);
- write_unlock(&entries_lock);
+ inode = bm_get_inode(sb, S_IFREG | 0644);
- err = 0;
- }
+ err = -ENOMEM;
+ if (!inode)
+ goto out2;
+
+ write_lock(&entries_lock);
+ if (!bm_mnt) {
+ write_unlock(&entries_lock);
+ mnt = kern_mount(&bm_fs_type);
+ if (IS_ERR(mnt)) {
+ err = PTR_ERR(mnt);
+ iput(inode);
+ inode = NULL;
+ goto out2;
}
- up(&root->d_inode->i_zombie);
- dput(dentry);
+ write_lock(&entries_lock);
+ if (!bm_mnt)
+ bm_mnt = mnt;
}
+ mntget(bm_mnt);
+ entry_count++;
+
+ e->dentry = dget(dentry);
+ inode->u.generic_ip = e;
+ inode->i_fop = &bm_entry_operations;
+ d_instantiate(dentry, inode);
+
+ list_add(&e->list, &entries);
+ write_unlock(&entries_lock);
+
+ mntput(mnt);
+ err = 0;
+out2:
+ up(&root->d_inode->i_zombie);
+ dput(dentry);
+out:
up(&root->d_inode->i_sem);
dput(root);
@@ -687,23 +718,13 @@ static struct linux_binfmt misc_format = {
static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
-static struct vfsmount *bm_mnt;
-
static int __init init_misc_binfmt(void)
{
int err = register_filesystem(&bm_fs_type);
if (!err) {
- bm_mnt = kern_mount(&bm_fs_type);
- err = PTR_ERR(bm_mnt);
- if (IS_ERR(bm_mnt))
+ err = register_binfmt(&misc_format);
+ if (err)
unregister_filesystem(&bm_fs_type);
- else {
- err = register_binfmt(&misc_format);
- if (err) {
- unregister_filesystem(&bm_fs_type);
- kern_umount(bm_mnt);
- }
- }
}
return err;
}
@@ -712,7 +733,6 @@ static void __exit exit_misc_binfmt(void)
{
unregister_binfmt(&misc_format);
unregister_filesystem(&bm_fs_type);
- kern_umount(bm_mnt);
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 4f34a8c0d..0d848e923 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -220,17 +220,19 @@ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent)
{
static struct super_operations sops = {};
- struct inode *root = new_inode(sb);
- if (!root)
- return NULL;
- root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
- root->i_uid = root->i_gid = 0;
- root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+ struct inode *root;
+
sb->s_maxbytes = ~0ULL;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = 0x62646576;
sb->s_op = &sops;
+ root = new_inode(sb);
+ if (!root)
+ return NULL;
+ root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
+ root->i_uid = root->i_gid = 0;
+ root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 });
if (!sb->s_root) {
iput(root);
diff --git a/fs/buffer.c b/fs/buffer.c
index 8a9233a44..baaf40a16 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -582,23 +582,13 @@ struct buffer_head * __get_hash_table(struct block_device *bdev, sector_t block,
return bh;
}
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
{
spin_lock(&lru_list_lock);
if (bh->b_inode)
list_del(&bh->b_inode_buffers);
- bh->b_inode = inode;
- list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
- spin_unlock(&lru_list_lock);
-}
-
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
- spin_lock(&lru_list_lock);
- if (bh->b_inode)
- list_del(&bh->b_inode_buffers);
- bh->b_inode = inode;
- list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
+ bh->b_inode = 1;
+ list_add(&bh->b_inode_buffers, list);
spin_unlock(&lru_list_lock);
}
@@ -606,7 +596,7 @@ void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
remove_inode_queue functions. */
static void __remove_inode_queue(struct buffer_head *bh)
{
- bh->b_inode = NULL;
+ bh->b_inode = 0;
list_del(&bh->b_inode_buffers);
}
@@ -826,73 +816,24 @@ inline void set_buffer_async_io(struct buffer_head *bh)
* any newly dirty buffers for write.
*/
-int fsync_inode_buffers(struct inode *inode)
-{
- struct buffer_head *bh;
- struct inode tmp;
- int err = 0, err2;
-
- INIT_LIST_HEAD(&tmp.i_dirty_buffers);
-
- spin_lock(&lru_list_lock);
-
- while (!list_empty(&inode->i_dirty_buffers)) {
- bh = BH_ENTRY(inode->i_dirty_buffers.next);
- list_del(&bh->b_inode_buffers);
- if (!buffer_dirty(bh) && !buffer_locked(bh))
- bh->b_inode = NULL;
- else {
- bh->b_inode = &tmp;
- list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
- if (buffer_dirty(bh)) {
- get_bh(bh);
- spin_unlock(&lru_list_lock);
- ll_rw_block(WRITE, 1, &bh);
- brelse(bh);
- spin_lock(&lru_list_lock);
- }
- }
- }
-
- while (!list_empty(&tmp.i_dirty_buffers)) {
- bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
- remove_inode_queue(bh);
- get_bh(bh);
- spin_unlock(&lru_list_lock);
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- err = -EIO;
- brelse(bh);
- spin_lock(&lru_list_lock);
- }
-
- spin_unlock(&lru_list_lock);
- err2 = osync_inode_buffers(inode);
-
- if (err)
- return err;
- else
- return err2;
-}
-
-int fsync_inode_data_buffers(struct inode *inode)
+int fsync_buffers_list(struct list_head *list)
{
struct buffer_head *bh;
- struct inode tmp;
+ struct list_head tmp;
int err = 0, err2;
- INIT_LIST_HEAD(&tmp.i_dirty_data_buffers);
+ INIT_LIST_HEAD(&tmp);
spin_lock(&lru_list_lock);
- while (!list_empty(&inode->i_dirty_data_buffers)) {
- bh = BH_ENTRY(inode->i_dirty_data_buffers.next);
+ while (!list_empty(list)) {
+ bh = BH_ENTRY(list->next);
list_del(&bh->b_inode_buffers);
if (!buffer_dirty(bh) && !buffer_locked(bh))
- bh->b_inode = NULL;
+ bh->b_inode = 0;
else {
- bh->b_inode = &tmp;
- list_add(&bh->b_inode_buffers, &tmp.i_dirty_data_buffers);
+ bh->b_inode = 1;
+ list_add(&bh->b_inode_buffers, &tmp);
if (buffer_dirty(bh)) {
get_bh(bh);
spin_unlock(&lru_list_lock);
@@ -903,8 +844,8 @@ int fsync_inode_data_buffers(struct inode *inode)
}
}
- while (!list_empty(&tmp.i_dirty_data_buffers)) {
- bh = BH_ENTRY(tmp.i_dirty_data_buffers.prev);
+ while (!list_empty(&tmp)) {
+ bh = BH_ENTRY(tmp.prev);
remove_inode_queue(bh);
get_bh(bh);
spin_unlock(&lru_list_lock);
@@ -916,7 +857,7 @@ int fsync_inode_data_buffers(struct inode *inode)
}
spin_unlock(&lru_list_lock);
- err2 = osync_inode_data_buffers(inode);
+ err2 = osync_buffers_list(list);
if (err)
return err;
@@ -935,19 +876,19 @@ int fsync_inode_data_buffers(struct inode *inode)
* write will not be flushed to disk by the osync.
*/
-int osync_inode_buffers(struct inode *inode)
+int osync_buffers_list(struct list_head *list)
{
struct buffer_head *bh;
- struct list_head *list;
+ struct list_head *p;
int err = 0;
spin_lock(&lru_list_lock);
repeat:
- for (list = inode->i_dirty_buffers.prev;
- bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
- list = bh->b_inode_buffers.prev) {
+ for (p = list->prev;
+ bh = BH_ENTRY(p), p != list;
+ p = bh->b_inode_buffers.prev) {
if (buffer_locked(bh)) {
get_bh(bh);
spin_unlock(&lru_list_lock);
@@ -964,36 +905,6 @@ int osync_inode_buffers(struct inode *inode)
return err;
}
-int osync_inode_data_buffers(struct inode *inode)
-{
- struct buffer_head *bh;
- struct list_head *list;
- int err = 0;
-
- spin_lock(&lru_list_lock);
-
- repeat:
-
- for (list = inode->i_dirty_data_buffers.prev;
- bh = BH_ENTRY(list), list != &inode->i_dirty_data_buffers;
- list = bh->b_inode_buffers.prev) {
- if (buffer_locked(bh)) {
- get_bh(bh);
- spin_unlock(&lru_list_lock);
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- err = -EIO;
- brelse(bh);
- spin_lock(&lru_list_lock);
- goto repeat;
- }
- }
-
- spin_unlock(&lru_list_lock);
- return err;
-}
-
-
/*
* Invalidate any and all dirty buffers on a given inode. We are
* probably unmounting the fs, but that doesn't mean we have already
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 3918709b0..365fb633e 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -39,9 +39,60 @@ static void coda_clear_inode(struct inode *);
static void coda_put_super(struct super_block *);
static int coda_statfs(struct super_block *sb, struct statfs *buf);
+static kmem_cache_t * coda_inode_cachep;
+
+static struct inode *coda_alloc_inode(struct super_block *sb)
+{
+ struct coda_inode_info *ei;
+ ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL);
+ memset(&ei->c_fid, 0, sizeof(struct ViceFid));
+ ei->c_flags = 0;
+ INIT_LIST_HEAD(&ei->c_cilist);
+ ei->c_container = NULL;
+ ei->c_contcount = 0;
+ memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
+ ei->c_cached_perm = 0;
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void coda_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(coda_inode_cachep, ITOC(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct coda_inode_info *ei = (struct coda_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+int coda_init_inodecache(void)
+{
+ coda_inode_cachep = kmem_cache_create("coda_inode_cache",
+ sizeof(struct coda_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (coda_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+void coda_destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(coda_inode_cachep))
+ printk(KERN_INFO "coda_inode_cache: not all structures were freed\n");
+}
+
/* exported operations */
struct super_operations coda_super_operations =
{
+ alloc_inode: coda_alloc_inode,
+ destroy_inode: coda_destroy_inode,
read_inode: coda_read_inode,
clear_inode: coda_clear_inode,
put_super: coda_put_super,
@@ -188,28 +239,7 @@ static void coda_read_inode(struct inode *inode)
if (!sbi) BUG();
-#if 0
- /* check if the inode is already initialized */
- if (inode->u.generic_ip) {
- printk("coda_read_inode: initialized inode");
- return;
- }
-
- inode->u.generic_ip = cii_alloc();
- if (!inode->u.generic_ip) {
- CDEBUG(D_CNODE, "coda_read_inode: failed to allocate inode info\n");
- make_bad_inode(inode);
- return;
- }
- memset(inode->u.generic_ip, 0, sizeof(struct coda_inode_info));
-#endif
-
cii = ITOC(inode);
- if (!coda_isnullfid(&cii->c_fid)) {
- printk("coda_read_inode: initialized inode");
- return;
- }
-
list_add(&cii->c_cilist, &sbi->sbi_cihead);
}
@@ -226,11 +256,6 @@ static void coda_clear_inode(struct inode *inode)
list_del_init(&cii->c_cilist);
inode->i_mapping = &inode->i_data;
coda_cache_clear_inode(inode);
-
-#if 0
- cii_free(inode->u.generic_ip);
- inode->u.generic_ip = NULL;
-#endif
}
int coda_notify_change(struct dentry *de, struct iattr *iattr)
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 7300732d4..add25fd1c 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -407,24 +407,35 @@ static int init_coda_psdev(void)
MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
MODULE_LICENSE("GPL");
+extern int coda_init_inodecache(void);
+extern void coda_destroy_inodecache(void);
static int __init init_coda(void)
{
int status;
printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.15, coda@cs.cmu.edu\n");
+ status = coda_init_inodecache();
+ if (status)
+ goto out2;
status = init_coda_psdev();
if ( status ) {
printk("Problem (%d) in init_coda_psdev\n", status);
- return status;
+ goto out1;
}
status = register_filesystem(&coda_fs_type);
if (status) {
printk("coda: failed to register filesystem!\n");
- devfs_unregister(devfs_handle);
- devfs_unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
- coda_sysctl_clean();
+ goto out;
}
+ return 0;
+out:
+ devfs_unregister(devfs_handle);
+ devfs_unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
+ coda_sysctl_clean();
+out1:
+ coda_destroy_inodecache();
+out2:
return status;
}
@@ -439,6 +450,7 @@ static void __exit exit_coda(void)
devfs_unregister(devfs_handle);
devfs_unregister_chrdev(CODA_PSDEV_MAJOR, "coda_psdev");
coda_sysctl_clean();
+ coda_destroy_inodecache();
}
module_init(init_coda);
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 19c406600..e7b2eec05 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -1,6 +1,6 @@
/* devfs (Device FileSystem) driver.
- Copyright (C) 1998-2001 Richard Gooch
+ Copyright (C) 1998-2002 Richard Gooch
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -604,6 +604,10 @@
20020113 Richard Gooch <rgooch@atnf.csiro.au>
Fixed (rare, old) race in <devfs_lookup>.
v1.9
+ 20020120 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed deadlock bug in <devfs_d_revalidate_wait>.
+ Tag VFS deletable in <devfs_mk_symlink> if handle ignored.
+ v1.10
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -636,7 +640,7 @@
#include <asm/bitops.h>
#include <asm/atomic.h>
-#define DEVFS_VERSION "1.9 (20020113)"
+#define DEVFS_VERSION "1.10 (20020120)"
#define DEVFS_NAME "devfs"
@@ -781,7 +785,7 @@ struct devfs_entry
umode_t mode;
unsigned short namelen; /* I think 64k+ filenames are a way off... */
unsigned char hide:1;
- unsigned char vfs_created:1; /* Whether created by driver or VFS */
+ unsigned char vfs_deletable:1;/* Whether the VFS may delete the entry */
char name[1]; /* This is just a dummy: the allocated array
is bigger. This is NULL-terminated */
};
@@ -1774,7 +1778,8 @@ int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags,
DPRINTK (DEBUG_REGISTER, "(%s)\n", name);
err = devfs_do_symlink (dir, name, flags, link, &de, info);
if (err) return err;
- if (handle != NULL) *handle = de;
+ if (handle == NULL) de->vfs_deletable = TRUE;
+ else *handle = de;
devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
return 0;
} /* End Function devfs_mk_symlink */
@@ -1817,7 +1822,7 @@ devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
{
PRINTK ("(%s): using old entry in dir: %p \"%s\"\n",
name, dir, dir->name);
- old->vfs_created = FALSE;
+ old->vfs_deletable = FALSE;
devfs_put (dir);
return old;
}
@@ -2878,13 +2883,16 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
DECLARE_WAITQUEUE (wait, current);
- if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
+ if ( is_devfsd_or_child (fs_info) )
{
devfs_handle_t de = lookup_info->de;
struct inode *inode;
- DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p de: %p by: \"%s\"\n",
- dentry->d_name.name, dentry, de, current->comm);
+ DPRINTK (DEBUG_I_LOOKUP,
+ "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
+ dentry->d_name.name, dentry, dentry->d_inode, de,
+ current->comm);
+ if (dentry->d_inode) return 1;
if (de == NULL)
{
read_lock (&parent->u.dir.lock);
@@ -3015,7 +3023,7 @@ static int devfs_unlink (struct inode *dir, struct dentry *dentry)
de = get_devfs_entry_from_vfs_inode (inode);
DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
if (de == NULL) return -ENOENT;
- if (!de->vfs_created) return -EPERM;
+ if (!de->vfs_deletable) return -EPERM;
write_lock (&de->parent->u.dir.lock);
unhooked = _devfs_unhook (de);
write_unlock (&de->parent->u.dir.lock);
@@ -3044,7 +3052,7 @@ static int devfs_symlink (struct inode *dir, struct dentry *dentry,
DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
dentry->d_name.name, err);
if (err < 0) return err;
- de->vfs_created = TRUE;
+ de->vfs_deletable = TRUE;
de->inode.uid = current->euid;
de->inode.gid = current->egid;
de->inode.atime = CURRENT_TIME;
@@ -3073,7 +3081,7 @@ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
if (parent == NULL) return -ENOENT;
de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
if (!de) return -ENOMEM;
- de->vfs_created = TRUE;
+ de->vfs_deletable = TRUE;
if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
return err;
de->inode.uid = current->euid;
@@ -3103,7 +3111,7 @@ static int devfs_rmdir (struct inode *dir, struct dentry *dentry)
de = get_devfs_entry_from_vfs_inode (inode);
if (de == NULL) return -ENOENT;
if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
- if (!de->vfs_created) return -EPERM;
+ if (!de->vfs_deletable) return -EPERM;
/* First ensure the directory is empty and will stay thay way */
write_lock (&de->u.dir.lock);
de->u.dir.no_more_additions = TRUE;
@@ -3137,7 +3145,7 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
if (parent == NULL) return -ENOENT;
de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
if (!de) return -ENOMEM;
- de->vfs_created = TRUE;
+ de->vfs_deletable = TRUE;
if ( S_ISBLK (mode) || S_ISCHR (mode) )
{
de->u.fcb.u.device.major = MAJOR (rdev);
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 9be6577fe..393ca3ece 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -139,6 +139,11 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
printk("devpts: called with bogus options\n");
goto fail_free;
}
+ s->u.generic_sbp = (void *) sbi;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = DEVPTS_SUPER_MAGIC;
+ s->s_op = &devpts_sops;
inode = new_inode(s);
if (!inode)
@@ -153,11 +158,6 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
inode->i_fop = &devpts_root_operations;
inode->i_nlink = 2;
- s->u.generic_sbp = (void *) sbi;
- s->s_blocksize = 1024;
- s->s_blocksize_bits = 10;
- s->s_magic = DEVPTS_SUPER_MAGIC;
- s->s_op = &devpts_sops;
s->s_root = d_alloc_root(inode);
if (s->s_root)
return s;
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 2d8f5afb9..541d86f2c 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -12,21 +12,78 @@
#include <linux/efs_fs.h>
#include <linux/efs_vh.h>
#include <linux/efs_fs_sb.h>
+#include <linux/slab.h>
static DECLARE_FSTYPE_DEV(efs_fs_type, "efs", efs_read_super);
+static kmem_cache_t * efs_inode_cachep;
+
+static struct inode *efs_alloc_inode(struct super_block *sb)
+{
+ struct efs_inode_info *ei;
+ ei = (struct efs_inode_info *)kmem_cache_alloc(efs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void efs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(efs_inode_cachep, INODE_INFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct efs_inode_info *ei = (struct efs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ efs_inode_cachep = kmem_cache_create("efs_inode_cache",
+ sizeof(struct efs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (efs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(efs_inode_cachep))
+ printk(KERN_INFO "efs_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations efs_superblock_operations = {
+ alloc_inode: efs_alloc_inode,
+ destroy_inode: efs_destroy_inode,
read_inode: efs_read_inode,
statfs: efs_statfs,
};
static int __init init_efs_fs(void) {
+ int err;
printk("EFS: "EFS_VERSION" - http://aeschi.ch.eu.org/efs/\n");
- return register_filesystem(&efs_fs_type);
+ err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&efs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_efs_fs(void) {
unregister_filesystem(&efs_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index da07d9462..5d3f1486f 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -12,8 +12,7 @@
*/
#include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -42,19 +41,20 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
unsigned long group_desc;
unsigned long desc;
struct ext2_group_desc * gdp;
+ struct ext2_sb_info *sbi = &sb->u.ext2_sb;
- if (block_group >= sb->u.ext2_sb.s_groups_count) {
+ if (block_group >= sbi->s_groups_count) {
ext2_error (sb, "ext2_get_group_desc",
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
- block_group, sb->u.ext2_sb.s_groups_count);
+ block_group, sbi->s_groups_count);
return NULL;
}
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
desc = block_group % EXT2_DESC_PER_BLOCK(sb);
- if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+ if (!sbi->s_group_desc[group_desc]) {
ext2_error (sb, "ext2_get_group_desc",
"Group descriptor not loaded - "
"block_group = %d, group_desc = %lu, desc = %lu",
@@ -62,10 +62,9 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
return NULL;
}
- gdp = (struct ext2_group_desc *)
- sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+ gdp = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
if (bh)
- *bh = sb->u.ext2_sb.s_group_desc[group_desc];
+ *bh = sbi->s_group_desc[group_desc];
return gdp + desc;
}
@@ -73,37 +72,26 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
* Read the bitmap for a given block_group, reading into the specified
* slot in the superblock's bitmap cache.
*
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head on success or NULL in case of failure.
*/
-static int read_block_bitmap (struct super_block * sb,
- unsigned int block_group,
- unsigned long bitmap_nr)
+static struct buffer_head *read_block_bitmap(struct super_block *sb,
+ unsigned int block_group)
{
struct ext2_group_desc * gdp;
struct buffer_head * bh = NULL;
- int retval = -EIO;
gdp = ext2_get_group_desc (sb, block_group, NULL);
if (!gdp)
goto error_out;
- retval = 0;
bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
- if (!bh) {
+ if (!bh)
ext2_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %lu",
block_group, (unsigned long) gdp->bg_block_bitmap);
- retval = -EIO;
- }
- /*
- * On IO error, just leave a zero in the superblock's block pointer for
- * this group. The IO will be retried next time.
- */
error_out:
- sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
- sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
- return retval;
+ return bh;
}
/*
@@ -117,134 +105,65 @@ error_out:
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
*
- * Return the slot used to store the bitmap, or a -ve error code.
+ * Return the buffer_head of the bitmap or ERR_PTR(-ve).
*/
-static int __load_block_bitmap (struct super_block * sb,
- unsigned int block_group)
+static struct buffer_head *load_block_bitmap(struct super_block * sb,
+ unsigned int block_group)
{
- int i, j, retval = 0;
- unsigned long block_bitmap_number;
- struct buffer_head * block_bitmap;
+ struct ext2_sb_info *sbi = &sb->u.ext2_sb;
+ int i, slot = 0;
+ struct buffer_head *bh = sbi->s_block_bitmap[0];
- if (block_group >= sb->u.ext2_sb.s_groups_count)
+ if (block_group >= sbi->s_groups_count)
ext2_panic (sb, "load_block_bitmap",
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
- block_group, sb->u.ext2_sb.s_groups_count);
-
- if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
- if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
- if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
- block_group)
- return block_group;
- ext2_error (sb, "__load_block_bitmap",
- "block_group != block_bitmap_number");
- }
- retval = read_block_bitmap (sb, block_group, block_group);
- if (retval < 0)
- return retval;
- return block_group;
- }
-
- for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
- sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++)
- ;
- if (i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
- sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) {
- block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i];
- block_bitmap = sb->u.ext2_sb.s_block_bitmap[i];
- for (j = i; j > 0; j--) {
- sb->u.ext2_sb.s_block_bitmap_number[j] =
- sb->u.ext2_sb.s_block_bitmap_number[j - 1];
- sb->u.ext2_sb.s_block_bitmap[j] =
- sb->u.ext2_sb.s_block_bitmap[j - 1];
- }
- sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
- sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
-
- /*
- * There's still one special case here --- if block_bitmap == 0
- * then our last attempt to read the bitmap failed and we have
- * just ended up caching that failure. Try again to read it.
- */
- if (!block_bitmap)
- retval = read_block_bitmap (sb, block_group, 0);
- } else {
- if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
- sb->u.ext2_sb.s_loaded_block_bitmaps++;
- else
- brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
- for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
- sb->u.ext2_sb.s_block_bitmap_number[j] =
- sb->u.ext2_sb.s_block_bitmap_number[j - 1];
- sb->u.ext2_sb.s_block_bitmap[j] =
- sb->u.ext2_sb.s_block_bitmap[j - 1];
- }
- retval = read_block_bitmap (sb, block_group, 0);
- }
- return retval;
-}
-
-/*
- * Load the block bitmap for a given block group. First of all do a couple
- * of fast lookups for common cases and then pass the request onto the guts
- * of the bitmap loader.
- *
- * Return the slot number of the group in the superblock bitmap cache's on
- * success, or a -ve error code.
- *
- * There is still one inconsistency here --- if the number of groups in this
- * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of
- * differentiating between a group for which we have never performed a bitmap
- * IO request, and a group for which the last bitmap read request failed.
- */
-static inline int load_block_bitmap (struct super_block * sb,
- unsigned int block_group)
-{
- int slot;
+ block_group, sbi->s_groups_count);
/*
* Do the lookup for the slot. First of all, check if we're asking
* for the same slot as last time, and did we succeed that last time?
*/
- if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
- sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
- sb->u.ext2_sb.s_block_bitmap[0]) {
- return 0;
- }
- /*
- * Or can we do a fast lookup based on a loaded group on a filesystem
- * small enough to be mapped directly into the superblock?
- */
- else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
- sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
- sb->u.ext2_sb.s_block_bitmap[block_group]) {
+ if (sbi->s_loaded_block_bitmaps > 0 &&
+ sbi->s_block_bitmap_number[0] == block_group && bh)
+ goto found;
+
+ if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
slot = block_group;
+ bh = sbi->s_block_bitmap[slot];
+ if (!bh)
+ goto read_it;
+ if (sbi->s_block_bitmap_number[slot] == slot)
+ goto found;
+ ext2_panic (sb, "__load_block_bitmap",
+ "block_group != block_bitmap_number");
}
- /*
- * If not, then do a full lookup for this block group.
- */
- else {
- slot = __load_block_bitmap (sb, block_group);
+
+ bh = NULL;
+ for (i = 0; i < sbi->s_loaded_block_bitmaps &&
+ sbi->s_block_bitmap_number[i] != block_group; i++)
+ ;
+ if (i < sbi->s_loaded_block_bitmaps)
+ bh = sbi->s_block_bitmap[i];
+ else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
+ sbi->s_loaded_block_bitmaps++;
+ else
+ brelse (sbi->s_block_bitmap[--i]);
+
+ while (i--) {
+ sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i];
+ sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i];
}
- /*
- * <0 means we just got an error
- */
- if (slot < 0)
- return slot;
-
- /*
- * If it's a valid slot, we may still have cached a previous IO error,
- * in which case the bh in the superblock cache will be zero.
- */
- if (!sb->u.ext2_sb.s_block_bitmap[slot])
- return -EIO;
-
- /*
- * Must have been read in OK to get this far.
- */
- return slot;
+read_it:
+ if (!bh)
+ bh = read_block_bitmap(sb, block_group);
+ sbi->s_block_bitmap_number[slot] = block_group;
+ sbi->s_block_bitmap[slot] = bh;
+ if (!bh)
+ return ERR_PTR(-EIO);
+found:
+ return bh;
}
/* Free given blocks, update quota and i_blocks field */
@@ -256,7 +175,6 @@ void ext2_free_blocks (struct inode * inode, unsigned long block,
unsigned long block_group;
unsigned long bit;
unsigned long i;
- int bitmap_nr;
unsigned long overflow;
struct super_block * sb;
struct ext2_group_desc * gdp;
@@ -293,11 +211,10 @@ do_more:
overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
count -= overflow;
}
- bitmap_nr = load_block_bitmap (sb, block_group);
- if (bitmap_nr < 0)
+ bh = load_block_bitmap (sb, block_group);
+ if (IS_ERR(bh))
goto error_return;
- bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
gdp = ext2_get_group_desc (sb, block_group, &bh2);
if (!gdp)
goto error_return;
@@ -361,7 +278,6 @@ int ext2_new_block (struct inode * inode, unsigned long goal,
struct buffer_head * bh2;
char * p, * r;
int i, j, k, tmp;
- int bitmap_nr;
struct super_block * sb;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
@@ -404,12 +320,10 @@ repeat:
if (j)
goal_attempts++;
#endif
- bitmap_nr = load_block_bitmap (sb, i);
- if (bitmap_nr < 0)
+ bh = load_block_bitmap (sb, i);
+ if (IS_ERR(bh))
goto io_error;
- bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-
ext2_debug ("goal is at %d:%d.\n", i, j);
if (!ext2_test_bit(j, bh->b_data)) {
@@ -477,11 +391,10 @@ repeat:
}
if (k >= sb->u.ext2_sb.s_groups_count)
goto out;
- bitmap_nr = load_block_bitmap (sb, i);
- if (bitmap_nr < 0)
+ bh = load_block_bitmap (sb, i);
+ if (IS_ERR(bh))
goto io_error;
- bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
j = (r - bh->b_data) << 3;
if (j < EXT2_BLOCKS_PER_GROUP(sb))
@@ -619,7 +532,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
#ifdef EXT2FS_DEBUG
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
- int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
@@ -629,16 +541,16 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+ struct buffer_head *bh;
gdp = ext2_get_group_desc (sb, i, NULL);
if (!gdp)
continue;
desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
- bitmap_nr = load_block_bitmap (sb, i);
- if (bitmap_nr < 0)
+ bh = load_block_bitmap (sb, i);
+ if (IS_ERR(bh))
continue;
- x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
- sb->s_blocksize);
+ x = ext2_count_free (bh, sb->s_blocksize);
printk ("group %d: stored = %d, counted = %lu\n",
i, le16_to_cpu(gdp->bg_free_blocks_count), x);
bitmap_count += x;
@@ -720,7 +632,6 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x, j;
unsigned long desc_blocks;
- int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
@@ -733,12 +644,10 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
if (!gdp)
continue;
desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
- bitmap_nr = load_block_bitmap (sb, i);
- if (bitmap_nr < 0)
+ bh = load_block_bitmap (sb, i);
+ if (IS_ERR(bh))
continue;
- bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr];
-
if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
ext2_error(sb, __FUNCTION__,
"Superblock in group %d is marked free", i);
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
index c30a3b075..a007b4460 100644
--- a/fs/ext2/bitmap.c
+++ b/fs/ext2/bitmap.c
@@ -7,9 +7,7 @@
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-
+#include "ext2.h"
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 9fc9fd62b..d6416b948 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -21,8 +21,7 @@
* and moved here. AV
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/pagemap.h>
typedef struct ext2_dir_entry_2 ext2_dirent;
@@ -306,12 +305,13 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
unsigned long start, n;
unsigned long npages = dir_pages(dir);
struct page *page = NULL;
+ struct ext2_inode_info *ei = EXT2_I(dir);
ext2_dirent * de;
/* OFFSET_CACHE */
*res_page = NULL;
- start = dir->u.ext2_i.i_dir_start_lookup;
+ start = ei->i_dir_start_lookup;
if (start >= npages)
start = 0;
n = start;
@@ -336,7 +336,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
found:
*res_page = page;
- dir->u.ext2_i.i_dir_start_lookup = n;
+ ei->i_dir_start_lookup = n;
return de;
}
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
new file mode 100644
index 000000000..09d13d60e
--- /dev/null
+++ b/fs/ext2/ext2.h
@@ -0,0 +1,120 @@
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+/*
+ * second extended file system inode data in memory
+ */
+struct ext2_inode_info {
+ __u32 i_data[15];
+ __u32 i_flags;
+ __u32 i_faddr;
+ __u8 i_frag_no;
+ __u8 i_frag_size;
+ __u16 i_osync;
+ __u32 i_file_acl;
+ __u32 i_dir_acl;
+ __u32 i_dtime;
+ __u32 i_block_group;
+ __u32 i_next_alloc_block;
+ __u32 i_next_alloc_goal;
+ __u32 i_prealloc_block;
+ __u32 i_prealloc_count;
+ __u32 i_dir_start_lookup;
+ struct inode vfs_inode;
+};
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext2 source programs needs to include it so they are duplicated here.
+ */
+
+static inline struct ext2_inode_info *EXT2_I(struct inode *inode)
+{
+ return list_entry(inode, struct ext2_inode_info, vfs_inode);
+}
+
+/* balloc.c */
+extern int ext2_bg_has_super(struct super_block *sb, int group);
+extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
+extern int ext2_new_block (struct inode *, unsigned long,
+ __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (struct inode *, unsigned long,
+ unsigned long);
+extern unsigned long ext2_count_free_blocks (struct super_block *);
+extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
+
+/* dir.c */
+extern int ext2_add_link (struct dentry *, struct inode *);
+extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
+extern int ext2_make_empty(struct inode *, struct inode *);
+extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
+extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
+extern int ext2_empty_dir (struct inode *);
+extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
+extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
+
+/* fsync.c */
+extern int ext2_sync_file (struct file *, struct dentry *, int);
+extern int ext2_fsync_inode (struct inode *, int);
+
+/* ialloc.c */
+extern struct inode * ext2_new_inode (struct inode *, int);
+extern void ext2_free_inode (struct inode *);
+extern unsigned long ext2_count_free_inodes (struct super_block *);
+extern void ext2_check_inodes_bitmap (struct super_block *);
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
+
+/* inode.c */
+extern void ext2_read_inode (struct inode *);
+extern void ext2_write_inode (struct inode *, int);
+extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
+extern int ext2_sync_inode (struct inode *);
+extern void ext2_discard_prealloc (struct inode *);
+extern void ext2_truncate (struct inode *);
+
+/* ioctl.c */
+extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+/* super.c */
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
+ const char *, ...)
+ __attribute__ ((NORET_AND format (printf, 3, 4)));
+extern void ext2_warning (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void ext2_update_dynamic_rev (struct super_block *sb);
+extern void ext2_put_super (struct super_block *);
+extern void ext2_write_super (struct super_block *);
+extern int ext2_remount (struct super_block *, int *, char *);
+extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int ext2_statfs (struct super_block *, struct statfs *);
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct file_operations ext2_dir_operations;
+
+/* file.c */
+extern struct inode_operations ext2_file_inode_operations;
+extern struct file_operations ext2_file_operations;
+
+/* inode.c */
+extern struct address_space_operations ext2_aops;
+
+/* namei.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations ext2_fast_symlink_inode_operations;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 8d978bdf6..9843debce 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -18,8 +18,7 @@
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/sched.h>
/*
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 211e52c7f..14c5db0d8 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -22,8 +22,7 @@
* we can depend on generic_block_fdatasync() to sync the data blocks.
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/locks.h>
#include <linux/smp_lock.h>
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index b492a6b22..dc40b916d 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -13,8 +13,7 @@
*/
#include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -311,7 +310,7 @@ found:
return group;
}
-struct inode * ext2_new_inode (const struct inode * dir, int mode)
+struct inode * ext2_new_inode(struct inode * dir, int mode)
{
struct super_block * sb;
struct buffer_head * bh;
@@ -321,6 +320,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
struct inode * inode;
struct ext2_group_desc * desc;
struct ext2_super_block * es;
+ struct ext2_inode_info *ei;
int err;
sb = dir->i_sb;
@@ -328,13 +328,14 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
if (!inode)
return ERR_PTR(-ENOMEM);
+ ei = EXT2_I(inode);
lock_super (sb);
es = sb->u.ext2_sb.s_es;
repeat:
if (S_ISDIR(mode))
- group = find_group_dir(sb, dir->u.ext2_i.i_block_group);
+ group = find_group_dir(sb, EXT2_I(dir)->i_block_group);
else
- group = find_group_other(sb, dir->u.ext2_i.i_block_group);
+ group = find_group_other(sb, EXT2_I(dir)->i_block_group);
err = -ENOSPC;
if (group == -1)
@@ -385,15 +386,26 @@ repeat:
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->u.ext2_i.i_new_inode = 1;
- inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
+ memset(ei->i_data, 0, sizeof(ei->i_data));
+ ei->i_flags = EXT2_I(dir)->i_flags;
if (S_ISLNK(mode))
- inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
- inode->u.ext2_i.i_block_group = group;
- if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
+ ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
+ ei->i_faddr = 0;
+ ei->i_frag_no = 0;
+ ei->i_osync = 0;
+ ei->i_file_acl = 0;
+ ei->i_dir_acl = 0;
+ ei->i_dtime = 0;
+ ei->i_block_group = group;
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
+ ei->i_prealloc_block = 0;
+ ei->i_prealloc_count = 0;
+ ei->i_dir_start_lookup = 0;
+ if (ei->i_flags & EXT2_SYNC_FL)
inode->i_flags |= S_SYNC;
- insert_inode_hash(inode);
inode->i_generation = sb->u.ext2_sb.s_next_generation++;
+ insert_inode_hash(inode);
mark_inode_dirty(inode);
unlock_super (sb);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 3c3040e75..a0b631578 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -22,8 +22,7 @@
* Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/locks.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
@@ -57,7 +56,7 @@ void ext2_delete_inode (struct inode * inode)
inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
goto no_delete;
- inode->u.ext2_i.i_dtime = CURRENT_TIME;
+ EXT2_I(inode)->i_dtime = CURRENT_TIME;
mark_inode_dirty(inode);
ext2_update_inode(inode, IS_SYNC(inode));
inode->i_size = 0;
@@ -75,13 +74,14 @@ no_delete:
void ext2_discard_prealloc (struct inode * inode)
{
#ifdef EXT2_PREALLOCATE
+ struct ext2_inode_info *ei = EXT2_I(inode);
lock_kernel();
/* Writer: ->i_prealloc* */
- if (inode->u.ext2_i.i_prealloc_count) {
- unsigned short total = inode->u.ext2_i.i_prealloc_count;
- unsigned long block = inode->u.ext2_i.i_prealloc_block;
- inode->u.ext2_i.i_prealloc_count = 0;
- inode->u.ext2_i.i_prealloc_block = 0;
+ if (ei->i_prealloc_count) {
+ unsigned short total = ei->i_prealloc_count;
+ unsigned long block = ei->i_prealloc_block;
+ ei->i_prealloc_count = 0;
+ ei->i_prealloc_block = 0;
/* Writer: end */
ext2_free_blocks (inode, block, total);
}
@@ -98,13 +98,14 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
#ifdef EXT2_PREALLOCATE
+ struct ext2_inode_info *ei = EXT2_I(inode);
/* Writer: ->i_prealloc* */
- if (inode->u.ext2_i.i_prealloc_count &&
- (goal == inode->u.ext2_i.i_prealloc_block ||
- goal + 1 == inode->u.ext2_i.i_prealloc_block))
+ if (ei->i_prealloc_count &&
+ (goal == ei->i_prealloc_block ||
+ goal + 1 == ei->i_prealloc_block))
{
- result = inode->u.ext2_i.i_prealloc_block++;
- inode->u.ext2_i.i_prealloc_count--;
+ result = ei->i_prealloc_block++;
+ ei->i_prealloc_count--;
/* Writer: end */
ext2_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts);
@@ -114,8 +115,8 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
alloc_hits, ++alloc_attempts);
if (S_ISREG(inode->i_mode))
result = ext2_new_block (inode, goal,
- &inode->u.ext2_i.i_prealloc_count,
- &inode->u.ext2_i.i_prealloc_block, err);
+ &ei->i_prealloc_count,
+ &ei->i_prealloc_block, err);
else
result = ext2_new_block (inode, goal, 0, 0, err);
}
@@ -245,7 +246,7 @@ static Indirect *ext2_get_branch(struct inode *inode,
*err = 0;
/* i_data is not going away, no lock needed */
- add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets);
+ add_chain (chain, NULL, EXT2_I(inode)->i_data + *offsets);
if (!p->key)
goto no_block;
while (--depth) {
@@ -287,7 +288,8 @@ no_block:
static inline unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
{
- u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.ext2_i.i_data;
+ struct ext2_inode_info *ei = EXT2_I(inode);
+ u32 *start = ind->bh ? (u32*) ind->bh->b_data : ei->i_data;
u32 *p;
/* Try to find previous block */
@@ -303,8 +305,7 @@ static inline unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
* It is going to be refered from inode itself? OK, just put it into
* the same cylinder group then.
*/
- return (inode->u.ext2_i.i_block_group *
- EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
+ return (ei->i_block_group * EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block);
}
@@ -327,10 +328,11 @@ static inline int ext2_find_goal(struct inode *inode,
Indirect *partial,
unsigned long *goal)
{
+ struct ext2_inode_info *ei = EXT2_I(inode);
/* Writer: ->i_next_alloc* */
- if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
- inode->u.ext2_i.i_next_alloc_block++;
- inode->u.ext2_i.i_next_alloc_goal++;
+ if (block == ei->i_next_alloc_block + 1) {
+ ei->i_next_alloc_block++;
+ ei->i_next_alloc_goal++;
}
/* Writer: end */
/* Reader: pointers, ->i_next_alloc* */
@@ -339,8 +341,8 @@ static inline int ext2_find_goal(struct inode *inode,
* try the heuristic for sequential allocation,
* failing that at least try to get decent locality.
*/
- if (block == inode->u.ext2_i.i_next_alloc_block)
- *goal = inode->u.ext2_i.i_next_alloc_goal;
+ if (block == ei->i_next_alloc_block)
+ *goal = ei->i_next_alloc_goal;
if (!*goal)
*goal = ext2_find_near(inode, partial);
return 0;
@@ -407,7 +409,7 @@ static int ext2_alloc_branch(struct inode *inode,
mark_buffer_uptodate(bh, 1);
unlock_buffer(bh);
mark_buffer_dirty_inode(bh, inode);
- if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+ if (IS_SYNC(inode) || EXT2_I(inode)->i_osync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
@@ -447,6 +449,7 @@ static inline int ext2_splice_branch(struct inode *inode,
Indirect *where,
int num)
{
+ struct ext2_inode_info *ei = EXT2_I(inode);
int i;
/* Verify that place we are splicing to is still there and vacant */
@@ -459,8 +462,8 @@ static inline int ext2_splice_branch(struct inode *inode,
/* That's it */
*where->p = where->key;
- inode->u.ext2_i.i_next_alloc_block = block;
- inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
+ ei->i_next_alloc_block = block;
+ ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);
/* Writer: end */
@@ -471,13 +474,13 @@ static inline int ext2_splice_branch(struct inode *inode,
/* had we spliced it onto indirect block? */
if (where->bh) {
mark_buffer_dirty_inode(where->bh, inode);
- if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+ if (IS_SYNC(inode) || ei->i_osync) {
ll_rw_block (WRITE, 1, &where->bh);
wait_on_buffer(where->bh);
}
}
- if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
+ if (IS_SYNC(inode) || ei->i_osync)
ext2_sync_inode (inode);
else
mark_inode_dirty(inode);
@@ -785,7 +788,7 @@ static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
void ext2_truncate (struct inode * inode)
{
- u32 *i_data = inode->u.ext2_i.i_data;
+ u32 *i_data = EXT2_I(inode)->i_data;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int offsets[4];
Indirect chain[4];
@@ -886,6 +889,7 @@ void ext2_read_inode (struct inode * inode)
unsigned long block;
unsigned long offset;
struct ext2_group_desc * gdp;
+ struct ext2_inode_info *ei = EXT2_I(inode);
if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
inode->i_ino != EXT2_ACL_DATA_INO &&
@@ -939,13 +943,13 @@ void ext2_read_inode (struct inode * inode)
inode->i_atime = le32_to_cpu(raw_inode->i_atime);
inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
- inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
+ ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
/* We now have enough fields to check if the inode was active or not.
* This is needed because nfsd might try to access dead inodes
* the test is that same one that e2fsck uses
* NeilBrown 1999oct15
*/
- if (inode->i_nlink == 0 && (inode->i_mode == 0 || inode->u.ext2_i.i_dtime)) {
+ if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
/* this inode is deleted */
brelse (bh);
goto bad_inode;
@@ -953,25 +957,30 @@ void ext2_read_inode (struct inode * inode)
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
inode->i_version = ++event;
- inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
- inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
- inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
- inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
- inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
+ ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
+ ei->i_frag_no = raw_inode->i_frag;
+ ei->i_frag_size = raw_inode->i_fsize;
+ ei->i_osync = 0;
+ ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
if (S_ISREG(inode->i_mode))
inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
else
- inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+ ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+ ei->i_dtime = 0;
inode->i_generation = le32_to_cpu(raw_inode->i_generation);
- inode->u.ext2_i.i_prealloc_count = 0;
- inode->u.ext2_i.i_block_group = block_group;
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
+ ei->i_prealloc_count = 0;
+ ei->i_block_group = block_group;
+ ei->i_dir_start_lookup = 0;
/*
* NOTE! The in-memory inode i_data array is in little-endian order
* even on big-endian machines: we do NOT byteswap the block numbers!
*/
for (block = 0; block < EXT2_N_BLOCKS; block++)
- inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+ ei->i_data[block] = raw_inode->i_block[block];
if (inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
@@ -996,19 +1005,19 @@ void ext2_read_inode (struct inode * inode)
le32_to_cpu(raw_inode->i_block[0]));
brelse (bh);
inode->i_attr_flags = 0;
- if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
+ if (ei->i_flags & EXT2_SYNC_FL) {
inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
inode->i_flags |= S_SYNC;
}
- if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
+ if (ei->i_flags & EXT2_APPEND_FL) {
inode->i_attr_flags |= ATTR_FLAG_APPEND;
inode->i_flags |= S_APPEND;
}
- if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
+ if (ei->i_flags & EXT2_IMMUTABLE_FL) {
inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
inode->i_flags |= S_IMMUTABLE;
}
- if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
+ if (ei->i_flags & EXT2_NOATIME_FL) {
inode->i_attr_flags |= ATTR_FLAG_NOATIME;
inode->i_flags |= S_NOATIME;
}
@@ -1030,6 +1039,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
unsigned long offset;
int err = 0;
struct ext2_group_desc * gdp;
+ struct ext2_inode_info *ei = EXT2_I(inode);
if ((inode->i_ino != EXT2_ROOT_INO &&
inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
@@ -1077,7 +1087,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
* Fix up interoperability with old kernels. Otherwise, old inodes get
* re-used with the upper 16 bits of the uid/gid intact
*/
- if(!inode->u.ext2_i.i_dtime) {
+ if(!ei->i_dtime) {
raw_inode->i_uid_high = cpu_to_le16(high_16_bits(inode->i_uid));
raw_inode->i_gid_high = cpu_to_le16(high_16_bits(inode->i_gid));
} else {
@@ -1096,14 +1106,14 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
- raw_inode->i_dtime = cpu_to_le32(inode->u.ext2_i.i_dtime);
- raw_inode->i_flags = cpu_to_le32(inode->u.ext2_i.i_flags);
- raw_inode->i_faddr = cpu_to_le32(inode->u.ext2_i.i_faddr);
- raw_inode->i_frag = inode->u.ext2_i.i_frag_no;
- raw_inode->i_fsize = inode->u.ext2_i.i_frag_size;
- raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
+ raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
+ raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+ raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
+ raw_inode->i_frag = ei->i_frag_no;
+ raw_inode->i_fsize = ei->i_frag_size;
+ raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
if (S_ISDIR(inode->i_mode))
- raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
+ raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
else {
raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
if (inode->i_size > 0x7fffffffULL) {
@@ -1129,7 +1139,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
else for (block = 0; block < EXT2_N_BLOCKS; block++)
- raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
+ raw_inode->i_block[block] = ei->i_data[block];
mark_buffer_dirty(bh);
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 6413da21b..07e9aafbc 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -7,8 +7,7 @@
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/sched.h>
#include <asm/uaccess.h>
@@ -16,13 +15,14 @@
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
+ struct ext2_inode_info *ei = EXT2_I(inode);
unsigned int flags;
ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);
switch (cmd) {
case EXT2_IOC_GETFLAGS:
- flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
+ flags = ei->i_flags & EXT2_FL_USER_VISIBLE;
return put_user(flags, (int *) arg);
case EXT2_IOC_SETFLAGS: {
unsigned int oldflags;
@@ -36,7 +36,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (get_user(flags, (int *) arg))
return -EFAULT;
- oldflags = inode->u.ext2_i.i_flags;
+ oldflags = ei->i_flags;
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
@@ -51,7 +51,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
flags = flags & EXT2_FL_USER_MODIFIABLE;
flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
- inode->u.ext2_i.i_flags = flags;
+ ei->i_flags = flags;
if (flags & EXT2_SYNC_FL)
inode->i_flags |= S_SYNC;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 364deca4f..24afae18f 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -29,8 +29,7 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/pagemap.h>
/*
@@ -134,7 +133,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
if (IS_ERR(inode))
goto out;
- if (l > sizeof (inode->u.ext2_i.i_data)) {
+ if (l > sizeof (EXT2_I(inode)->i_data)) {
/* slow symlink */
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &ext2_aops;
@@ -144,7 +143,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
} else {
/* fast symlink */
inode->i_op = &ext2_fast_symlink_inode_operations;
- memcpy((char*)&inode->u.ext2_i.i_data,symname,l);
+ memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
inode->i_size = l-1;
}
mark_inode_dirty(inode);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 05ae46d5c..bb14991cf 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -19,8 +19,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/locks.h>
@@ -148,7 +147,51 @@ void ext2_put_super (struct super_block * sb)
return;
}
+static kmem_cache_t * ext2_inode_cachep;
+
+static struct inode *ext2_alloc_inode(struct super_block *sb)
+{
+ struct ext2_inode_info *ei;
+ ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void ext2_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
+ sizeof(struct ext2_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (ext2_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(ext2_inode_cachep))
+ printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations ext2_sops = {
+ alloc_inode: ext2_alloc_inode,
+ destroy_inode: ext2_destroy_inode,
read_inode: ext2_read_inode,
write_inode: ext2_write_inode,
put_inode: ext2_put_inode,
@@ -804,12 +847,23 @@ static DECLARE_FSTYPE_DEV(ext2_fs_type, "ext2", ext2_read_super);
static int __init init_ext2_fs(void)
{
- return register_filesystem(&ext2_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&ext2_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_ext2_fs(void)
{
unregister_filesystem(&ext2_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 05a4e585a..c642c53c6 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -17,19 +17,18 @@
* ext2 symlink handling code
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- char *s = (char *)dentry->d_inode->u.ext2_i.i_data;
- return vfs_readlink(dentry, buffer, buflen, s);
+ struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
+ return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data);
}
static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *s = (char *)dentry->d_inode->u.ext2_i.i_data;
- return vfs_follow_link(nd, s);
+ struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
+ return vfs_follow_link(nd, (char *)ei->i_data);
}
struct inode_operations ext2_fast_symlink_inode_operations = {
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 0800f6845..30e309d0f 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -293,7 +293,7 @@ error_return:
* group to find a free inode.
*/
struct inode * ext3_new_inode (handle_t *handle,
- const struct inode * dir, int mode)
+ struct inode * dir, int mode)
{
struct super_block * sb;
struct buffer_head * bh;
@@ -304,6 +304,7 @@ struct inode * ext3_new_inode (handle_t *handle,
struct ext3_group_desc * gdp;
struct ext3_group_desc * tmp;
struct ext3_super_block * es;
+ struct ext3_inode_info *ei;
int err = 0;
/* Cannot create files in a deleted directory */
@@ -314,7 +315,7 @@ struct inode * ext3_new_inode (handle_t *handle,
inode = new_inode(sb);
if (!inode)
return ERR_PTR(-ENOMEM);
- init_rwsem(&inode->u.ext3_i.truncate_sem);
+ ei = EXT3_I(inode);
lock_super (sb);
es = sb->u.ext3_sb.s_es;
@@ -346,7 +347,7 @@ repeat:
/*
* Try to place the inode in its parent directory
*/
- i = dir->u.ext3_i.i_block_group;
+ i = EXT3_I(dir)->i_block_group;
tmp = ext3_get_group_desc (sb, i, &bh2);
if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
gdp = tmp;
@@ -372,7 +373,7 @@ repeat:
/*
* That failed: try linear search for a free inode
*/
- i = dir->u.ext3_i.i_block_group + 1;
+ i = EXT3_I(dir)->i_block_group + 1;
for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) {
if (++i >= sb->u.ext3_sb.s_groups_count)
i = 0;
@@ -479,31 +480,37 @@ repeat:
inode->i_blksize = PAGE_SIZE;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags & ~EXT3_INDEX_FL;
+
+ memset(ei->i_data, 0, sizeof(ei->i_data));
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
+ ei->i_dir_start_lookup = 0;
+ ei->i_disksize = 0;
+
+ ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL;
if (S_ISLNK(mode))
- inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
+ ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
#ifdef EXT3_FRAGMENTS
- inode->u.ext3_i.i_faddr = 0;
- inode->u.ext3_i.i_frag_no = 0;
- inode->u.ext3_i.i_frag_size = 0;
+ ei->i_faddr = 0;
+ ei->i_frag_no = 0;
+ ei->i_frag_size = 0;
#endif
- inode->u.ext3_i.i_file_acl = 0;
- inode->u.ext3_i.i_dir_acl = 0;
- inode->u.ext3_i.i_dtime = 0;
- INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+ ei->i_file_acl = 0;
+ ei->i_dir_acl = 0;
+ ei->i_dtime = 0;
#ifdef EXT3_PREALLOCATE
- inode->u.ext3_i.i_prealloc_count = 0;
+ ei->i_prealloc_count = 0;
#endif
- inode->u.ext3_i.i_block_group = i;
+ ei->i_block_group = i;
- if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL)
+ if (ei->i_flags & EXT3_SYNC_FL)
inode->i_flags |= S_SYNC;
if (IS_SYNC(inode))
handle->h_sync = 1;
insert_inode_hash(inode);
inode->i_generation = event++;
- inode->u.ext3_i.i_state = EXT3_STATE_NEW;
+ ei->i_state = EXT3_STATE_NEW;
err = ext3_mark_inode_dirty(handle, inode);
if (err) goto fail;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index e0ad97fe3..4398759a1 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -196,7 +196,7 @@ void ext3_delete_inode (struct inode * inode)
* (Well, we could do this if we need to, but heck - it works)
*/
ext3_orphan_del(handle, inode);
- inode->u.ext3_i.i_dtime = CURRENT_TIME;
+ EXT3_I(inode)->i_dtime = CURRENT_TIME;
/*
* One subtle ordering requirement: if anything has gone wrong
@@ -220,13 +220,14 @@ no_delete:
void ext3_discard_prealloc (struct inode * inode)
{
#ifdef EXT3_PREALLOCATE
+ struct ext3_inode_info *ei = EXT3_I(inode);
lock_kernel();
/* Writer: ->i_prealloc* */
- if (inode->u.ext3_i.i_prealloc_count) {
- unsigned short total = inode->u.ext3_i.i_prealloc_count;
- unsigned long block = inode->u.ext3_i.i_prealloc_block;
- inode->u.ext3_i.i_prealloc_count = 0;
- inode->u.ext3_i.i_prealloc_block = 0;
+ if (ei->i_prealloc_count) {
+ unsigned short total = ei->i_prealloc_count;
+ unsigned long block = ei->i_prealloc_block;
+ ei->i_prealloc_count = 0;
+ ei->i_prealloc_block = 0;
/* Writer: end */
ext3_free_blocks (inode, block, total);
}
@@ -243,13 +244,14 @@ static int ext3_alloc_block (handle_t *handle,
unsigned long result;
#ifdef EXT3_PREALLOCATE
+ struct ext3_inode_info *ei = EXT3_I(inode);
/* Writer: ->i_prealloc* */
- if (inode->u.ext3_i.i_prealloc_count &&
- (goal == inode->u.ext3_i.i_prealloc_block ||
- goal + 1 == inode->u.ext3_i.i_prealloc_block))
+ if (ei->i_prealloc_count &&
+ (goal == ei->i_prealloc_block ||
+ goal + 1 == ei->i_prealloc_block))
{
- result = inode->u.ext3_i.i_prealloc_block++;
- inode->u.ext3_i.i_prealloc_count--;
+ result = ei->i_prealloc_block++;
+ ei->i_prealloc_count--;
/* Writer: end */
ext3_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts);
@@ -259,8 +261,8 @@ static int ext3_alloc_block (handle_t *handle,
alloc_hits, ++alloc_attempts);
if (S_ISREG(inode->i_mode))
result = ext3_new_block (inode, goal,
- &inode->u.ext3_i.i_prealloc_count,
- &inode->u.ext3_i.i_prealloc_block, err);
+ &ei->i_prealloc_count,
+ &ei->i_prealloc_block, err);
else
result = ext3_new_block (inode, goal, 0, 0, err);
/*
@@ -394,7 +396,7 @@ static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets,
*err = 0;
/* i_data is not going away, no lock needed */
- add_chain (chain, NULL, inode->u.ext3_i.i_data + *offsets);
+ add_chain (chain, NULL, EXT3_I(inode)->i_data + *offsets);
if (!p->key)
goto no_block;
while (--depth) {
@@ -437,7 +439,8 @@ no_block:
static inline unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
{
- u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.ext3_i.i_data;
+ struct ext3_inode_info *ei = EXT3_I(inode);
+ u32 *start = ind->bh ? (u32*) ind->bh->b_data : ei->i_data;
u32 *p;
/* Try to find previous block */
@@ -453,8 +456,7 @@ static inline unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
* It is going to be refered from inode itself? OK, just put it into
* the same cylinder group then.
*/
- return (inode->u.ext3_i.i_block_group *
- EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
+ return (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
le32_to_cpu(inode->i_sb->u.ext3_sb.s_es->s_first_data_block);
}
@@ -474,14 +476,15 @@ static inline unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4],
Indirect *partial, unsigned long *goal)
{
+ struct ext3_inode_info *ei = EXT3_I(inode);
/* Writer: ->i_next_alloc* */
- if (block == inode->u.ext3_i.i_next_alloc_block + 1) {
- inode->u.ext3_i.i_next_alloc_block++;
- inode->u.ext3_i.i_next_alloc_goal++;
+ if (block == ei->i_next_alloc_block + 1) {
+ ei->i_next_alloc_block++;
+ ei->i_next_alloc_goal++;
}
#ifdef SEARCH_FROM_ZERO
- inode->u.ext3_i.i_next_alloc_block = 0;
- inode->u.ext3_i.i_next_alloc_goal = 0;
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
#endif
/* Writer: end */
/* Reader: pointers, ->i_next_alloc* */
@@ -490,8 +493,8 @@ static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4],
* try the heuristic for sequential allocation,
* failing that at least try to get decent locality.
*/
- if (block == inode->u.ext3_i.i_next_alloc_block)
- *goal = inode->u.ext3_i.i_next_alloc_goal;
+ if (block == ei->i_next_alloc_block)
+ *goal = ei->i_next_alloc_goal;
if (!*goal)
*goal = ext3_find_near(inode, partial);
#ifdef SEARCH_FROM_ZERO
@@ -619,6 +622,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
{
int i;
int err = 0;
+ struct ext3_inode_info *ei = EXT3_I(inode);
/*
* If we're splicing into a [td]indirect block (as opposed to the
@@ -641,11 +645,11 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
/* That's it */
*where->p = where->key;
- inode->u.ext3_i.i_next_alloc_block = block;
- inode->u.ext3_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
+ ei->i_next_alloc_block = block;
+ ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);
#ifdef SEARCH_FROM_ZERO
- inode->u.ext3_i.i_next_alloc_block = 0;
- inode->u.ext3_i.i_next_alloc_goal = 0;
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
#endif
/* Writer: end */
@@ -729,6 +733,7 @@ static int ext3_get_block_handle(handle_t *handle, struct inode *inode,
unsigned long goal;
int left;
int depth = ext3_block_to_path(inode, iblock, offsets);
+ struct ext3_inode_info *ei = EXT3_I(inode);
loff_t new_size;
J_ASSERT(handle != NULL || create == 0);
@@ -780,7 +785,7 @@ out:
/*
* Block out ext3_truncate while we alter the tree
*/
- down_read(&inode->u.ext3_i.truncate_sem);
+ down_read(&ei->truncate_sem);
err = ext3_alloc_branch(handle, inode, left, goal,
offsets+(partial-chain), partial);
@@ -792,7 +797,7 @@ out:
if (!err)
err = ext3_splice_branch(handle, inode, iblock, chain,
partial, left);
- up_read(&inode->u.ext3_i.truncate_sem);
+ up_read(&ei->truncate_sem);
if (err == -EAGAIN)
goto changed;
if (err)
@@ -805,8 +810,8 @@ out:
* truncate is in progress. It is racy between multiple parallel
* instances of get_block, but we have the BKL.
*/
- if (new_size > inode->u.ext3_i.i_disksize)
- inode->u.ext3_i.i_disksize = new_size;
+ if (new_size > ei->i_disksize)
+ ei->i_disksize = new_size;
bh_result->b_state |= (1UL << BH_New);
goto got_it;
@@ -916,7 +921,7 @@ struct buffer_head *ext3_bread(handle_t *handle, struct inode * inode,
struct buffer_head *tmp_bh;
for (i = 1;
- inode->u.ext3_i.i_prealloc_count &&
+ EXT3_I(inode)->i_prealloc_count &&
i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
i++) {
/*
@@ -1126,8 +1131,8 @@ static int ext3_commit_write(struct file *file, struct page *page,
kunmap(page);
}
}
- if (inode->i_size > inode->u.ext3_i.i_disksize) {
- inode->u.ext3_i.i_disksize = inode->i_size;
+ if (inode->i_size > EXT3_I(inode)->i_disksize) {
+ EXT3_I(inode)->i_disksize = inode->i_size;
ret2 = ext3_mark_inode_dirty(handle, inode);
if (!ret)
ret = ret2;
@@ -1826,7 +1831,8 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
void ext3_truncate(struct inode * inode)
{
handle_t *handle;
- u32 *i_data = inode->u.ext3_i.i_data;
+ struct ext3_inode_info *ei = EXT3_I(inode);
+ u32 *i_data = ei->i_data;
int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
int offsets[4];
Indirect chain[4];
@@ -1878,13 +1884,13 @@ void ext3_truncate(struct inode * inode)
* on-disk inode. We do this via i_disksize, which is the value which
* ext3 *really* writes onto the disk inode.
*/
- inode->u.ext3_i.i_disksize = inode->i_size;
+ ei->i_disksize = inode->i_size;
/*
* From here we block out all ext3_get_block() callers who want to
* modify the block allocation tree.
*/
- down_write(&inode->u.ext3_i.truncate_sem);
+ down_write(&ei->truncate_sem);
if (n == 1) { /* direct blocks */
ext3_free_data(handle, inode, NULL, i_data+offsets[0],
@@ -1948,7 +1954,7 @@ do_indirects:
case EXT3_TIND_BLOCK:
;
}
- up_write(&inode->u.ext3_i.truncate_sem);
+ up_write(&ei->truncate_sem);
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
ext3_mark_inode_dirty(handle, inode);
@@ -2041,6 +2047,7 @@ void ext3_read_inode(struct inode * inode)
{
struct ext3_iloc iloc;
struct ext3_inode *raw_inode;
+ struct ext3_inode_info *ei = EXT3_I(inode);
struct buffer_head *bh;
int block;
@@ -2048,7 +2055,6 @@ void ext3_read_inode(struct inode * inode)
goto bad_inode;
bh = iloc.bh;
raw_inode = iloc.raw_inode;
- init_rwsem(&inode->u.ext3_i.truncate_sem);
inode->i_mode = le16_to_cpu(raw_inode->i_mode);
inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
@@ -2061,7 +2067,12 @@ void ext3_read_inode(struct inode * inode)
inode->i_atime = le32_to_cpu(raw_inode->i_atime);
inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
- inode->u.ext3_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
+
+ ei->i_state = 0;
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
+ ei->i_dir_start_lookup = 0;
+ ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
/* We now have enough fields to check if the inode was active or not.
* This is needed because nfsd might try to access dead inodes
* the test is that same one that e2fsck uses
@@ -2084,33 +2095,33 @@ void ext3_read_inode(struct inode * inode)
* size */
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
inode->i_version = ++event;
- inode->u.ext3_i.i_flags = le32_to_cpu(raw_inode->i_flags);
+ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
#ifdef EXT3_FRAGMENTS
- inode->u.ext3_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
- inode->u.ext3_i.i_frag_no = raw_inode->i_frag;
- inode->u.ext3_i.i_frag_size = raw_inode->i_fsize;
+ ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
+ ei->i_frag_no = raw_inode->i_frag;
+ ei->i_frag_size = raw_inode->i_fsize;
#endif
- inode->u.ext3_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+ ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
if (!S_ISREG(inode->i_mode)) {
- inode->u.ext3_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+ ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
} else {
inode->i_size |=
((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
}
- inode->u.ext3_i.i_disksize = inode->i_size;
+ ei->i_disksize = inode->i_size;
inode->i_generation = le32_to_cpu(raw_inode->i_generation);
#ifdef EXT3_PREALLOCATE
- inode->u.ext3_i.i_prealloc_count = 0;
+ ei->i_prealloc_count = 0;
#endif
- inode->u.ext3_i.i_block_group = iloc.block_group;
+ ei->i_block_group = iloc.block_group;
/*
* NOTE! The in-memory inode i_data array is in little-endian order
* even on big-endian machines: we do NOT byteswap the block numbers!
*/
for (block = 0; block < EXT3_N_BLOCKS; block++)
- inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
- INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+ ei->i_data[block] = iloc.raw_inode->i_block[block];
+ INIT_LIST_HEAD(&ei->i_orphan);
brelse (iloc.bh);
@@ -2135,19 +2146,19 @@ void ext3_read_inode(struct inode * inode)
init_special_inode(inode, inode->i_mode,
le32_to_cpu(iloc.raw_inode->i_block[0]));
/* inode->i_attr_flags = 0; unused */
- if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) {
+ if (ei->i_flags & EXT3_SYNC_FL) {
/* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
inode->i_flags |= S_SYNC;
}
- if (inode->u.ext3_i.i_flags & EXT3_APPEND_FL) {
+ if (ei->i_flags & EXT3_APPEND_FL) {
/* inode->i_attr_flags |= ATTR_FLAG_APPEND; unused */
inode->i_flags |= S_APPEND;
}
- if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) {
+ if (ei->i_flags & EXT3_IMMUTABLE_FL) {
/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE; unused */
inode->i_flags |= S_IMMUTABLE;
}
- if (inode->u.ext3_i.i_flags & EXT3_NOATIME_FL) {
+ if (ei->i_flags & EXT3_NOATIME_FL) {
/* inode->i_attr_flags |= ATTR_FLAG_NOATIME; unused */
inode->i_flags |= S_NOATIME;
}
@@ -2169,6 +2180,7 @@ static int ext3_do_update_inode(handle_t *handle,
struct ext3_iloc *iloc)
{
struct ext3_inode *raw_inode = iloc->raw_inode;
+ struct ext3_inode_info *ei = EXT3_I(inode);
struct buffer_head *bh = iloc->bh;
int err = 0, rc, block;
@@ -2186,7 +2198,7 @@ static int ext3_do_update_inode(handle_t *handle,
* Fix up interoperability with old kernels. Otherwise, old inodes get
* re-used with the upper 16 bits of the uid/gid intact
*/
- if(!inode->u.ext3_i.i_dtime) {
+ if(!ei->i_dtime) {
raw_inode->i_uid_high =
cpu_to_le16(high_16_bits(inode->i_uid));
raw_inode->i_gid_high =
@@ -2204,34 +2216,34 @@ static int ext3_do_update_inode(handle_t *handle,
raw_inode->i_gid_high = 0;
}
raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
- raw_inode->i_size = cpu_to_le32(inode->u.ext3_i.i_disksize);
+ raw_inode->i_size = cpu_to_le32(ei->i_disksize);
raw_inode->i_atime = cpu_to_le32(inode->i_atime);
raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
- raw_inode->i_dtime = cpu_to_le32(inode->u.ext3_i.i_dtime);
- raw_inode->i_flags = cpu_to_le32(inode->u.ext3_i.i_flags);
+ raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
+ raw_inode->i_flags = cpu_to_le32(ei->i_flags);
#ifdef EXT3_FRAGMENTS
- raw_inode->i_faddr = cpu_to_le32(inode->u.ext3_i.i_faddr);
- raw_inode->i_frag = inode->u.ext3_i.i_frag_no;
- raw_inode->i_fsize = inode->u.ext3_i.i_frag_size;
+ raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
+ raw_inode->i_frag = ei->i_frag_no;
+ raw_inode->i_fsize = ei->i_frag_size;
#else
/* If we are not tracking these fields in the in-memory inode,
* then preserve them on disk, but still initialise them to zero
* for new inodes. */
- if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {
+ if (ei->i_state & EXT3_STATE_NEW) {
raw_inode->i_faddr = 0;
raw_inode->i_frag = 0;
raw_inode->i_fsize = 0;
}
#endif
- raw_inode->i_file_acl = cpu_to_le32(inode->u.ext3_i.i_file_acl);
+ raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
if (!S_ISREG(inode->i_mode)) {
- raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext3_i.i_dir_acl);
+ raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
} else {
raw_inode->i_size_high =
- cpu_to_le32(inode->u.ext3_i.i_disksize >> 32);
- if (inode->u.ext3_i.i_disksize > 0x7fffffffULL) {
+ cpu_to_le32(ei->i_disksize >> 32);
+ if (ei->i_disksize > 0x7fffffffULL) {
struct super_block *sb = inode->i_sb;
if (!EXT3_HAS_RO_COMPAT_FEATURE(sb,
EXT3_FEATURE_RO_COMPAT_LARGE_FILE) ||
@@ -2259,13 +2271,13 @@ static int ext3_do_update_inode(handle_t *handle,
raw_inode->i_block[0] =
cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
else for (block = 0; block < EXT3_N_BLOCKS; block++)
- raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
+ raw_inode->i_block[block] = ei->i_data[block];
BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
rc = ext3_journal_dirty_metadata(handle, bh);
if (!err)
err = rc;
- EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW;
+ ei->i_state &= ~EXT3_STATE_NEW;
out_brelse:
brelse (bh);
@@ -2373,7 +2385,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
}
error = ext3_orphan_add(handle, inode);
- inode->u.ext3_i.i_disksize = attr->ia_size;
+ EXT3_I(inode)->i_disksize = attr->ia_size;
rc = ext3_mark_inode_dirty(handle, inode);
if (!error)
error = rc;
@@ -2616,9 +2628,9 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val)
*/
if (val)
- inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+ EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
else
- inode->u.ext3_i.i_flags &= ~EXT3_JOURNAL_DATA_FL;
+ EXT3_I(inode)->i_flags &= ~EXT3_JOURNAL_DATA_FL;
journal_unlock_updates(journal);
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 767bf6570..07f7fdd93 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -18,13 +18,14 @@
int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
+ struct ext3_inode_info *ei = EXT3_I(inode);
unsigned int flags;
ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
switch (cmd) {
case EXT3_IOC_GETFLAGS:
- flags = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE;
+ flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
return put_user(flags, (int *) arg);
case EXT3_IOC_SETFLAGS: {
handle_t *handle = NULL;
@@ -42,7 +43,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (get_user(flags, (int *) arg))
return -EFAULT;
- oldflags = inode->u.ext3_i.i_flags;
+ oldflags = ei->i_flags;
/* The JOURNAL_DATA flag is modifiable only by root */
jflag = flags & EXT3_JOURNAL_DATA_FL;
@@ -79,7 +80,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
flags = flags & EXT3_FL_USER_MODIFIABLE;
flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
- inode->u.ext3_i.i_flags = flags;
+ ei->i_flags = flags;
if (flags & EXT3_SYNC_FL)
inode->i_flags |= S_SYNC;
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index d7502fd79..ca49f46f9 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -124,7 +124,7 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
sb = dir->i_sb;
nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
- start = dir->u.ext3_i.i_dir_start_lookup;
+ start = EXT3_I(dir)->i_dir_start_lookup;
if (start >= nblocks)
start = 0;
block = start;
@@ -165,7 +165,7 @@ restart:
i = search_dirblock(bh, dir, dentry,
block << EXT3_BLOCK_SIZE_BITS(sb), res_dir);
if (i == 1) {
- dir->u.ext3_i.i_dir_start_lookup = block;
+ EXT3_I(dir)->i_dir_start_lookup = block;
ret = bh;
goto cleanup_and_exit;
} else {
@@ -295,9 +295,9 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
de = (struct ext3_dir_entry_2 *) bh->b_data;
de->inode = 0;
de->rec_len = le16_to_cpu(sb->s_blocksize);
- dir->u.ext3_i.i_disksize =
+ EXT3_I(dir)->i_disksize =
dir->i_size = offset + sb->s_blocksize;
- dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
ext3_mark_inode_dirty(handle, dir);
} else {
@@ -353,7 +353,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
* and/or different from the directory change time.
*/
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
ext3_mark_inode_dirty(handle, dir);
dir->i_version = ++event;
BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
@@ -521,7 +521,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_op = &ext3_dir_inode_operations;
inode->i_fop = &ext3_dir_operations;
- inode->i_size = inode->u.ext3_i.i_disksize = inode->i_sb->s_blocksize;
+ inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
inode->i_blocks = 0;
dir_block = ext3_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
@@ -557,7 +557,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
if (err)
goto out_no_entry;
dir->i_nlink++;
- dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
ext3_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
out_stop:
@@ -655,7 +655,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
int err = 0, rc;
lock_super(sb);
- if (!list_empty(&inode->u.ext3_i.i_orphan))
+ if (!list_empty(&EXT3_I(inode)->i_orphan))
goto out_unlock;
/* Orphan handling is only valid for files with data blocks
@@ -696,7 +696,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
* This is safe: on error we're going to ignore the orphan list
* anyway on the next recovery. */
if (!err)
- list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan);
+ list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);
jbd_debug(4, "orphan inode %ld will point to %d\n",
@@ -714,25 +714,25 @@ out_unlock:
int ext3_orphan_del(handle_t *handle, struct inode *inode)
{
struct list_head *prev;
+ struct ext3_inode_info *ei = EXT3_I(inode);
struct ext3_sb_info *sbi;
ino_t ino_next;
struct ext3_iloc iloc;
int err = 0;
lock_super(inode->i_sb);
- if (list_empty(&inode->u.ext3_i.i_orphan)) {
+ if (list_empty(&ei->i_orphan)) {
unlock_super(inode->i_sb);
return 0;
}
ino_next = NEXT_ORPHAN(inode);
- prev = inode->u.ext3_i.i_orphan.prev;
+ prev = ei->i_orphan.prev;
sbi = EXT3_SB(inode->i_sb);
jbd_debug(4, "remove inode %ld from orphan list\n", inode->i_ino);
- list_del(&inode->u.ext3_i.i_orphan);
- INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+ list_del_init(&ei->i_orphan);
/* If we're on an error path, we may not have a valid
* transaction handle with which to update the orphan list on
@@ -756,7 +756,7 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode)
} else {
struct ext3_iloc iloc2;
struct inode *i_prev =
- list_entry(prev, struct inode, u.ext3_i.i_orphan);
+ &list_entry(prev, struct ext3_inode_info, i_orphan)->vfs_inode;
jbd_debug(4, "orphan inode %ld will point to %ld\n",
i_prev->i_ino, ino_next);
@@ -832,7 +832,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
ext3_mark_inode_dirty(handle, inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
ext3_mark_inode_dirty(handle, dir);
end_rmdir:
@@ -878,7 +878,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
if (retval)
goto end_unlink;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
ext3_mark_inode_dirty(handle, dir);
inode->i_nlink--;
if (!inode->i_nlink)
@@ -916,7 +916,7 @@ static int ext3_symlink (struct inode * dir,
if (IS_ERR(inode))
goto out_stop;
- if (l > sizeof (inode->u.ext3_i.i_data)) {
+ if (l > sizeof (EXT3_I(inode)->i_data)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &ext3_aops;
/*
@@ -929,10 +929,10 @@ static int ext3_symlink (struct inode * dir,
goto out_no_entry;
} else {
inode->i_op = &ext3_fast_symlink_inode_operations;
- memcpy((char*)&inode->u.ext3_i.i_data,symname,l);
+ memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
inode->i_size = l-1;
}
- inode->u.ext3_i.i_disksize = inode->i_size;
+ EXT3_I(inode)->i_disksize = inode->i_size;
ext3_mark_inode_dirty(handle, inode);
err = ext3_add_nondir(handle, dentry, inode);
out_stop:
@@ -1077,7 +1077,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
new_inode->i_ctime = CURRENT_TIME;
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
- old_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(old_dir)->i_flags &= ~EXT3_INDEX_FL;
if (dir_bh) {
BUFFER_TRACE(dir_bh, "get_write_access");
ext3_journal_get_write_access(handle, dir_bh);
@@ -1089,7 +1089,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
new_inode->i_nlink--;
} else {
new_dir->i_nlink++;
- new_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(new_dir)->i_flags &= ~EXT3_INDEX_FL;
ext3_mark_inode_dirty(handle, new_dir);
}
}
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 46664b11a..013bb132a 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -376,7 +376,10 @@ static int ext3_blkdev_remove(struct ext3_sb_info *sbi)
return ret;
}
-#define orphan_list_entry(l) list_entry((l), struct inode, u.ext3_i.i_orphan)
+static inline struct inode *orphan_list_entry(struct list_head *l)
+{
+ return &list_entry(l, struct ext3_inode_info, i_orphan)->vfs_inode;
+}
static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi)
{
@@ -444,7 +447,54 @@ void ext3_put_super (struct super_block * sb)
return;
}
+static kmem_cache_t * ext3_inode_cachep;
+
+static struct inode *ext3_alloc_inode(struct super_block *sb)
+{
+ struct ext3_inode_info *ei;
+ ei = (struct ext3_inode_info *)kmem_cache_alloc(ext3_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void ext3_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct ext3_inode_info *ei = (struct ext3_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ INIT_LIST_HEAD(&ei->i_orphan);
+ init_rwsem(&ei->truncate_sem);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
+ sizeof(struct ext3_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (ext3_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(ext3_inode_cachep))
+ printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations ext3_sops = {
+ alloc_inode: ext3_alloc_inode,
+ destroy_inode: ext3_destroy_inode,
read_inode: ext3_read_inode, /* BKL held */
write_inode: ext3_write_inode, /* BKL not held. Don't need */
dirty_inode: ext3_dirty_inode, /* BKL not held. We take it */
@@ -1723,12 +1773,23 @@ static DECLARE_FSTYPE_DEV(ext3_fs_type, "ext3", ext3_read_super);
static int __init init_ext3_fs(void)
{
- return register_filesystem(&ext3_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&ext3_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_ext3_fs(void)
{
unregister_filesystem(&ext3_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c
index 87f91adbd..46f04cf69 100644
--- a/fs/ext3/symlink.c
+++ b/fs/ext3/symlink.c
@@ -23,14 +23,14 @@
static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- char *s = (char *)dentry->d_inode->u.ext3_i.i_data;
- return vfs_readlink(dentry, buffer, buflen, s);
+ struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
+ return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data);
}
static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *s = (char *)dentry->d_inode->u.ext3_i.i_data;
- return vfs_follow_link(nd, s);
+ struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
+ return vfs_follow_link(nd, (char*)ei->i_data);
}
struct inode_operations ext3_fast_symlink_inode_operations = {
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 2b474f297..29bb6bf79 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -744,8 +744,8 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
return -ENOSPC;
new_bh = fat_extend_dir(dir);
- if (!new_bh)
- return -ENOSPC;
+ if (IS_ERR(new_bh))
+ return PTR_ERR(new_bh);
fat_brelse(sb, new_bh);
do {
fat_get_entry(dir, &curr, bh, de, ino);
@@ -761,7 +761,10 @@ int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
struct msdos_dir_entry *de;
__u16 date, time;
- if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
+ bh = fat_extend_dir(dir);
+ if (IS_ERR(bh))
+ return PTR_ERR(bh);
+
/* zeroed out, so... */
fat_date_unix2dos(dir->i_mtime,&time,&date);
de = (struct msdos_dir_entry*)&bh->b_data[0];
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 9a3b45bcd..e18c537d0 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -65,8 +65,11 @@ int fat_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_r
return -EIO;
}
if (!(iblock % MSDOS_SB(inode->i_sb)->cluster_size)) {
- if (fat_add_cluster(inode) < 0)
- return -ENOSPC;
+ int error;
+
+ error = fat_add_cluster(inode);
+ if (error < 0)
+ return error;
}
MSDOS_I(inode)->mmu_private += sb->s_blocksize;
phys = fat_bmap(inode, iblock);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 524f18d05..f769ee09e 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -559,9 +559,9 @@ fat_read_super(struct super_block *sb, void *data, int silent,
struct buffer_head *bh;
struct fat_boot_sector *b;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- int logical_sector_size, fat_clusters;
+ int logical_sector_size, fat_clusters, debug, cp;
unsigned int total_sectors, rootdir_sectors;
- int debug, cp;
+ long error = -EIO;
char buf[50];
int i;
char cvf_format[21];
@@ -786,9 +786,8 @@ fat_read_super(struct super_block *sb, void *data, int silent,
return sb;
out_invalid:
- if (!silent)
- printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
- sb->s_id);
+ error = 0;
+
out_fail:
if (sbi->nls_io)
unload_nls(sbi->nls_io);
@@ -799,8 +798,8 @@ out_fail:
if (sbi->private_data)
kfree(sbi->private_data);
sbi->private_data = NULL;
-
- return NULL;
+
+ return ERR_PTR(error);
}
int fat_statfs(struct super_block *sb,struct statfs *buf)
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 2f34195b5..87b913b03 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -131,14 +131,13 @@ int fat_add_cluster(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
int count, nr, limit, last, curr, file_cluster;
- int cluster_size = MSDOS_SB(sb)->cluster_size;
- int res = -ENOSPC;
+ int cluster_bits = MSDOS_SB(sb)->cluster_bits;
lock_fat(sb);
if (MSDOS_SB(sb)->free_clusters == 0) {
unlock_fat(sb);
- return res;
+ return -ENOSPC;
}
limit = MSDOS_SB(sb)->clusters;
nr = limit; /* to keep GCC happy */
@@ -150,7 +149,7 @@ int fat_add_cluster(struct inode *inode)
if (count >= limit) {
MSDOS_SB(sb)->free_clusters = 0;
unlock_fat(sb);
- return res;
+ return -ENOSPC;
}
MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
@@ -174,13 +173,20 @@ int fat_add_cluster(struct inode *inode)
*/
last = file_cluster = 0;
if ((curr = MSDOS_I(inode)->i_start) != 0) {
+ int max_cluster = MSDOS_I(inode)->mmu_private >> cluster_bits;
+
fat_cache_lookup(inode, INT_MAX, &last, &curr);
file_cluster = last;
- while (curr && curr != -1){
+ while (curr && curr != -1) {
file_cluster++;
- if (!(curr = fat_access(sb, last = curr,-1))) {
+ if (!(curr = fat_access(sb, last = curr, -1))) {
fat_fs_panic(sb, "File without EOF");
- return res;
+ return -EIO;
+ }
+ if (file_cluster > max_cluster) {
+ fat_fs_panic(sb,"inode %lu: bad cluster counts",
+ inode->i_ino);
+ return -EIO;
}
}
}
@@ -192,14 +198,12 @@ int fat_add_cluster(struct inode *inode)
MSDOS_I(inode)->i_logstart = nr;
mark_inode_dirty(inode);
}
- if (file_cluster
- != inode->i_blocks / cluster_size / (sb->s_blocksize / 512)) {
+ if (file_cluster != (inode->i_blocks >> (cluster_bits - 9))) {
printk ("file_cluster badly computed!!! %d <> %ld\n",
- file_cluster,
- inode->i_blocks / cluster_size / (sb->s_blocksize / 512));
+ file_cluster, inode->i_blocks >> (cluster_bits - 9));
fat_cache_inval_inode(inode);
}
- inode->i_blocks += (1 << MSDOS_SB(sb)->cluster_bits) / 512;
+ inode->i_blocks += (1 << cluster_bits) >> 9;
return nr;
}
@@ -213,24 +217,23 @@ struct buffer_head *fat_extend_dir(struct inode *inode)
if (MSDOS_SB(sb)->fat_bits != 32) {
if (inode->i_ino == MSDOS_ROOT_INO)
- return res;
+ return ERR_PTR(-ENOSPC);
}
nr = fat_add_cluster(inode);
if (nr < 0)
- return res;
+ return ERR_PTR(nr);
sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size;
last_sector = sector + cluster_size;
- if (MSDOS_SB(sb)->cvf_format && MSDOS_SB(sb)->cvf_format->zero_out_cluster)
+ if (MSDOS_SB(sb)->cvf_format
+ && MSDOS_SB(sb)->cvf_format->zero_out_cluster) {
+ res = ERR_PTR(-EIO);
MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode, nr);
- else {
+ } else {
for ( ; sector < last_sector; sector++) {
-#ifdef DEBUG
- printk("zeroing sector %d\n", sector);
-#endif
if (!(bh = fat_getblk(sb, sector)))
- printk("getblk failed\n");
+ printk("FAT: fat_getblk() failed\n");
else {
memset(bh->b_data, 0, sb->s_blocksize);
fat_set_uptodate(sb, bh, 1);
@@ -241,6 +244,8 @@ struct buffer_head *fat_extend_dir(struct inode *inode)
fat_brelse(sb, bh);
}
}
+ if (res == NULL)
+ res = ERR_PTR(-EIO);
}
if (inode->i_size & (sb->s_blocksize - 1)) {
fat_fs_panic(sb, "Odd directory size");
@@ -484,12 +489,11 @@ static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
**res_de)
{
int count, cluster;
- unsigned long dir_size;
+ unsigned long dir_size = 0;
#ifdef DEBUG
printk("raw_scan_nonroot: start=%d\n",start);
#endif
- dir_size = 0;
do {
for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
if ((cluster = raw_scan_sector(sb,(start-2)*
diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c
index 408427e9b..f62612bb9 100644
--- a/fs/hpfs/anode.c
+++ b/fs/hpfs/anode.c
@@ -42,9 +42,10 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
return -1;
}
if (inode) {
- inode->i_hpfs_file_sec = btree->u.external[i].file_secno;
- inode->i_hpfs_disk_sec = btree->u.external[i].disk_secno;
- inode->i_hpfs_n_secs = btree->u.external[i].length;
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
+ hpfs_inode->i_file_sec = btree->u.external[i].file_secno;
+ hpfs_inode->i_disk_sec = btree->u.external[i].disk_secno;
+ hpfs_inode->i_n_secs = btree->u.external[i].length;
}
brelse(bh);
return a;
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
index 66067c2a5..0049e5ee4 100644
--- a/fs/hpfs/buffer.c
+++ b/fs/hpfs/buffer.c
@@ -47,38 +47,72 @@ void hpfs_unlock_iget(struct super_block *s)
void hpfs_lock_inode(struct inode *i)
{
- if (i) down(&i->i_hpfs_sem);
+ if (i) {
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
+ down(&hpfs_inode->i_sem);
+ }
}
void hpfs_unlock_inode(struct inode *i)
{
- if (i) up(&i->i_hpfs_sem);
+ if (i) {
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
+ up(&hpfs_inode->i_sem);
+ }
}
void hpfs_lock_2inodes(struct inode *i1, struct inode *i2)
{
- if (!i1) { if (i2) down(&i2->i_hpfs_sem); return; }
- if (!i2) { if (i1) down(&i1->i_hpfs_sem); return; }
+ struct hpfs_inode_info *hpfs_i1 = NULL, *hpfs_i2 = NULL;
+
+ if (!i1) {
+ if (i2) {
+ hpfs_i2 = hpfs_i(i2);
+ down(&hpfs_i2->i_sem);
+ }
+ return;
+ }
+ if (!i2) {
+ if (i1) {
+ hpfs_i1 = hpfs_i(i1);
+ down(&hpfs_i1->i_sem);
+ }
+ return;
+ }
if (i1->i_ino < i2->i_ino) {
- down(&i1->i_hpfs_sem);
- down(&i2->i_hpfs_sem);
+ down(&hpfs_i1->i_sem);
+ down(&hpfs_i2->i_sem);
} else if (i1->i_ino > i2->i_ino) {
- down(&i2->i_hpfs_sem);
- down(&i1->i_hpfs_sem);
- } else down(&i1->i_hpfs_sem);
+ down(&hpfs_i2->i_sem);
+ down(&hpfs_i1->i_sem);
+ } else down(&hpfs_i1->i_sem);
}
void hpfs_unlock_2inodes(struct inode *i1, struct inode *i2)
{
- if (!i1) { if (i2) up(&i2->i_hpfs_sem); return; }
- if (!i2) { if (i1) up(&i1->i_hpfs_sem); return; }
+ struct hpfs_inode_info *hpfs_i1 = NULL, *hpfs_i2 = NULL;
+
+ if (!i1) {
+ if (i2) {
+ hpfs_i2 = hpfs_i(i2);
+ up(&hpfs_i2->i_sem);
+ }
+ return;
+ }
+ if (!i2) {
+ if (i1) {
+ hpfs_i1 = hpfs_i(i1);
+ up(&hpfs_i1->i_sem);
+ }
+ return;
+ }
if (i1->i_ino < i2->i_ino) {
- up(&i2->i_hpfs_sem);
- up(&i1->i_hpfs_sem);
+ up(&hpfs_i2->i_sem);
+ up(&hpfs_i1->i_sem);
} else if (i1->i_ino > i2->i_ino) {
- up(&i1->i_hpfs_sem);
- up(&i2->i_hpfs_sem);
- } else up(&i1->i_hpfs_sem);
+ up(&hpfs_i1->i_sem);
+ up(&hpfs_i2->i_sem);
+ } else up(&hpfs_i1->i_sem);
}
void hpfs_lock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
@@ -87,13 +121,16 @@ void hpfs_lock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
if (!i2) { hpfs_lock_2inodes(i1, i3); return; }
if (!i3) { hpfs_lock_2inodes(i1, i2); return; }
if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
- down(&i1->i_hpfs_sem);
+ struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
+ down(&hpfs_i1->i_sem);
hpfs_lock_2inodes(i2, i3);
} else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
- down(&i2->i_hpfs_sem);
+ struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
+ down(&hpfs_i2->i_sem);
hpfs_lock_2inodes(i1, i3);
} else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
- down(&i3->i_hpfs_sem);
+ struct hpfs_inode_info *hpfs_i3 = hpfs_i(i3);
+ down(&hpfs_i3->i_sem);
hpfs_lock_2inodes(i1, i2);
} else if (i1->i_ino != i2->i_ino) hpfs_lock_2inodes(i1, i2);
else hpfs_lock_2inodes(i1, i3);
@@ -105,14 +142,17 @@ void hpfs_unlock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
if (!i2) { hpfs_unlock_2inodes(i1, i3); return; }
if (!i3) { hpfs_unlock_2inodes(i1, i2); return; }
if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
+ struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
hpfs_unlock_2inodes(i2, i3);
- up(&i1->i_hpfs_sem);
+ up(&hpfs_i1->i_sem);
} else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
+ struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
hpfs_unlock_2inodes(i1, i3);
- up(&i2->i_hpfs_sem);
+ up(&hpfs_i2->i_sem);
} else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
+ struct hpfs_inode_info *hpfs_i3 = hpfs_i(i3);
hpfs_unlock_2inodes(i1, i2);
- up(&i3->i_hpfs_sem);
+ up(&hpfs_i3->i_sem);
} else if (i1->i_ino != i2->i_ino) hpfs_unlock_2inodes(i1, i2);
else hpfs_unlock_2inodes(i1, i3);
}
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index f2a732869..e9c1706f1 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -27,11 +27,12 @@ loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
loff_t pos;
struct quad_buffer_head qbh;
struct inode *i = filp->f_dentry->d_inode;
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct super_block *s = i->i_sb;
/*printk("dir lseek\n");*/
if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
hpfs_lock_inode(i);
- pos = ((loff_t) hpfs_de_as_down_as_possible(s, i->i_hpfs_dno) << 4) + 1;
+ pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
while (pos != new_off) {
if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
else goto fail;
@@ -49,6 +50,7 @@ loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct inode *inode = filp->f_dentry->d_inode;
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
struct quad_buffer_head qbh;
struct hpfs_dirent *de;
int lc;
@@ -59,7 +61,7 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (inode->i_sb->s_hpfs_chk) {
if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
return -EFSERROR;
- if (hpfs_chk_sectors(inode->i_sb, inode->i_hpfs_dno, 4, "dir_dnode"))
+ if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode"))
return -EFSERROR;
}
if (inode->i_sb->s_hpfs_chk >= 2) {
@@ -72,9 +74,9 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
e = 1;
hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino);
}
- if (inode->i_hpfs_dno != fno->u.external[0].disk_secno) {
+ if (hpfs_inode->i_dno != fno->u.external[0].disk_secno) {
e = 1;
- hpfs_error(inode->i_sb, "corrupted inode: i_hpfs_dno == %08x, fnode -> dnode == %08x", inode->i_hpfs_dno, fno->u.external[0].disk_secno);
+ hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, fno->u.external[0].disk_secno);
}
brelse(bh);
if (e) return -EFSERROR;
@@ -115,14 +117,14 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
filp->f_pos = 11;
}
if (filp->f_pos == 11) {
- if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir, DT_DIR) < 0) {
+ if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) {
hpfs_unlock_inode(inode);
return 0;
}
filp->f_pos = 1;
}
if (filp->f_pos == 1) {
- filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, inode->i_hpfs_dno) << 4) + 1;
+ filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
hpfs_add_pos(inode, &filp->f_pos);
filp->f_version = inode->i_version;
}
@@ -180,6 +182,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
ino_t ino;
int err;
struct inode *result = NULL;
+ struct hpfs_inode_info *hpfs_result;
if ((err = hpfs_chk_name((char *)name, &len))) {
if (err == -ENAMETOOLONG) return ERR_PTR(-ENAMETOOLONG);
@@ -191,7 +194,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
* '.' and '..' will never be passed here.
*/
- de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh);
+ de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *) name, len, NULL, &qbh);
/*
* This is not really a bailout, just means file not found.
@@ -215,7 +218,8 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
goto bail1;
}
- if (!de->directory) result->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_result = hpfs_i(result);
+ if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
hpfs_unlock_iget(dir->i_sb);
hpfs_decide_conv(result, (char *)name, len);
@@ -235,14 +239,14 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
result->i_ctime = 1;
result->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
result->i_atime = local_to_gmt(dir->i_sb, de->read_date);
- result->i_hpfs_ea_size = de->ea_size;
- if (!result->i_hpfs_ea_mode && de->read_only)
+ hpfs_result->i_ea_size = de->ea_size;
+ if (!hpfs_result->i_ea_mode && de->read_only)
result->i_mode &= ~0222;
if (!de->directory) {
if (result->i_size == -1) {
result->i_size = de->file_size;
result->i_data.a_ops = &hpfs_aops;
- result->u.hpfs_i.mmu_private = result->i_size;
+ hpfs_i(result)->mmu_private = result->i_size;
/*
* i_blocks should count the fnode and any anodes.
* We count 1 for the fnode and don't bother about
diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c
index 78286ad36..2ddea3546 100644
--- a/fs/hpfs/dnode.c
+++ b/fs/hpfs/dnode.c
@@ -23,39 +23,43 @@ static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
void hpfs_add_pos(struct inode *inode, loff_t *pos)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
int i = 0;
loff_t **ppos;
- if (inode->i_hpfs_rddir_off)
- for (; inode->i_hpfs_rddir_off[i]; i++)
- if (inode->i_hpfs_rddir_off[i] == pos) return;
+
+ if (hpfs_inode->i_rddir_off)
+ for (; hpfs_inode->i_rddir_off[i]; i++)
+ if (hpfs_inode->i_rddir_off[i] == pos) return;
if (!(i&0x0f)) {
if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_KERNEL))) {
printk("HPFS: out of memory for position list\n");
return;
}
- if (inode->i_hpfs_rddir_off) {
- memcpy(ppos, inode->i_hpfs_rddir_off, i * sizeof(loff_t));
- kfree(inode->i_hpfs_rddir_off);
+ if (hpfs_inode->i_rddir_off) {
+ memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t));
+ kfree(hpfs_inode->i_rddir_off);
}
- inode->i_hpfs_rddir_off = ppos;
+ hpfs_inode->i_rddir_off = ppos;
}
- inode->i_hpfs_rddir_off[i] = pos;
- inode->i_hpfs_rddir_off[i + 1] = NULL;
+ hpfs_inode->i_rddir_off[i] = pos;
+ hpfs_inode->i_rddir_off[i + 1] = NULL;
}
void hpfs_del_pos(struct inode *inode, loff_t *pos)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
loff_t **i, **j;
- if (!inode->i_hpfs_rddir_off) goto not_f;
- for (i = inode->i_hpfs_rddir_off; *i; i++) if (*i == pos) goto fnd;
+
+ if (!hpfs_inode->i_rddir_off) goto not_f;
+ for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd;
goto not_f;
fnd:
for (j = i + 1; *j; j++) ;
*i = *(j - 1);
*(j - 1) = NULL;
- if (j - 1 == inode->i_hpfs_rddir_off) {
- kfree(inode->i_hpfs_rddir_off);
- inode->i_hpfs_rddir_off = NULL;
+ if (j - 1 == hpfs_inode->i_rddir_off) {
+ kfree(hpfs_inode->i_rddir_off);
+ hpfs_inode->i_rddir_off = NULL;
}
return;
not_f:
@@ -66,9 +70,11 @@ void hpfs_del_pos(struct inode *inode, loff_t *pos)
static void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t),
loff_t p1, loff_t p2)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
loff_t **i;
- if (!inode->i_hpfs_rddir_off) return;
- for (i = inode->i_hpfs_rddir_off; *i; i++) (*f)(*i, p1, p2);
+
+ if (!hpfs_inode->i_rddir_off) return;
+ for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2);
return;
}
@@ -339,7 +345,7 @@ int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, unsigned char *name, uns
fnode->u.external[0].disk_secno = rdno;
mark_buffer_dirty(bh);
brelse(bh);
- d->up = ad->up = i->i_hpfs_dno = rdno;
+ d->up = ad->up = hpfs_i(i)->i_dno = rdno;
d->root_dnode = ad->root_dnode = 0;
hpfs_mark_4buffers_dirty(&qbh);
hpfs_brelse4(&qbh);
@@ -363,13 +369,14 @@ int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, unsigned char *name, uns
int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen,
struct hpfs_dirent *new_de, int cdepth)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct dnode *d;
struct hpfs_dirent *de, *de_end;
struct quad_buffer_head qbh;
dnode_secno dno;
int c;
int c1, c2 = 0;
- dno = i->i_hpfs_dno;
+ dno = hpfs_inode->i_dno;
down:
if (i->i_sb->s_hpfs_chk)
if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1;
@@ -494,6 +501,7 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
static void delete_empty_dnode(struct inode *i, dnode_secno dno)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct quad_buffer_head qbh;
struct dnode *dnode;
dnode_secno down, up, ndown;
@@ -538,7 +546,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
mark_buffer_dirty(bh);
brelse(bh);
}
- i->i_hpfs_dno = down;
+ hpfs_inode->i_dno = down;
for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12);
return;
}
diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c
index 6c21acfb0..f49fe4ee5 100644
--- a/fs/hpfs/ea.c
+++ b/fs/hpfs/ea.c
@@ -355,7 +355,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail;
fnode->ea_size_l = pos;
ret:
- inode->i_hpfs_ea_size += 5 + strlen(key) + size;
+ hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size;
return;
bail:
if (fnode->ea_secno)
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index a6ea7c41b..d841654ed 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -45,12 +45,13 @@ int hpfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
secno hpfs_bmap(struct inode *inode, unsigned file_secno)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
unsigned n, disk_secno;
struct fnode *fnode;
struct buffer_head *bh;
- if (BLOCKS(inode->u.hpfs_i.mmu_private) <= file_secno) return 0;
- n = file_secno - inode->i_hpfs_file_sec;
- if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n;
+ if (BLOCKS(hpfs_i(inode)->mmu_private) <= file_secno) return 0;
+ n = file_secno - hpfs_inode->i_file_sec;
+ if (n < hpfs_inode->i_n_secs) return hpfs_inode->i_disk_sec + n;
if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh);
if (disk_secno == -1) return 0;
@@ -61,9 +62,9 @@ secno hpfs_bmap(struct inode *inode, unsigned file_secno)
void hpfs_truncate(struct inode *i)
{
if (IS_IMMUTABLE(i)) return /*-EPERM*/;
- i->i_hpfs_n_secs = 0;
+ hpfs_i(i)->i_n_secs = 0;
i->i_blocks = 1 + ((i->i_size + 511) >> 9);
- i->u.hpfs_i.mmu_private = i->i_size;
+ hpfs_i(i)->mmu_private = i->i_size;
hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
hpfs_write_inode(i);
}
@@ -77,7 +78,7 @@ int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_
return 0;
}
if (!create) return 0;
- if (iblock<<9 != inode->u.hpfs_i.mmu_private) {
+ if (iblock<<9 != hpfs_i(inode)->mmu_private) {
BUG();
return -EIO;
}
@@ -86,7 +87,7 @@ int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_
return -ENOSPC;
}
inode->i_blocks++;
- inode->u.hpfs_i.mmu_private += 512;
+ hpfs_i(inode)->mmu_private += 512;
bh_result->b_state |= 1UL << BH_New;
map_bh(bh_result, inode->i_sb, s);
return 0;
@@ -103,7 +104,7 @@ static int hpfs_readpage(struct file *file, struct page *page)
static int hpfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,hpfs_get_block,
- &page->mapping->host->u.hpfs_i.mmu_private);
+ &hpfs_i(page->mapping->host)->mmu_private);
}
static int _hpfs_bmap(struct address_space *mapping, long block)
{
@@ -126,7 +127,7 @@ ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t
if (retval > 0) {
struct inode *inode = file->f_dentry->d_inode;
inode->i_mtime = CURRENT_TIME;
- inode->i_hpfs_dirty = 1;
+ hpfs_i(inode)->i_dirty = 1;
}
return retval;
}
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index d7588317f..ce0c2b0f2 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -11,6 +11,7 @@
#include <linux/fs.h>
#include <linux/hpfs_fs.h>
+#include <linux/hpfs_fs_i.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/kernel.h>
@@ -303,6 +304,11 @@ int hpfs_rmdir(struct inode *, struct dentry *);
int hpfs_symlink_readpage(struct file *, struct page *);
int hpfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+static inline struct hpfs_inode_info *hpfs_i(struct inode *inode)
+{
+ return list_entry(inode, struct hpfs_inode_info, vfs_inode);
+}
+
/* super.c */
void hpfs_error(struct super_block *, char *, ...);
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index a4e03e28e..a45a3303b 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -59,31 +59,32 @@ void hpfs_read_inode(struct inode *i)
struct buffer_head *bh;
struct fnode *fnode;
struct super_block *sb = i->i_sb;
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
unsigned char *ea;
int ea_size;
- init_MUTEX(&i->i_hpfs_sem);
+
i->i_uid = sb->s_hpfs_uid;
i->i_gid = sb->s_hpfs_gid;
i->i_mode = sb->s_hpfs_mode;
- i->i_hpfs_conv = sb->s_hpfs_conv;
+ hpfs_inode->i_conv = sb->s_hpfs_conv;
i->i_blksize = 512;
i->i_size = -1;
i->i_blocks = -1;
- i->i_hpfs_dno = 0;
- i->i_hpfs_n_secs = 0;
- i->i_hpfs_file_sec = 0;
- i->i_hpfs_disk_sec = 0;
- i->i_hpfs_dpos = 0;
- i->i_hpfs_dsubdno = 0;
- i->i_hpfs_ea_mode = 0;
- i->i_hpfs_ea_uid = 0;
- i->i_hpfs_ea_gid = 0;
- i->i_hpfs_ea_size = 0;
+ hpfs_inode->i_dno = 0;
+ hpfs_inode->i_n_secs = 0;
+ hpfs_inode->i_file_sec = 0;
+ hpfs_inode->i_disk_sec = 0;
+ hpfs_inode->i_dpos = 0;
+ hpfs_inode->i_dsubdno = 0;
+ hpfs_inode->i_ea_mode = 0;
+ hpfs_inode->i_ea_uid = 0;
+ hpfs_inode->i_ea_gid = 0;
+ hpfs_inode->i_ea_size = 0;
i->i_version = ++event;
- i->i_hpfs_rddir_off = NULL;
- i->i_hpfs_dirty = 0;
+ hpfs_inode->i_rddir_off = NULL;
+ hpfs_inode->i_dirty = 0;
i->i_atime = 0;
i->i_mtime = 0;
@@ -112,14 +113,14 @@ void hpfs_read_inode(struct inode *i)
if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) {
if (ea_size == 2) {
i->i_uid = ea[0] + (ea[1] << 8);
- i->i_hpfs_ea_uid = 1;
+ hpfs_inode->i_ea_uid = 1;
}
kfree(ea);
}
if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) {
if (ea_size == 2) {
i->i_gid = ea[0] + (ea[1] << 8);
- i->i_hpfs_ea_gid = 1;
+ hpfs_inode->i_ea_gid = 1;
}
kfree(ea);
}
@@ -139,7 +140,7 @@ void hpfs_read_inode(struct inode *i)
umode_t mode = sb->s_hpfs_mode;
if (ea_size == 2) {
mode = ea[0] + (ea[1] << 8);
- i->i_hpfs_ea_mode = 1;
+ hpfs_inode->i_ea_mode = 1;
}
kfree(ea);
i->i_mode = mode;
@@ -165,60 +166,61 @@ void hpfs_read_inode(struct inode *i)
i->i_mode |= S_IFDIR;
i->i_op = &hpfs_dir_iops;
i->i_fop = &hpfs_dir_ops;
- i->i_hpfs_parent_dir = fnode->up;
- i->i_hpfs_dno = fnode->u.external[0].disk_secno;
+ hpfs_inode->i_parent_dir = fnode->up;
+ hpfs_inode->i_dno = fnode->u.external[0].disk_secno;
if (sb->s_hpfs_chk >= 2) {
struct buffer_head *bh0;
- if (hpfs_map_fnode(sb, i->i_hpfs_parent_dir, &bh0)) brelse(bh0);
+ if (hpfs_map_fnode(sb, hpfs_inode->i_parent_dir, &bh0)) brelse(bh0);
}
n_dnodes = 0; n_subdirs = 0;
- hpfs_count_dnodes(i->i_sb, i->i_hpfs_dno, &n_dnodes, &n_subdirs, NULL);
+ hpfs_count_dnodes(i->i_sb, hpfs_inode->i_dno, &n_dnodes, &n_subdirs, NULL);
i->i_blocks = 4 * n_dnodes;
i->i_size = 2048 * n_dnodes;
i->i_nlink = 2 + n_subdirs;
} else {
i->i_mode |= S_IFREG;
- if (!i->i_hpfs_ea_mode) i->i_mode &= ~0111;
+ if (!hpfs_inode->i_ea_mode) i->i_mode &= ~0111;
i->i_op = &hpfs_file_iops;
i->i_fop = &hpfs_file_ops;
i->i_nlink = 1;
i->i_size = fnode->file_size;
i->i_blocks = ((i->i_size + 511) >> 9) + 1;
i->i_data.a_ops = &hpfs_aops;
- i->u.hpfs_i.mmu_private = i->i_size;
+ hpfs_i(i)->mmu_private = i->i_size;
}
brelse(bh);
}
void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
if (fnode->acl_size_l || fnode->acl_size_s) {
/* Some unknown structures like ACL may be in fnode,
we'd better not overwrite them */
hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
} else if (i->i_sb->s_hpfs_eas >= 2) {
unsigned char ea[4];
- if ((i->i_uid != i->i_sb->s_hpfs_uid) || i->i_hpfs_ea_uid) {
+ if ((i->i_uid != i->i_sb->s_hpfs_uid) || hpfs_inode->i_ea_uid) {
ea[0] = i->i_uid & 0xff;
ea[1] = i->i_uid >> 8;
hpfs_set_ea(i, fnode, "UID", ea, 2);
- i->i_hpfs_ea_uid = 1;
+ hpfs_inode->i_ea_uid = 1;
}
- if ((i->i_gid != i->i_sb->s_hpfs_gid) || i->i_hpfs_ea_gid) {
+ if ((i->i_gid != i->i_sb->s_hpfs_gid) || hpfs_inode->i_ea_gid) {
ea[0] = i->i_gid & 0xff;
ea[1] = i->i_gid >> 8;
hpfs_set_ea(i, fnode, "GID", ea, 2);
- i->i_hpfs_ea_gid = 1;
+ hpfs_inode->i_ea_gid = 1;
}
if (!S_ISLNK(i->i_mode))
if ((i->i_mode != ((i->i_sb->s_hpfs_mode & ~(S_ISDIR(i->i_mode) ? 0 : 0111))
| (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))
&& i->i_mode != ((i->i_sb->s_hpfs_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333))
- | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || i->i_hpfs_ea_mode) {
+ | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) {
ea[0] = i->i_mode & 0xff;
ea[1] = i->i_mode >> 8;
hpfs_set_ea(i, fnode, "MODE", ea, 2);
- i->i_hpfs_ea_mode = 1;
+ hpfs_inode->i_ea_mode = 1;
}
if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) {
int d = kdev_t_to_nr(i->i_rdev);
@@ -233,17 +235,18 @@ void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
void hpfs_write_inode(struct inode *i)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct inode *parent;
if (!i->i_nlink) return;
if (i->i_ino == i->i_sb->s_hpfs_root) return;
- if (i->i_hpfs_rddir_off && !atomic_read(&i->i_count)) {
- if (*i->i_hpfs_rddir_off) printk("HPFS: write_inode: some position still there\n");
- kfree(i->i_hpfs_rddir_off);
- i->i_hpfs_rddir_off = NULL;
+ if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) {
+ if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n");
+ kfree(hpfs_inode->i_rddir_off);
+ hpfs_inode->i_rddir_off = NULL;
}
- i->i_hpfs_dirty = 0;
+ hpfs_inode->i_dirty = 0;
hpfs_lock_iget(i->i_sb, 1);
- parent = iget(i->i_sb, i->i_hpfs_parent_dir);
+ parent = iget(i->i_sb, hpfs_inode->i_parent_dir);
hpfs_unlock_iget(i->i_sb);
hpfs_lock_inode(parent);
hpfs_write_inode_nolock(i);
@@ -253,6 +256,7 @@ void hpfs_write_inode(struct inode *i)
void hpfs_write_inode_nolock(struct inode *i)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct buffer_head *bh;
struct fnode *fnode;
struct quad_buffer_head qbh;
@@ -276,17 +280,17 @@ void hpfs_write_inode_nolock(struct inode *i)
de->read_date = gmt_to_local(i->i_sb, i->i_atime);
de->creation_date = gmt_to_local(i->i_sb, i->i_ctime);
de->read_only = !(i->i_mode & 0222);
- de->ea_size = i->i_hpfs_ea_size;
+ de->ea_size = hpfs_inode->i_ea_size;
hpfs_mark_4buffers_dirty(&qbh);
hpfs_brelse4(&qbh);
}
if (S_ISDIR(i->i_mode)) {
- if ((de = map_dirent(i, i->i_hpfs_dno, "\001\001", 2, NULL, &qbh))) {
+ if ((de = map_dirent(i, hpfs_inode->i_dno, "\001\001", 2, NULL, &qbh))) {
de->write_date = gmt_to_local(i->i_sb, i->i_mtime);
de->read_date = gmt_to_local(i->i_sb, i->i_atime);
de->creation_date = gmt_to_local(i->i_sb, i->i_ctime);
de->read_only = !(i->i_mode & 0222);
- de->ea_size = /*i->i_hpfs_ea_size*/0;
+ de->ea_size = /*hpfs_inode->i_ea_size*/0;
de->file_size = 0;
hpfs_mark_4buffers_dirty(&qbh);
hpfs_brelse4(&qbh);
@@ -312,9 +316,10 @@ int hpfs_notify_change(struct dentry *dentry, struct iattr *attr)
void hpfs_write_if_changed(struct inode *inode)
{
- if (inode->i_hpfs_dirty) {
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
+
+ if (hpfs_inode->i_dirty)
hpfs_write_inode(inode);
- }
}
void hpfs_delete_inode(struct inode *inode)
diff --git a/fs/hpfs/name.c b/fs/hpfs/name.c
index f9fa94c7e..a50b0b004 100644
--- a/fs/hpfs/name.c
+++ b/fs/hpfs/name.c
@@ -20,8 +20,9 @@ char *text_prefix[]={
void hpfs_decide_conv(struct inode *inode, unsigned char *name, unsigned len)
{
+ struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
int i;
- if (inode->i_hpfs_conv != CONV_AUTO) return;
+ if (hpfs_inode->i_conv != CONV_AUTO) return;
for (i = 0; *text_postfix[i]; i++) {
int l = strlen(text_postfix[i]);
if (l <= len)
@@ -34,10 +35,10 @@ void hpfs_decide_conv(struct inode *inode, unsigned char *name, unsigned len)
if (!hpfs_compare_names(inode->i_sb, text_prefix[i], l, name, l, 0))
goto text;
}
- inode->i_hpfs_conv = CONV_BINARY;
+ hpfs_inode->i_conv = CONV_BINARY;
return;
text:
- inode->i_hpfs_conv = CONV_TEXT;
+ hpfs_inode->i_conv = CONV_TEXT;
return;
}
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 094767362..3c5333c37 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -25,7 +25,7 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct hpfs_dirent dee;
int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
- if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+ if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
if (!(dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1))) goto bail1;
memset(&dee, 0, sizeof dee);
dee.directory = 1;
@@ -69,9 +69,9 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
dir->i_nlink++;
hpfs_lock_iget(dir->i_sb, 1);
if ((result = iget(dir->i_sb, fno))) {
- result->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
- result->i_hpfs_ea_size = 0;
+ hpfs_i(result)->i_ea_size = 0;
if (dee.read_only) result->i_mode &= ~0222;
if (result->i_uid != current->fsuid ||
result->i_gid != current->fsgid ||
@@ -109,7 +109,7 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode)
struct hpfs_dirent dee;
int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
- if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+ if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
memset(&dee, 0, sizeof dee);
if (!(mode & 0222)) dee.read_only = 1;
dee.archive = 1;
@@ -133,15 +133,15 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode)
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
hpfs_decide_conv(result, (char *)name, len);
- result->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
- result->i_hpfs_ea_size = 0;
+ hpfs_i(result)->i_ea_size = 0;
if (dee.read_only) result->i_mode &= ~0222;
if (result->i_blocks == -1) result->i_blocks = 1;
if (result->i_size == -1) {
result->i_size = 0;
result->i_data.a_ops = &hpfs_aops;
- result->u.hpfs_i.mmu_private = 0;
+ hpfs_i(result)->mmu_private = 0;
}
if (result->i_uid != current->fsuid ||
result->i_gid != current->fsgid ||
@@ -177,7 +177,7 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
if (dir->i_sb->s_hpfs_eas < 2) return -EPERM;
- if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+ if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
memset(&dee, 0, sizeof dee);
if (!(mode & 0222)) dee.read_only = 1;
dee.archive = 1;
@@ -199,9 +199,9 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
mark_buffer_dirty(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
- result->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
- result->i_hpfs_ea_size = 0;
+ hpfs_i(result)->i_ea_size = 0;
/*if (result->i_blocks == -1) result->i_blocks = 1;
if (result->i_size == -1) result->i_size = 0;*/
result->i_uid = current->fsuid;
@@ -240,7 +240,7 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
if (dir->i_sb->s_hpfs_eas < 2) return -EPERM;
- if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+ if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
memset(&dee, 0, sizeof dee);
dee.archive = 1;
dee.hidden = name[0] == '.';
@@ -262,9 +262,9 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
brelse(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
- result->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
- result->i_hpfs_ea_size = 0;
+ hpfs_i(result)->i_ea_size = 0;
/*if (result->i_blocks == -1) result->i_blocks = 1;
if (result->i_size == -1) result->i_size = 0;*/
result->i_mode = S_IFLNK | 0777;
@@ -307,7 +307,7 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
hpfs_adjust_length((char *)name, &len);
again:
hpfs_lock_2inodes(dir, inode);
- if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) {
+ if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
hpfs_unlock_2inodes(dir, inode);
return -ENOENT;
}
@@ -368,7 +368,7 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
int r;
hpfs_adjust_length((char *)name, &len);
hpfs_lock_2inodes(dir, inode);
- if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) {
+ if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
hpfs_unlock_2inodes(dir, inode);
return -ENOENT;
}
@@ -382,7 +382,7 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
hpfs_unlock_2inodes(dir, inode);
return -ENOTDIR;
}
- hpfs_count_dnodes(dir->i_sb, inode->i_hpfs_dno, NULL, NULL, &n_items);
+ hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items);
if (n_items) {
hpfs_brelse4(&qbh);
hpfs_unlock_2inodes(dir, inode);
@@ -458,7 +458,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto end1;
}
- if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) {
+ if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) {
hpfs_error(i->i_sb, "lookup succeeded but map dirent failed");
err = -ENOENT;
goto end1;
@@ -469,7 +469,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_inode) {
int r;
if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
- if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
+ if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) {
new_inode->i_nlink = 0;
copy_de(nde, &de);
memcpy(nde->name, new_name, new_len);
@@ -497,7 +497,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
if (new_dir == old_dir)
- if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) {
+ if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) {
hpfs_unlock_creation(i->i_sb);
hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
err = -ENOENT;
@@ -513,7 +513,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
hpfs_unlock_creation(i->i_sb);
end:
- i->i_hpfs_parent_dir = new_dir->i_ino;
+ hpfs_i(i)->i_parent_dir = new_dir->i_ino;
if (S_ISDIR(i->i_mode)) {
new_dir->i_nlink++;
old_dir->i_nlink--;
@@ -526,7 +526,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
mark_buffer_dirty(bh);
brelse(bh);
}
- i->i_hpfs_conv = i->i_sb->s_hpfs_conv;
+ hpfs_i(i)->i_conv = i->i_sb->s_hpfs_conv;
hpfs_decide_conv(i, (char *)new_name, new_len);
end1:
hpfs_unlock_3inodes(old_dir, new_dir, i);
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 6d8f486be..2483e920b 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -148,10 +148,56 @@ int hpfs_statfs(struct super_block *s, struct statfs *buf)
return 0;
}
+static kmem_cache_t * hpfs_inode_cachep;
+
+static struct inode *hpfs_alloc_inode(struct super_block *sb)
+{
+ struct hpfs_inode_info *ei;
+ ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void hpfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ init_MUTEX(&ei->i_sem);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
+ sizeof(struct hpfs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (hpfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(hpfs_inode_cachep))
+ printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n");
+}
+
/* Super operations */
static struct super_operations hpfs_sops =
{
+ alloc_inode: hpfs_alloc_inode,
+ destroy_inode: hpfs_destroy_inode,
read_inode: hpfs_read_inode,
delete_inode: hpfs_delete_inode,
put_super: hpfs_put_super,
@@ -545,8 +591,8 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
s->s_root->d_inode->i_atime = local_to_gmt(s, de->read_date);
s->s_root->d_inode->i_mtime = local_to_gmt(s, de->write_date);
s->s_root->d_inode->i_ctime = local_to_gmt(s, de->creation_date);
- s->s_root->d_inode->i_hpfs_ea_size = de->ea_size;
- s->s_root->d_inode->i_hpfs_parent_dir = s->s_root->d_inode->i_ino;
+ hpfs_i(s->s_root->d_inode)->i_ea_size = de->ea_size;
+ hpfs_i(s->s_root->d_inode)->i_parent_dir = s->s_root->d_inode->i_ino;
if (s->s_root->d_inode->i_size == -1) s->s_root->d_inode->i_size = 2048;
if (s->s_root->d_inode->i_blocks == -1) s->s_root->d_inode->i_blocks = 5;
}
@@ -568,12 +614,23 @@ DECLARE_FSTYPE_DEV(hpfs_fs_type, "hpfs", hpfs_read_super);
static int __init init_hpfs_fs(void)
{
- return register_filesystem(&hpfs_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&hpfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_hpfs_fs(void)
{
unregister_filesystem(&hpfs_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/inode.c b/fs/inode.c
index 22b6d538e..c23323fba 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -75,13 +75,53 @@ struct inodes_stat_t inodes_stat;
static kmem_cache_t * inode_cachep;
-#define alloc_inode() \
- ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+ static struct address_space_operations empty_aops;
+ static struct inode_operations empty_iops;
+ static struct file_operations empty_fops;
+ struct inode *inode;
+
+ if (sb->s_op->alloc_inode)
+ inode = sb->s_op->alloc_inode(sb);
+ else
+ inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+
+ if (inode) {
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_blkbits = sb->s_blocksize_bits;
+ inode->i_flags = 0;
+ atomic_set(&inode->i_count, 1);
+ inode->i_sock = 0;
+ inode->i_op = &empty_iops;
+ inode->i_fop = &empty_fops;
+ inode->i_nlink = 1;
+ atomic_set(&inode->i_writecount, 0);
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ inode->i_generation = 0;
+ memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+ inode->i_pipe = NULL;
+ inode->i_bdev = NULL;
+ inode->i_cdev = NULL;
+ inode->i_data.a_ops = &empty_aops;
+ inode->i_data.host = inode;
+ inode->i_data.gfp_mask = GFP_HIGHUSER;
+ inode->i_mapping = &inode->i_data;
+ memset(&inode->u, 0, sizeof(inode->u));
+ }
+ return inode;
+}
+
static void destroy_inode(struct inode *inode)
{
if (inode_has_buffers(inode))
BUG();
- kmem_cache_free(inode_cachep, (inode));
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ kmem_cache_free(inode_cachep, (inode));
}
@@ -90,27 +130,30 @@ static void destroy_inode(struct inode *inode)
* once, because the fields are idempotent across use
* of the inode, so let the slab aware of that.
*/
+void inode_init_once(struct inode *inode)
+{
+ memset(inode, 0, sizeof(*inode));
+ init_waitqueue_head(&inode->i_wait);
+ INIT_LIST_HEAD(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_data.clean_pages);
+ INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+ INIT_LIST_HEAD(&inode->i_data.locked_pages);
+ INIT_LIST_HEAD(&inode->i_dentry);
+ INIT_LIST_HEAD(&inode->i_dirty_buffers);
+ INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+ INIT_LIST_HEAD(&inode->i_devices);
+ sema_init(&inode->i_sem, 1);
+ sema_init(&inode->i_zombie, 1);
+ spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
{
struct inode * inode = (struct inode *) foo;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR)
- {
- memset(inode, 0, sizeof(*inode));
- init_waitqueue_head(&inode->i_wait);
- INIT_LIST_HEAD(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_data.clean_pages);
- INIT_LIST_HEAD(&inode->i_data.dirty_pages);
- INIT_LIST_HEAD(&inode->i_data.locked_pages);
- INIT_LIST_HEAD(&inode->i_dentry);
- INIT_LIST_HEAD(&inode->i_dirty_buffers);
- INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
- INIT_LIST_HEAD(&inode->i_devices);
- sema_init(&inode->i_sem, 1);
- sema_init(&inode->i_zombie, 1);
- spin_lock_init(&inode->i_data.i_shared_lock);
- }
+ inode_init_once(inode);
}
/*
@@ -768,72 +811,28 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
return inode;
}
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
- static struct address_space_operations empty_aops;
- static struct inode_operations empty_iops;
- static struct file_operations empty_fops;
- memset(&inode->u, 0, sizeof(inode->u));
- inode->i_sock = 0;
- inode->i_op = &empty_iops;
- inode->i_fop = &empty_fops;
- inode->i_nlink = 1;
- atomic_set(&inode->i_writecount, 0);
- inode->i_size = 0;
- inode->i_blocks = 0;
- inode->i_generation = 0;
- memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
- inode->i_pipe = NULL;
- inode->i_bdev = NULL;
- inode->i_cdev = NULL;
- inode->i_data.a_ops = &empty_aops;
- inode->i_data.host = inode;
- inode->i_data.gfp_mask = GFP_HIGHUSER;
- inode->i_mapping = &inode->i_data;
-}
-
/**
- * get_empty_inode - obtain an inode
- *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
+ * new_inode - obtain an inode
+ * @sb: superblock
*
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ * Allocates a new inode for given superblock.
*/
-struct inode * get_empty_inode(void)
+struct inode *new_inode(struct super_block *sb)
{
static unsigned long last_ino;
struct inode * inode;
spin_lock_prefetch(&inode_lock);
- inode = alloc_inode();
- if (inode)
- {
+ inode = alloc_inode(sb);
+ if (inode) {
spin_lock(&inode_lock);
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
- inode->i_sb = NULL;
- inode->i_dev = NODEV;
- inode->i_blkbits = 0;
inode->i_ino = ++last_ino;
- inode->i_flags = 0;
- atomic_set(&inode->i_count, 1);
inode->i_state = 0;
spin_unlock(&inode_lock);
- clean_inode(inode);
}
return inode;
}
@@ -848,7 +847,7 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
{
struct inode * inode;
- inode = alloc_inode();
+ inode = alloc_inode(sb);
if (inode) {
struct inode * old;
@@ -859,17 +858,10 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_hash, head);
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_blkbits = sb->s_blocksize_bits;
inode->i_ino = ino;
- inode->i_flags = 0;
- atomic_set(&inode->i_count, 1);
inode->i_state = I_LOCK;
spin_unlock(&inode_lock);
- clean_inode(inode);
-
/* reiserfs specific hack right here. We don't
** want this to last, and are looking for VFS changes
** that will allow us to get rid of it.
diff --git a/fs/intermezzo/journal_ext3.c b/fs/intermezzo/journal_ext3.c
index 43a4740dd..eadd1d857 100644
--- a/fs/intermezzo/journal_ext3.c
+++ b/fs/intermezzo/journal_ext3.c
@@ -188,7 +188,7 @@ void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
void presto_e3_journal_file_data(struct inode *inode)
{
#ifdef EXT3_JOURNAL_DATA_FL
- inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+ EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
#else
#warning You must have a facility to enable journaled writes for recovery!
#endif
diff --git a/fs/intermezzo/journal_obdfs.c b/fs/intermezzo/journal_obdfs.c
index 3fdb83156..bda86f328 100644
--- a/fs/intermezzo/journal_obdfs.c
+++ b/fs/intermezzo/journal_obdfs.c
@@ -163,7 +163,7 @@ void presto_obdfs_trans_commit(struct presto_file_set *fset, void *handle)
void presto_obdfs_journal_file_data(struct inode *inode)
{
#ifdef EXT3_JOURNAL_DATA_FL
- inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+ EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
#else
#warning You must have a facility to enable journaled writes for recovery!
#endif
diff --git a/fs/intermezzo/journal_reiserfs.c b/fs/intermezzo/journal_reiserfs.c
index 578251ff9..780d9daa1 100644
--- a/fs/intermezzo/journal_reiserfs.c
+++ b/fs/intermezzo/journal_reiserfs.c
@@ -101,7 +101,7 @@ void presto_reiserfs_trans_commit(struct presto_file_set *fset, void *handle)
void presto_reiserfs_journal_file_data(struct inode *inode)
{
#ifdef EXT3_JOURNAL_DATA_FL
- inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+ EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
#else
#warning You must have a facility to enable journaled writes for recovery!
#endif
diff --git a/fs/intermezzo/kml_reint.c b/fs/intermezzo/kml_reint.c
index bd2c058cf..9eeecfc5b 100644
--- a/fs/intermezzo/kml_reint.c
+++ b/fs/intermezzo/kml_reint.c
@@ -17,7 +17,6 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_kml.h>
#include <linux/intermezzo_psdev.h>
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 29e96b885..ee8f2248c 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -224,14 +224,13 @@ write_out_data_locked:
}
} while (jh != last_jh);
- if (bufs || current->need_resched) {
+ if (bufs || need_resched()) {
jbd_debug(2, "submit %d writes\n", bufs);
spin_unlock(&journal_datalist_lock);
unlock_journal(journal);
if (bufs)
ll_rw_block(WRITE, bufs, wbuf);
- if (current->need_resched)
- schedule();
+ cond_resched();
journal_brelse_array(wbuf, bufs);
lock_journal(journal);
spin_lock(&journal_datalist_lock);
@@ -458,8 +457,7 @@ start_journal_io:
bh->b_end_io = journal_end_buffer_io_sync;
submit_bh(WRITE, bh);
}
- if (current->need_resched)
- schedule();
+ cond_resched();
lock_journal(journal);
/* Force a new descriptor to be generated next
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 6cd846e46..be5f8be03 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -127,8 +127,7 @@ static int jffs2_garbage_collect_thread(void *_c)
schedule();
}
- if (current->need_resched)
- schedule();
+ cond_resched();
/* Put_super will send a SIGKILL and then wait on the sem.
*/
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 115c7a20f..2dc9b5f38 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -131,8 +131,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
jffs2_erase_block(c, jeb);
/* Be nice */
- if (current->need_resched)
- schedule();
+ cond_resched();
spin_lock_bh(&c->erase_completion_lock);
}
spin_unlock_bh(&c->erase_completion_lock);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 6d93dd5d6..55206f024 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -101,8 +101,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u3
if (ret)
return ret;
- if (current->need_resched)
- schedule();
+ cond_resched();
if (signal_pending(current))
return -EINTR;
diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
index 38b2e0d6c..4dc34bf6e 100644
--- a/fs/msdos/msdosfs_syms.c
+++ b/fs/msdos/msdosfs_syms.c
@@ -23,7 +23,6 @@ EXPORT_SYMBOL(msdos_mkdir);
EXPORT_SYMBOL(msdos_rename);
EXPORT_SYMBOL(msdos_rmdir);
EXPORT_SYMBOL(msdos_unlink);
-EXPORT_SYMBOL(msdos_read_super);
EXPORT_SYMBOL(msdos_put_super);
static DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super);
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 92ece6210..e431184b7 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -589,7 +589,15 @@ struct super_block *msdos_read_super(struct super_block *sb,void *data, int sile
MSDOS_SB(sb)->options.isvfat = 0;
res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
- if (res)
- sb->s_root->d_op = &msdos_dentry_operations;
+ if (IS_ERR(res))
+ return NULL;
+ if (res == NULL) {
+ if (!silent)
+ printk(KERN_INFO "VFS: Can't find a valid"
+ " MSDOS filesystem on dev %s.\n", sb->s_id);
+ return NULL;
+ }
+
+ sb->s_root->d_op = &msdos_dentry_operations;
return res;
}
diff --git a/fs/namei.c b/fs/namei.c
index 3d9b2dbec..a629546c6 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -339,7 +339,7 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
goto loop;
if (current->total_link_count >= 40)
goto loop;
- if (current->need_resched) {
+ if (need_resched()) {
current->state = TASK_RUNNING;
schedule();
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 64f549723..dc50e798c 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -45,6 +45,8 @@ static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct
void nfs_zap_caches(struct inode *);
static void nfs_invalidate_inode(struct inode *);
+static struct inode *nfs_alloc_inode(struct super_block *sb);
+static void nfs_destroy_inode(struct inode *);
static void nfs_read_inode(struct inode *);
static void nfs_write_inode(struct inode *,int);
static void nfs_delete_inode(struct inode *);
@@ -55,6 +57,8 @@ static int nfs_statfs(struct super_block *, struct statfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *);
static struct super_operations nfs_sops = {
+ alloc_inode: nfs_alloc_inode,
+ destroy_inode: nfs_destroy_inode,
read_inode: nfs_read_inode,
write_inode: nfs_write_inode,
delete_inode: nfs_delete_inode,
@@ -94,26 +98,11 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
/*
* The "read_inode" function doesn't actually do anything:
- * the real data is filled in later in nfs_fhget. Here we
- * just mark the cache times invalid, and zero out i_mode
- * (the latter makes "nfs_refresh_inode" do the right thing
- * wrt pipe inodes)
+ * the real data is filled in later in nfs_fhget.
*/
static void
nfs_read_inode(struct inode * inode)
{
- inode->i_blksize = inode->i_sb->s_blocksize;
- inode->i_mode = 0;
- inode->i_rdev = NODEV;
- /* We can't support UPDATE_ATIME(), since the server will reset it */
- inode->i_flags |= S_NOATIME;
- INIT_LIST_HEAD(&inode->u.nfs_i.read);
- INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
- INIT_LIST_HEAD(&inode->u.nfs_i.commit);
- INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
- NFS_CACHEINV(inode);
- NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
- NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
static void
@@ -623,39 +612,6 @@ nfs_invalidate_inode(struct inode *inode)
nfs_zap_caches(inode);
}
-/*
- * Fill in inode information from the fattr.
- */
-static void
-nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
-{
- /*
- * Check whether the mode has been set, as we only want to
- * do this once. (We don't allow inodes to change types.)
- */
- if (inode->i_mode == 0) {
- NFS_FILEID(inode) = fattr->fileid;
- NFS_FSID(inode) = fattr->fsid;
- inode->i_mode = fattr->mode;
- /* Why so? Because we want revalidate for devices/FIFOs, and
- * that's precisely what we have in nfs_file_inode_operations.
- */
- inode->i_op = &nfs_file_inode_operations;
- if (S_ISREG(inode->i_mode)) {
- inode->i_fop = &nfs_file_operations;
- inode->i_data.a_ops = &nfs_file_aops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &nfs_dir_inode_operations;
- inode->i_fop = &nfs_dir_operations;
- } else if (S_ISLNK(inode->i_mode))
- inode->i_op = &nfs_symlink_inode_operations;
- else
- init_special_inode(inode, inode->i_mode, fattr->rdev);
- memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
- }
- nfs_refresh_inode(inode, fattr);
-}
-
struct nfs_find_desc {
struct nfs_fh *fh;
struct nfs_fattr *fattr;
@@ -678,7 +634,7 @@ nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
return 0;
if (NFS_FILEID(inode) != fattr->fileid)
return 0;
- if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
+ if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0)
return 0;
/* Force an attribute cache update if inode->i_count == 0 */
if (!atomic_read(&inode->i_count))
@@ -700,7 +656,7 @@ nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fat
return 1;
/* Has the filehandle changed? If so is the old one stale? */
- if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
+ if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0 &&
__nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
return 1;
@@ -749,7 +705,65 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
goto out_no_inode;
- nfs_fill_inode(inode, fh, fattr);
+ if (NFS_NEW(inode)) {
+ __u64 new_size, new_mtime;
+ loff_t new_isize;
+ time_t new_atime;
+
+ /* We can't support UPDATE_ATIME(), since the server will reset it */
+ NFS_FLAGS(inode) &= ~NFS_INO_NEW;
+ NFS_FILEID(inode) = fattr->fileid;
+ NFS_FSID(inode) = fattr->fsid;
+ memcpy(NFS_FH(inode), fh, sizeof(struct nfs_fh));
+ inode->i_flags |= S_NOATIME;
+ inode->i_mode = fattr->mode;
+ /* Why so? Because we want revalidate for devices/FIFOs, and
+ * that's precisely what we have in nfs_file_inode_operations.
+ */
+ inode->i_op = &nfs_file_inode_operations;
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_fop = &nfs_file_operations;
+ inode->i_data.a_ops = &nfs_file_aops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &nfs_dir_inode_operations;
+ inode->i_fop = &nfs_dir_operations;
+ } else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &nfs_symlink_inode_operations;
+ else
+ init_special_inode(inode, inode->i_mode, fattr->rdev);
+
+ new_mtime = fattr->mtime;
+ new_size = fattr->size;
+ new_isize = nfs_size_to_loff_t(fattr->size);
+ new_atime = nfs_time_to_secs(fattr->atime);
+
+ NFS_READTIME(inode) = jiffies;
+ NFS_CACHE_CTIME(inode) = fattr->ctime;
+ inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+ inode->i_atime = new_atime;
+ NFS_CACHE_MTIME(inode) = new_mtime;
+ inode->i_mtime = nfs_time_to_secs(new_mtime);
+ NFS_CACHE_ISIZE(inode) = new_size;
+ inode->i_size = new_isize;
+ inode->i_mode = fattr->mode;
+ inode->i_nlink = fattr->nlink;
+ inode->i_uid = fattr->uid;
+ inode->i_gid = fattr->gid;
+ if (fattr->valid & NFS_ATTR_FATTR_V3) {
+ /*
+ * report the blocks in 512byte units
+ */
+ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+ inode->i_blksize = inode->i_sb->s_blocksize;
+ } else {
+ inode->i_blocks = fattr->du.nfs2.blocks;
+ inode->i_blksize = fattr->du.nfs2.blocksize;
+ }
+ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+ memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+ } else
+ nfs_refresh_inode(inode, fattr);
dprintk("NFS: __nfs_fhget(%s/%Ld ct=%d)\n",
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
@@ -1152,6 +1166,64 @@ extern int nfs_destroy_readpagecache(void);
extern int nfs_init_writepagecache(void);
extern int nfs_destroy_writepagecache(void);
+static kmem_cache_t * nfs_inode_cachep;
+
+static struct inode *nfs_alloc_inode(struct super_block *sb)
+{
+ struct nfs_inode *nfsi;
+ nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL);
+ if (!nfsi)
+ return NULL;
+ nfsi->flags = NFS_INO_NEW;
+ /* do we need the next 4 lines? */
+ nfsi->hash_next = NULL;
+ nfsi->hash_prev = NULL;
+ nfsi->nextscan = 0;
+ nfsi->mm_cred = NULL;
+ return &nfsi->vfs_inode;
+}
+
+static void nfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct nfs_inode *nfsi = (struct nfs_inode *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ inode_init_once(&nfsi->vfs_inode);
+ INIT_LIST_HEAD(&nfsi->read);
+ INIT_LIST_HEAD(&nfsi->dirty);
+ INIT_LIST_HEAD(&nfsi->commit);
+ INIT_LIST_HEAD(&nfsi->writeback);
+ nfsi->nread = 0;
+ nfsi->ndirty = 0;
+ nfsi->ncommit = 0;
+ nfsi->npages = 0;
+ }
+}
+
+int nfs_init_inodecache(void)
+{
+ nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
+ sizeof(struct nfs_inode),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (nfs_inode_cachep == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void nfs_destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(nfs_inode_cachep))
+ printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
+}
+
/*
* Initialize NFS
*/
@@ -1161,26 +1233,45 @@ static int __init init_nfs_fs(void)
err = nfs_init_nfspagecache();
if (err)
- return err;
+ goto out4;
+
+ err = nfs_init_inodecache();
+ if (err)
+ goto out3;
err = nfs_init_readpagecache();
if (err)
- return err;
+ goto out2;
err = nfs_init_writepagecache();
if (err)
- return err;
+ goto out1;
#ifdef CONFIG_PROC_FS
rpc_proc_register(&nfs_rpcstat);
#endif
- return register_filesystem(&nfs_fs_type);
+ err = register_filesystem(&nfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ rpc_proc_unregister("nfs");
+ nfs_destroy_writepagecache();
+out1:
+ nfs_destroy_readpagecache();
+out2:
+ nfs_destroy_inodecache();
+out3:
+ nfs_destroy_nfspagecache();
+out4:
+ return err;
}
static void __exit exit_nfs_fs(void)
{
nfs_destroy_writepagecache();
nfs_destroy_readpagecache();
+ nfs_destroy_inodecache();
nfs_destroy_nfspagecache();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 936ce1dba..919b2c5b5 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -156,10 +156,11 @@ static inline void
nfs_mark_request_read(struct nfs_page *req)
{
struct inode *inode = req->wb_inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfs_wreq_lock);
- nfs_list_add_request(req, &inode->u.nfs_i.read);
- inode->u.nfs_i.nread++;
+ nfs_list_add_request(req, &nfsi->read);
+ nfsi->nread++;
__nfs_add_lru(&NFS_SERVER(inode)->lru_read, req);
spin_unlock(&nfs_wreq_lock);
}
@@ -167,6 +168,7 @@ nfs_mark_request_read(struct nfs_page *req)
static int
nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_page *new;
new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
@@ -174,7 +176,7 @@ nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
return PTR_ERR(new);
nfs_mark_request_read(new);
- if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+ if (nfsi->nread >= NFS_SERVER(inode)->rpages ||
page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
nfs_pagein_inode(inode, 0, 0);
return 0;
@@ -318,13 +320,13 @@ nfs_pagein_list(struct list_head *head, int rpages)
int
nfs_scan_lru_read_timeout(struct nfs_server *server, struct list_head *dst)
{
- struct inode *inode;
+ struct nfs_inode *nfsi;
int npages;
npages = nfs_scan_lru_timeout(&server->lru_read, dst, server->rpages);
if (npages) {
- inode = nfs_list_entry(dst->next)->wb_inode;
- inode->u.nfs_i.nread -= npages;
+ nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+ nfsi->nread -= npages;
}
return npages;
}
@@ -341,13 +343,13 @@ nfs_scan_lru_read_timeout(struct nfs_server *server, struct list_head *dst)
int
nfs_scan_lru_read(struct nfs_server *server, struct list_head *dst)
{
- struct inode *inode;
+ struct nfs_inode *nfsi;
int npages;
npages = nfs_scan_lru(&server->lru_read, dst, server->rpages);
if (npages) {
- inode = nfs_list_entry(dst->next)->wb_inode;
- inode->u.nfs_i.nread -= npages;
+ nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+ nfsi->nread -= npages;
}
return npages;
}
@@ -365,10 +367,11 @@ nfs_scan_lru_read(struct nfs_server *server, struct list_head *dst)
static int
nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
int res;
- res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages);
- inode->u.nfs_i.nread -= res;
- if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read))
+ res = nfs_scan_list(&nfsi->read, dst, NULL, idx_start, npages);
+ nfsi->nread -= res;
+ if ((nfsi->nread == 0) != list_empty(&nfsi->read))
printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
return res;
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 096ea12f8..b3774c964 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -315,14 +315,15 @@ region_locked(struct inode *inode, struct nfs_page *req)
static inline void
nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
if (!list_empty(&req->wb_hash))
return;
if (!NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
- if (list_empty(&inode->u.nfs_i.writeback))
+ if (list_empty(&nfsi->writeback))
igrab(inode);
- inode->u.nfs_i.npages++;
- list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
+ nfsi->npages++;
+ list_add(&req->wb_hash, &nfsi->writeback);
req->wb_count++;
}
@@ -332,6 +333,7 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
static inline void
nfs_inode_remove_request(struct nfs_page *req)
{
+ struct nfs_inode *nfsi;
struct inode *inode;
spin_lock(&nfs_wreq_lock);
if (list_empty(&req->wb_hash)) {
@@ -343,10 +345,11 @@ nfs_inode_remove_request(struct nfs_page *req)
inode = req->wb_inode;
list_del(&req->wb_hash);
INIT_LIST_HEAD(&req->wb_hash);
- inode->u.nfs_i.npages--;
- if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
+ nfsi = NFS_I(inode);
+ nfsi->npages--;
+ if ((nfsi->npages == 0) != list_empty(&nfsi->writeback))
printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
- if (list_empty(&inode->u.nfs_i.writeback)) {
+ if (list_empty(&nfsi->writeback)) {
spin_unlock(&nfs_wreq_lock);
iput(inode);
} else
@@ -360,9 +363,10 @@ nfs_inode_remove_request(struct nfs_page *req)
static inline struct nfs_page *
_nfs_find_request(struct inode *inode, struct page *page)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
struct list_head *head, *next;
- head = &inode->u.nfs_i.writeback;
+ head = &nfsi->writeback;
next = head->next;
while (next != head) {
struct nfs_page *req = nfs_inode_wb_entry(next);
@@ -393,10 +397,11 @@ static inline void
nfs_mark_request_dirty(struct nfs_page *req)
{
struct inode *inode = req->wb_inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfs_wreq_lock);
- nfs_list_add_request(req, &inode->u.nfs_i.dirty);
- inode->u.nfs_i.ndirty++;
+ nfs_list_add_request(req, &nfsi->dirty);
+ nfsi->ndirty++;
__nfs_del_lru(req);
__nfs_add_lru(&NFS_SERVER(inode)->lru_dirty, req);
spin_unlock(&nfs_wreq_lock);
@@ -409,8 +414,8 @@ nfs_mark_request_dirty(struct nfs_page *req)
static inline int
nfs_dirty_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_inode;
- return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
+ struct nfs_inode *nfsi = NFS_I(req->wb_inode);
+ return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
}
#ifdef CONFIG_NFS_V3
@@ -421,10 +426,11 @@ static inline void
nfs_mark_request_commit(struct nfs_page *req)
{
struct inode *inode = req->wb_inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&nfs_wreq_lock);
- nfs_list_add_request(req, &inode->u.nfs_i.commit);
- inode->u.nfs_i.ncommit++;
+ nfs_list_add_request(req, &nfsi->commit);
+ nfsi->ncommit++;
__nfs_del_lru(req);
__nfs_add_lru(&NFS_SERVER(inode)->lru_commit, req);
spin_unlock(&nfs_wreq_lock);
@@ -440,6 +446,7 @@ nfs_mark_request_commit(struct nfs_page *req)
static int
nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
struct list_head *p, *head;
unsigned long idx_end;
unsigned int res = 0;
@@ -451,7 +458,7 @@ nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_s
idx_end = idx_start + npages - 1;
spin_lock(&nfs_wreq_lock);
- head = &inode->u.nfs_i.writeback;
+ head = &nfsi->writeback;
p = head->next;
while (p != head) {
unsigned long pg_idx;
@@ -494,13 +501,13 @@ nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_s
int
nfs_scan_lru_dirty_timeout(struct nfs_server *server, struct list_head *dst)
{
- struct inode *inode;
+ struct nfs_inode *nfsi;
int npages;
npages = nfs_scan_lru_timeout(&server->lru_dirty, dst, server->wpages);
if (npages) {
- inode = nfs_list_entry(dst->next)->wb_inode;
- inode->u.nfs_i.ndirty -= npages;
+ nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+ nfsi->ndirty -= npages;
}
return npages;
}
@@ -517,13 +524,13 @@ nfs_scan_lru_dirty_timeout(struct nfs_server *server, struct list_head *dst)
int
nfs_scan_lru_dirty(struct nfs_server *server, struct list_head *dst)
{
- struct inode *inode;
+ struct nfs_inode *nfsi;
int npages;
npages = nfs_scan_lru(&server->lru_dirty, dst, server->wpages);
if (npages) {
- inode = nfs_list_entry(dst->next)->wb_inode;
- inode->u.nfs_i.ndirty -= npages;
+ nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+ nfsi->ndirty -= npages;
}
return npages;
}
@@ -542,10 +549,11 @@ nfs_scan_lru_dirty(struct nfs_server *server, struct list_head *dst)
static int
nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
int res;
- res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages);
- inode->u.nfs_i.ndirty -= res;
- if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))
+ res = nfs_scan_list(&nfsi->dirty, dst, file, idx_start, npages);
+ nfsi->ndirty -= res;
+ if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))
printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
return res;
}
@@ -565,14 +573,14 @@ nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, un
int
nfs_scan_lru_commit_timeout(struct nfs_server *server, struct list_head *dst)
{
- struct inode *inode;
+ struct nfs_inode *nfsi;
int npages;
npages = nfs_scan_lru_timeout(&server->lru_commit, dst, 1);
if (npages) {
- inode = nfs_list_entry(dst->next)->wb_inode;
- npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0);
- inode->u.nfs_i.ncommit -= npages;
+ nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+ npages += nfs_scan_list(&nfsi->commit, dst, NULL, 0, 0);
+ nfsi->ncommit -= npages;
}
return npages;
}
@@ -592,14 +600,14 @@ nfs_scan_lru_commit_timeout(struct nfs_server *server, struct list_head *dst)
int
nfs_scan_lru_commit(struct nfs_server *server, struct list_head *dst)
{
- struct inode *inode;
+ struct nfs_inode *nfsi;
int npages;
npages = nfs_scan_lru(&server->lru_commit, dst, 1);
if (npages) {
- inode = nfs_list_entry(dst->next)->wb_inode;
- npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0);
- inode->u.nfs_i.ncommit -= npages;
+ nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+ npages += nfs_scan_list(&nfsi->commit, dst, NULL, 0, 0);
+ nfsi->ncommit -= npages;
}
return npages;
}
@@ -618,10 +626,11 @@ nfs_scan_lru_commit(struct nfs_server *server, struct list_head *dst)
static int
nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
int res;
- res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages);
- inode->u.nfs_i.ncommit -= res;
- if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))
+ res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages);
+ nfsi->ncommit -= res;
+ if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
return res;
}
@@ -738,7 +747,7 @@ nfs_strategy(struct inode *inode)
{
unsigned int dirty, wpages;
- dirty = inode->u.nfs_i.ndirty;
+ dirty = NFS_I(inode)->ndirty;
wpages = NFS_SERVER(inode)->wpages;
#ifdef CONFIG_NFS_V3
if (NFS_PROTO(inode)->version == 2) {
@@ -889,6 +898,7 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
static int
nfs_flush_one(struct list_head *head, struct inode *inode, int how)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_write_data *data;
struct rpc_task *task;
@@ -913,7 +923,7 @@ nfs_flush_one(struct list_head *head, struct inode *inode, int how)
if (nfsvers < 3)
data->args.stable = NFS_FILE_SYNC;
else if (stable) {
- if (!inode->u.nfs_i.ncommit)
+ if (!nfsi->ncommit)
data->args.stable = NFS_FILE_SYNC;
else
data->args.stable = NFS_DATA_SYNC;
diff --git a/fs/pipe.c b/fs/pipe.c
index 3b0926a92..5910c1682 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -608,16 +608,18 @@ static struct super_operations pipefs_ops = {
static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
{
- struct inode *root = new_inode(sb);
+ struct inode *root;
+
+ sb->s_blocksize = 1024;
+ sb->s_blocksize_bits = 10;
+ sb->s_magic = PIPEFS_MAGIC;
+ sb->s_op = &pipefs_ops;
+ root = new_inode(sb);
if (!root)
return NULL;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
- sb->s_blocksize = 1024;
- sb->s_blocksize_bits = 10;
- sb->s_magic = PIPEFS_MAGIC;
- sb->s_op = &pipefs_ops;
sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });
if (!sb->s_root) {
iput(root);
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
index f544a436c..b06d5c1d9 100644
--- a/fs/qnx4/bitmap.c
+++ b/fs/qnx4/bitmap.c
@@ -142,13 +142,13 @@ int qnx4_set_bitmap(struct super_block *sb, long block, int busy)
static void qnx4_clear_inode(struct inode *inode)
{
- struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
-
- memset(qnx4_ino->i_reserved, 0, sizeof qnx4_ino->i_reserved);
- qnx4_ino->i_size = 0;
- qnx4_ino->i_num_xtnts = 0;
- qnx4_ino->i_mode = 0;
- qnx4_ino->i_status = 0;
+ struct qnx4_inode_entry *qnx4_ino = qnx4_raw_inode(inode);
+ /* What for? */
+ memset(qnx4_ino->di_fname, 0, sizeof qnx4_ino->di_fname);
+ qnx4_ino->di_size = 0;
+ qnx4_ino->di_num_xtnts = 0;
+ qnx4_ino->di_mode = 0;
+ qnx4_ino->di_status = 0;
}
void qnx4_free_inode(struct inode *inode)
diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c
index 7d17225f0..f3d2301f1 100644
--- a/fs/qnx4/fsync.c
+++ b/fs/qnx4/fsync.c
@@ -90,7 +90,7 @@ static int sync_direct(struct inode *inode, int wait)
for (i = 0; i < 7; i++) {
rc = sync_block(inode,
- (unsigned short *) inode->u.qnx4_i.i_first_xtnt.xtnt_blk + i, wait);
+ (unsigned short *) qnx4_raw_inode(inode)->di_first_xtnt.xtnt_blk + i, wait);
if (rc > 0)
break;
if (rc)
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index b74d341c2..972fa8ed9 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -121,12 +121,16 @@ static void qnx4_write_inode(struct inode *inode, int unused)
static struct super_block *qnx4_read_super(struct super_block *, void *, int);
static void qnx4_put_super(struct super_block *sb);
+static struct inode *qnx4_alloc_inode(struct super_block *sb);
+static void qnx4_destroy_inode(struct inode *inode);
static void qnx4_read_inode(struct inode *);
static int qnx4_remount(struct super_block *sb, int *flags, char *data);
static int qnx4_statfs(struct super_block *, struct statfs *);
static struct super_operations qnx4_sops =
{
+ alloc_inode: qnx4_alloc_inode,
+ destroy_inode: qnx4_destroy_inode,
read_inode: qnx4_read_inode,
#ifdef CONFIG_QNX4FS_RW
write_inode: qnx4_write_inode,
@@ -227,16 +231,16 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
unsigned long block = 0;
struct buffer_head *bh = 0;
struct qnx4_xblk *xblk = 0;
- struct qnx4_inode_info *qnx4_inode = &inode->u.qnx4_i;
- qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->i_num_xtnts);
+ struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
+ qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
- if ( iblock < le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size) ) {
+ if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
// iblock is in the first extent. This is easy.
- block = le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_blk) + iblock - 1;
+ block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1;
} else {
// iblock is beyond first extent. We have to follow the extent chain.
- i_xblk = le32_to_cpu(qnx4_inode->i_xblk);
- offset = iblock - le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size);
+ i_xblk = le32_to_cpu(qnx4_inode->di_xblk);
+ offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size);
ix = 0;
while ( --nxtnt > 0 ) {
if ( ix == 0 ) {
@@ -417,10 +421,12 @@ static int qnx4_readpage(struct file *file, struct page *page)
{
return block_read_full_page(page,qnx4_get_block);
}
-static int qnx4_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+static int qnx4_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
{
- return cont_prepare_write(page,from,to,qnx4_get_block,
- &page->mapping->host->u.qnx4_i.mmu_private);
+ struct qnx4_inode_info *qnx4_inode = qnx4_i(page->mapping->host);
+ return cont_prepare_write(page, from, to, qnx4_get_block,
+ &qnx4_inode->mmu_private);
}
static int qnx4_bmap(struct address_space *mapping, long block)
{
@@ -441,6 +447,7 @@ static void qnx4_read_inode(struct inode *inode)
struct qnx4_inode_entry *raw_inode;
int block, ino;
struct super_block *sb = inode->i_sb;
+ struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
ino = inode->i_ino;
inode->i_mode = 0;
@@ -472,35 +479,92 @@ static void qnx4_read_inode(struct inode *inode)
inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);
inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
- memcpy(&inode->u.qnx4_i, (struct qnx4_inode_info *) raw_inode, QNX4_DIR_ENTRY_SIZE);
+ memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &qnx4_file_inode_operations;
inode->i_fop = &qnx4_file_operations;
inode->i_mapping->a_ops = &qnx4_aops;
- inode->u.qnx4_i.mmu_private = inode->i_size;
+ qnx4_i(inode)->mmu_private = inode->i_size;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &qnx4_dir_inode_operations;
inode->i_fop = &qnx4_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &qnx4_aops;
- inode->u.qnx4_i.mmu_private = inode->i_size;
+ qnx4_i(inode)->mmu_private = inode->i_size;
} else
printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id);
brelse(bh);
}
+static kmem_cache_t *qnx4_inode_cachep;
+
+static struct inode *qnx4_alloc_inode(struct super_block *sb)
+{
+ struct qnx4_inode_info *ei;
+ ei = kmem_cache_alloc(qnx4_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void qnx4_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode));
+}
+
+static void init_once(void *foo, kmem_cache_t * cachep,
+ unsigned long flags)
+{
+ struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache",
+ sizeof(struct qnx4_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (qnx4_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(qnx4_inode_cachep))
+ printk(KERN_INFO
+ "qnx4_inode_cache: not all structures were freed\n");
+}
+
static DECLARE_FSTYPE_DEV(qnx4_fs_type, "qnx4", qnx4_read_super);
static int __init init_qnx4_fs(void)
{
+ int err;
+
+ err = init_inodecache();
+ if (err)
+ return err;
+
+ err = register_filesystem(&qnx4_fs_type);
+ if (err) {
+ destroy_inodecache();
+ return err;
+ }
+
printk("QNX4 filesystem 0.2.2 registered.\n");
- return register_filesystem(&qnx4_fs_type);
+ return 0;
}
static void __exit exit_qnx4_fs(void)
{
unregister_filesystem(&qnx4_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 688d5c8e6..f9748aac8 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -101,9 +101,9 @@ inline void make_le_item_head (struct item_head * ih, const struct cpu_key * key
}
static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
- struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+ struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ;
- buffer_insert_inode_queue(bh, jinode) ;
+ buffer_insert_list(bh, list) ;
}
//
@@ -808,8 +808,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
/* inserting indirect pointers for a hole can take a
** long time. reschedule if needed
*/
- if (current->need_resched)
- schedule() ;
+ cond_resched();
retval = search_for_position_by_key (inode->i_sb, &key, &path);
if (retval == IO_ERROR) {
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 98d6b2dc3..1c9dc427c 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1897,7 +1897,7 @@ int journal_init(struct super_block *p_s_sb) {
memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
- INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+ INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap,
SB_BMAP_NR(p_s_sb)) ;
allocate_bitmap_nodes(p_s_sb) ;
@@ -2902,7 +2902,7 @@ printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ;
SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
/* write any buffers that must hit disk before this commit is done */
- fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+ fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
/* honor the flush and async wishes from the caller */
if (flush) {
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 31c1bdd0e..8f82baf1f 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -271,7 +271,7 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
unlock_super (sb);
return (unsigned)-1;
}
- if (fragment < inode->u.ufs_i.i_lastfrag) {
+ if (fragment < UFS_I(inode)->i_lastfrag) {
UFSD(("EXIT (ALREADY ALLOCATED)\n"))
unlock_super (sb);
return 0;
@@ -310,7 +310,7 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
*p = cpu_to_fs32(sb, result);
*err = 0;
inode->i_blocks += count << uspi->s_nspfshift;
- inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count);
+ UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
NULLIFY_FRAGMENTS
}
unlock_super(sb);
@@ -325,7 +325,7 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
if (result) {
*err = 0;
inode->i_blocks += count << uspi->s_nspfshift;
- inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count);
+ UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
NULLIFY_FRAGMENTS
unlock_super(sb);
UFSD(("EXIT, result %u\n", result))
@@ -378,7 +378,7 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
*p = cpu_to_fs32(sb, result);
*err = 0;
inode->i_blocks += count << uspi->s_nspfshift;
- inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count);
+ UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
NULLIFY_FRAGMENTS
unlock_super(sb);
if (newcount < request)
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 25f22378b..d1eea1f58 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -142,7 +142,7 @@ void ufs_free_inode (struct inode * inode)
* For other inodes, search forward from the parent directory's block
* group to find a free inode.
*/
-struct inode * ufs_new_inode (const struct inode * dir, int mode)
+struct inode * ufs_new_inode(struct inode * dir, int mode)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
@@ -151,6 +151,7 @@ struct inode * ufs_new_inode (const struct inode * dir, int mode)
struct ufs_cylinder_group * ucg;
struct inode * inode;
unsigned cg, bit, i, j, start;
+ struct ufs_inode_info *ufsi;
UFSD(("ENTER\n"))
@@ -161,6 +162,7 @@ struct inode * ufs_new_inode (const struct inode * dir, int mode)
inode = new_inode(sb);
if (!inode)
return ERR_PTR(-ENOMEM);
+ ufsi = UFS_I(inode);
uspi = sb->u.ufs_sb.s_uspi;
usb1 = ubh_get_usb_first(USPI_UBH);
@@ -261,8 +263,13 @@ cg_found:
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags;
- inode->u.ufs_i.i_lastfrag = 0;
+ ufsi->i_flags = UFS_I(dir)->i_flags;
+ ufsi->i_lastfrag = 0;
+ ufsi->i_gen = 0;
+ ufsi->i_shadow = 0;
+ ufsi->i_osync = 0;
+ ufsi->i_oeftflag = 0;
+ memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1));
insert_inode_hash(inode);
mark_inode_dirty(inode);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index d2d009aee..cc08c9feb 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -84,6 +84,7 @@ static int ufs_block_to_path(struct inode *inode, long i_block, int offsets[4])
int ufs_frag_map(struct inode *inode, int frag)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block *sb = inode->i_sb;
struct ufs_sb_private_info *uspi = sb->u.ufs_sb.s_uspi;
int mask = uspi->s_apbmask>>uspi->s_fpbshift;
@@ -99,7 +100,7 @@ int ufs_frag_map(struct inode *inode, int frag)
p = offsets;
lock_kernel();
- block = inode->u.ufs_i.i_u1.i_data[*p++];
+ block = ufsi->i_u1.i_data[*p++];
if (!block)
goto out;
while (--depth) {
@@ -124,6 +125,7 @@ static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
unsigned int fragment, unsigned int new_fragment,
unsigned int required, int *err, int metadata, long *phys, int *new)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * result;
@@ -138,12 +140,12 @@ static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
uspi = sb->u.ufs_sb.s_uspi;
block = ufs_fragstoblks (fragment);
blockoff = ufs_fragnum (fragment);
- p = inode->u.ufs_i.i_u1.i_data + block;
+ p = ufsi->i_u1.i_data + block;
goal = 0;
repeat:
tmp = fs32_to_cpu(sb, *p);
- lastfrag = inode->u.ufs_i.i_lastfrag;
+ lastfrag = ufsi->i_lastfrag;
if (tmp && fragment < lastfrag) {
if (metadata) {
result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
@@ -169,19 +171,19 @@ repeat:
* We must reallocate last allocated block
*/
if (lastblockoff) {
- p2 = inode->u.ufs_i.i_u1.i_data + lastblock;
+ p2 = ufsi->i_u1.i_data + lastblock;
tmp = ufs_new_fragments (inode, p2, lastfrag,
fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err);
if (!tmp) {
- if (lastfrag != inode->u.ufs_i.i_lastfrag)
+ if (lastfrag != ufsi->i_lastfrag)
goto repeat;
else
return NULL;
}
- lastfrag = inode->u.ufs_i.i_lastfrag;
+ lastfrag = ufsi->i_lastfrag;
}
- goal = fs32_to_cpu(sb, inode->u.ufs_i.i_u1.i_data[lastblock]) + uspi->s_fpb;
+ goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, fragment - blockoff,
goal, required + blockoff, err);
}
@@ -196,14 +198,14 @@ repeat:
* We will allocate new block before last allocated block
*/
else /* (lastblock > block) */ {
- if (lastblock && (tmp = fs32_to_cpu(sb, inode->u.ufs_i.i_u1.i_data[lastblock-1])))
+ if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1])))
goal = tmp + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, fragment - blockoff,
goal, uspi->s_fpb, err);
}
if (!tmp) {
if ((!blockoff && *p) ||
- (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+ (blockoff && lastfrag != ufsi->i_lastfrag))
goto repeat;
*err = -ENOSPC;
return NULL;
@@ -470,6 +472,7 @@ struct address_space_operations ufs_aops = {
void ufs_read_inode (struct inode * inode)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_inode * ufs_inode;
@@ -517,24 +520,23 @@ void ufs_read_inode (struct inode * inode)
inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks);
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat) */
inode->i_version = ++event;
-
- inode->u.ufs_i.i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
- inode->u.ufs_i.i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
- inode->u.ufs_i.i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
- inode->u.ufs_i.i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
- inode->u.ufs_i.i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+ ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
+ ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
+ ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
+ ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
+ ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
;
else if (inode->i_blocks) {
for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
- inode->u.ufs_i.i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
+ ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
}
else {
for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
- inode->u.ufs_i.i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
+ ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
}
-
+ ufsi->i_osync = 0;
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ufs_file_inode_operations;
@@ -566,6 +568,7 @@ bad_inode:
static int ufs_update_inode(struct inode * inode, int do_sync)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * bh;
@@ -606,23 +609,23 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime);
ufs_inode->ui_mtime.tv_usec = 0;
ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks);
- ufs_inode->ui_flags = cpu_to_fs32(sb, inode->u.ufs_i.i_flags);
- ufs_inode->ui_gen = cpu_to_fs32(sb, inode->u.ufs_i.i_gen);
+ ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags);
+ ufs_inode->ui_gen = cpu_to_fs32(sb, ufsi->i_gen);
if ((flags & UFS_UID_MASK) == UFS_UID_EFT) {
- ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, inode->u.ufs_i.i_shadow);
- ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, inode->u.ufs_i.i_oeftflag);
+ ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow);
+ ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag);
}
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
else if (inode->i_blocks) {
for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
- ufs_inode->ui_u2.ui_addr.ui_db[i] = inode->u.ufs_i.i_u1.i_data[i];
+ ufs_inode->ui_u2.ui_addr.ui_db[i] = ufsi->i_u1.i_data[i];
}
else {
for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
- ufs_inode->ui_u2.ui_symlink[i] = inode->u.ufs_i.i_u1.i_symlink[i];
+ ufs_inode->ui_u2.ui_symlink[i] = ufsi->i_u1.i_symlink[i];
}
if (!inode->i_nlink)
@@ -653,7 +656,7 @@ int ufs_sync_inode (struct inode *inode)
void ufs_delete_inode (struct inode * inode)
{
- /*inode->u.ufs_i.i_dtime = CURRENT_TIME;*/
+ /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/
lock_kernel();
mark_inode_dirty(inode);
ufs_update_inode(inode, IS_SYNC(inode));
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index b6b1833c4..0a95f62f7 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -138,7 +138,7 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
} else {
/* fast symlink */
inode->i_op = &ufs_fast_symlink_inode_operations;
- memcpy((char*)&inode->u.ufs_i.i_u1.i_data,symname,l);
+ memcpy((char*)&UFS_I(inode)->i_u1.i_data,symname,l);
inode->i_size = l-1;
}
mark_inode_dirty(inode);
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 8d1260c60..8d57fb9d6 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -953,7 +953,51 @@ int ufs_statfs (struct super_block * sb, struct statfs * buf)
return 0;
}
+static kmem_cache_t * ufs_inode_cachep;
+
+static struct inode *ufs_alloc_inode(struct super_block *sb)
+{
+ struct ufs_inode_info *ei;
+ ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void ufs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(ufs_inode_cachep, UFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct ufs_inode_info *ei = (struct ufs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
+ sizeof(struct ufs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (ufs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(ufs_inode_cachep))
+ printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations ufs_super_ops = {
+ alloc_inode: ufs_alloc_inode,
+ destroy_inode: ufs_destroy_inode,
read_inode: ufs_read_inode,
write_inode: ufs_write_inode,
delete_inode: ufs_delete_inode,
@@ -967,15 +1011,27 @@ static DECLARE_FSTYPE_DEV(ufs_fs_type, "ufs", ufs_read_super);
static int __init init_ufs_fs(void)
{
- return register_filesystem(&ufs_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&ufs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_ufs_fs(void)
{
unregister_filesystem(&ufs_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
module_init(init_ufs_fs)
module_exit(exit_ufs_fs)
+MODULE_LICENSE("GPL");
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
index 59a44e22e..2602f506d 100644
--- a/fs/ufs/symlink.c
+++ b/fs/ufs/symlink.c
@@ -26,17 +26,18 @@
*/
#include <linux/fs.h>
+#include <linux/ufs_fs.h>
static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink;
- return vfs_readlink(dentry, buffer, buflen, s);
+ struct ufs_inode_info *p = UFS_I(dentry->d_inode);
+ return vfs_readlink(dentry, buffer, buflen, (char*)p->i_u1.i_symlink);
}
static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink;
- return vfs_follow_link(nd, s);
+ struct ufs_inode_info *p = UFS_I(dentry->d_inode);
+ return vfs_follow_link(nd, (char*)p->i_u1.i_symlink);
}
struct inode_operations ufs_fast_symlink_inode_operations = {
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 6fd8df562..448466b31 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -67,6 +67,7 @@
static int ufs_trunc_direct (struct inode * inode)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * bh;
@@ -86,7 +87,7 @@ static int ufs_trunc_direct (struct inode * inode)
retry = 0;
frag1 = DIRECT_FRAGMENT;
- frag4 = min_t(u32, UFS_NDIR_FRAGMENT, inode->u.ufs_i.i_lastfrag);
+ frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
frag3 = frag4 & ~uspi->s_fpbmask;
block1 = block2 = 0;
@@ -107,7 +108,7 @@ static int ufs_trunc_direct (struct inode * inode)
/*
* Free first free fragments
*/
- p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag1);
+ p = ufsi->i_u1.i_data + ufs_fragstoblks (frag1);
tmp = fs32_to_cpu(sb, *p);
if (!tmp )
ufs_panic (sb, "ufs_trunc_direct", "internal error");
@@ -132,7 +133,7 @@ next1:
* Free whole blocks
*/
for (i = block1 ; i < block2; i++) {
- p = inode->u.ufs_i.i_u1.i_data + i;
+ p = ufsi->i_u1.i_data + i;
tmp = fs32_to_cpu(sb, *p);
if (!tmp)
continue;
@@ -170,7 +171,7 @@ next2:;
/*
* Free last free fragments
*/
- p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag3);
+ p = ufsi->i_u1.i_data + ufs_fragstoblks (frag3);
tmp = fs32_to_cpu(sb, *p);
if (!tmp )
ufs_panic(sb, "ufs_truncate_direct", "internal error");
@@ -360,6 +361,7 @@ static int ufs_trunc_dindirect (struct inode * inode, unsigned offset, u32 * p)
static int ufs_trunc_tindirect (struct inode * inode)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_buffer_head * tind_bh;
@@ -375,7 +377,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0;
- p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
+ p = ufsi->i_u1.i_data + UFS_TIND_BLOCK;
if (!(tmp = fs32_to_cpu(sb, *p)))
return 0;
tind_bh = ubh_bread (sb, tmp, uspi->s_bsize);
@@ -422,6 +424,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
void ufs_truncate (struct inode * inode)
{
+ struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * bh;
@@ -439,9 +442,9 @@ void ufs_truncate (struct inode * inode)
while (1) {
retry = ufs_trunc_direct(inode);
retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK,
- (u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]);
+ (u32 *) &ufsi->i_u1.i_data[UFS_IND_BLOCK]);
retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb,
- (u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]);
+ (u32 *) &ufsi->i_u1.i_data[UFS_DIND_BLOCK]);
retry |= ufs_trunc_tindirect (inode);
if (!retry)
break;
@@ -460,7 +463,7 @@ void ufs_truncate (struct inode * inode)
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->u.ufs_i.i_lastfrag = DIRECT_FRAGMENT;
+ ufsi->i_lastfrag = DIRECT_FRAGMENT;
mark_inode_dirty(inode);
UFSD(("EXIT\n"))
}
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 2d94ed553..3f4a19155 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -9,6 +9,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/locks.h>
+#include <linux/ufs_fs.h>
#include "swab.h"
#include "util.h"
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index b2a140ce0..8d797bb6d 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -204,7 +204,7 @@ filp->f_dentry->d_name.name, entry.name);
if (!inode)
goto remove_name;
#ifdef UMSDOS_DEBUG_VERBOSE
-if (inode->u.umsdos_i.i_is_hlink)
+if (UMSDOS_I(inode)->i_is_hlink)
printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
#endif
@@ -214,7 +214,7 @@ dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
entry.flags));
/* check whether to resolve a hard-link */
if ((entry.flags & UMSDOS_HLINK) &&
- !inode->u.umsdos_i.i_is_hlink) {
+ !UMSDOS_I(inode)->i_is_hlink) {
dret = umsdos_solve_hlink (dret);
ret = PTR_ERR(dret);
if (IS_ERR(dret))
@@ -361,9 +361,9 @@ void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
/*
* This part of the initialization depends only on i_patched.
*/
- if (inode->u.umsdos_i.i_patched)
+ if (UMSDOS_I(inode)->i_patched)
goto out;
- inode->u.umsdos_i.i_patched = 1;
+ UMSDOS_I(inode)->i_patched = 1;
if (S_ISREG (entry->mode))
entry->mtime = inode->i_mtime;
inode->i_mode = entry->mode;
@@ -498,7 +498,7 @@ dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
/* Check for a hard link */
if ((info.entry.flags & UMSDOS_HLINK) &&
- !inode->u.umsdos_i.i_is_hlink) {
+ !UMSDOS_I(inode)->i_is_hlink) {
dret = umsdos_solve_hlink (dret);
ret = PTR_ERR(dret);
if (IS_ERR(dret))
@@ -756,7 +756,7 @@ dir->d_parent->d_name.name, dir->d_name.name, start, real);
if (!IS_ERR(dentry_dst)) {
struct inode *inode = dentry_dst->d_inode;
if (inode) {
- inode->u.umsdos_i.i_is_hlink = 1;
+ UMSDOS_I(inode)->i_is_hlink = 1;
#ifdef UMSDOS_DEBUG_VERBOSE
printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index cbe1b4ee4..befdd474f 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -34,7 +34,7 @@ void UMSDOS_put_inode (struct inode *inode)
PRINTK ((KERN_DEBUG
"put inode %p (%lu) pos %lu count=%d\n"
,inode, inode->i_ino
- ,inode->u.umsdos_i.pos
+ ,UMSDOS_I(inode)->pos
,atomic_read(&inode->i_count)));
if (inode == pseudo_root) {
@@ -42,7 +42,7 @@ void UMSDOS_put_inode (struct inode *inode)
}
if (atomic_read(&inode->i_count) == 1)
- inode->u.umsdos_i.i_patched = 0;
+ UMSDOS_I(inode)->i_patched = 0;
}
@@ -67,15 +67,16 @@ void UMSDOS_put_super (struct super_block *sb)
void umsdos_setup_dir(struct dentry *dir)
{
struct inode *inode = dir->d_inode;
+ struct umsdos_inode_info *ui = UMSDOS_I(inode);
if (!S_ISDIR(inode->i_mode))
printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
dir->d_parent->d_name.name, dir->d_name.name);
- init_waitqueue_head (&inode->u.umsdos_i.dir_info.p);
- inode->u.umsdos_i.dir_info.looking = 0;
- inode->u.umsdos_i.dir_info.creating = 0;
- inode->u.umsdos_i.dir_info.pid = 0;
+ init_waitqueue_head (&ui->dir_info.p);
+ ui->dir_info.looking = 0;
+ ui->dir_info.creating = 0;
+ ui->dir_info.pid = 0;
inode->i_op = &umsdos_rdir_inode_operations;
inode->i_fop = &umsdos_rdir_operations;
@@ -96,7 +97,7 @@ void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
struct inode *inode = dentry->d_inode;
struct dentry *demd;
- inode->u.umsdos_i.pos = f_pos;
+ UMSDOS_I(inode)->pos = f_pos;
/* now check the EMD file */
demd = umsdos_get_emd_dentry(dentry->d_parent);
@@ -233,7 +234,7 @@ int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
int offs;
Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
+dentry->d_parent->d_name.name, dentry->d_name.name, UMSDOS_I(inode)->i_patched));
if (inode->i_nlink == 0)
goto out;
@@ -265,9 +266,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched)
/* Read only the start of the entry since we don't touch the name */
mapping = demd->d_inode->i_mapping;
- offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;
+ offs = UMSDOS_I(inode)->pos & ~PAGE_CACHE_MASK;
ret = -ENOMEM;
- page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);
+ page=grab_cache_page(mapping,UMSDOS_I(inode)->pos>>PAGE_CACHE_SHIFT);
if (!page)
goto out_dput;
ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
@@ -363,10 +364,17 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
* Call msdos-fs to mount the disk.
* Note: this returns res == sb or NULL
*/
- res = msdos_read_super (sb, data, silent);
-
- if (!res)
- goto out_fail;
+ MSDOS_SB(sb)->options.isvfat = 0;
+ res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations);
+
+ if (IS_ERR(res))
+ return NULL;
+ if (res == NULL) {
+ if (!silent)
+ printk(KERN_INFO "VFS: Can't find a valid "
+ "UMSDOS filesystem on dev %s.\n", sb->s_id);
+ return NULL;
+ }
printk (KERN_INFO "UMSDOS 0.86k "
"(compatibility level %d.%d, fast msdos)\n",
@@ -394,10 +402,6 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
dget (sb->s_root); sb->s_root = dget(new_root);
}
return sb;
-
-out_fail:
- printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
- return NULL;
}
/*
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 9049610da..1e40fd8e9 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -28,12 +28,12 @@
static inline void u_sleep_on (struct inode *dir)
{
- sleep_on (&dir->u.umsdos_i.dir_info.p);
+ sleep_on (&UMSDOS_I(dir)->dir_info.p);
}
static inline void u_wake_up (struct inode *dir)
{
- wake_up (&dir->u.umsdos_i.dir_info.p);
+ wake_up (&UMSDOS_I(dir)->dir_info.p);
}
/*
@@ -47,9 +47,9 @@ static int umsdos_waitcreate (struct inode *dir)
{
int ret = 0;
- if (dir->u.umsdos_i.dir_info.creating
- && dir->u.umsdos_i.dir_info.pid != current->pid) {
- PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.dir_info.pid, current->pid));
+ if (UMSDOS_I(dir)->dir_info.creating
+ && UMSDOS_I(dir)->dir_info.pid != current->pid) {
+ PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", UMSDOS_I(dir)->dir_info.pid, current->pid));
u_sleep_on (dir);
ret = 1;
}
@@ -61,7 +61,7 @@ static int umsdos_waitcreate (struct inode *dir)
*/
static void umsdos_waitlookup (struct inode *dir)
{
- while (dir->u.umsdos_i.dir_info.looking) {
+ while (UMSDOS_I(dir)->dir_info.looking) {
u_sleep_on (dir);
}
}
@@ -104,8 +104,8 @@ void umsdos_lockcreate (struct inode *dir)
* if we (the process) own the lock
*/
while (umsdos_waitcreate (dir) != 0);
- dir->u.umsdos_i.dir_info.creating++;
- dir->u.umsdos_i.dir_info.pid = current->pid;
+ UMSDOS_I(dir)->dir_info.creating++;
+ UMSDOS_I(dir)->dir_info.pid = current->pid;
umsdos_waitlookup (dir);
}
@@ -124,10 +124,10 @@ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
if (umsdos_waitcreate (dir1) == 0
&& umsdos_waitcreate (dir2) == 0) {
/* We own both now */
- dir1->u.umsdos_i.dir_info.creating++;
- dir1->u.umsdos_i.dir_info.pid = current->pid;
- dir2->u.umsdos_i.dir_info.creating++;
- dir2->u.umsdos_i.dir_info.pid = current->pid;
+ UMSDOS_I(dir1)->dir_info.creating++;
+ UMSDOS_I(dir1)->dir_info.pid = current->pid;
+ UMSDOS_I(dir2)->dir_info.creating++;
+ UMSDOS_I(dir2)->dir_info.pid = current->pid;
break;
}
}
@@ -141,7 +141,7 @@ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
void umsdos_startlookup (struct inode *dir)
{
while (umsdos_waitcreate (dir) != 0);
- dir->u.umsdos_i.dir_info.looking++;
+ UMSDOS_I(dir)->dir_info.looking++;
}
/*
@@ -149,10 +149,10 @@ void umsdos_startlookup (struct inode *dir)
*/
void umsdos_unlockcreate (struct inode *dir)
{
- dir->u.umsdos_i.dir_info.creating--;
- if (dir->u.umsdos_i.dir_info.creating < 0) {
- printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
- ,dir->u.umsdos_i.dir_info.creating);
+ UMSDOS_I(dir)->dir_info.creating--;
+ if (UMSDOS_I(dir)->dir_info.creating < 0) {
+ printk ("UMSDOS: UMSDOS_I(dir)->dir_info.creating < 0: %d"
+ ,UMSDOS_I(dir)->dir_info.creating);
}
u_wake_up (dir);
}
@@ -162,10 +162,10 @@ void umsdos_unlockcreate (struct inode *dir)
*/
void umsdos_endlookup (struct inode *dir)
{
- dir->u.umsdos_i.dir_info.looking--;
- if (dir->u.umsdos_i.dir_info.looking < 0) {
- printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
- ,dir->u.umsdos_i.dir_info.looking);
+ UMSDOS_I(dir)->dir_info.looking--;
+ if (UMSDOS_I(dir)->dir_info.looking < 0) {
+ printk ("UMSDOS: UMSDOS_I(dir)->dir_info.looking < 0: %d"
+ ,UMSDOS_I(dir)->dir_info.looking);
}
u_wake_up (dir);
}
@@ -618,7 +618,7 @@ temp->d_parent->d_name.name, temp->d_name.name, ret);
goto cleanup;
}
/* mark the inode as a hardlink */
- oldinode->u.umsdos_i.i_is_hlink = 1;
+ UMSDOS_I(oldinode)->i_is_hlink = 1;
/*
* Capture the path to the hidden link.
@@ -667,7 +667,7 @@ olddentry->d_parent->d_name.name, olddentry->d_name.name));
* the dentry for its real name, not the visible name.
* N.B. make sure it's the hidden inode ...
*/
- if (!oldinode->u.umsdos_i.i_is_hlink)
+ if (!UMSDOS_I(oldinode)->i_is_hlink)
printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
olddentry->d_parent->d_name.name,
olddentry->d_name.name, oldinode->i_ino);
@@ -721,7 +721,7 @@ out_unlock:
#ifdef UMSDOS_PARANOIA
-if (!oldinode->u.umsdos_i.i_is_hlink)
+if (!UMSDOS_I(oldinode)->i_is_hlink)
printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
#endif
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index 9fbca3941..372454a2e 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -113,7 +113,7 @@ Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name));
/* only patch if needed (because we get called even for lookup
(not only rlookup) stuff sometimes, like in umsdos_covered() */
- if (dentry->d_inode->u.umsdos_i.i_patched == 0)
+ if (UMSDOS_I(dentry->d_inode)->i_patched == 0)
umsdos_patch_dentry_inode(dentry, 0);
}
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 656b58f1b..2e1d0f3aa 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -1266,10 +1266,15 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
struct super_block *res;
MSDOS_SB(sb)->options.isvfat = 1;
-
res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
- if (res == NULL)
+ if (IS_ERR(res))
+ return NULL;
+ if (res == NULL) {
+ if (!silent)
+ printk(KERN_INFO "VFS: Can't find a valid"
+ " VFAT filesystem on dev %s.\n", sb->s_id);
return NULL;
+ }
if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
MSDOS_SB(sb)->options.dotsOK = 0;
diff --git a/include/asm-arm/arch-arc/system.h b/include/asm-arm/arch-arc/system.h
index fce24985d..5886cbeb8 100644
--- a/include/asm-arm/arch-arc/system.h
+++ b/include/asm-arm/arch-arc/system.h
@@ -10,7 +10,7 @@
static void arch_idle(void)
{
- while (!current->need_resched && !hlt_counter);
+ while (!need_resched() && !hlt_counter);
}
static inline void arch_reset(char mode)
diff --git a/include/asm-arm/arch-cl7500/system.h b/include/asm-arm/arch-cl7500/system.h
index 2bdd19913..6cb002194 100644
--- a/include/asm-arm/arch-cl7500/system.h
+++ b/include/asm-arm/arch-cl7500/system.h
@@ -10,7 +10,7 @@
static void arch_idle(void)
{
- while (!current->need_resched && !hlt_counter)
+ while (!need_resched() && !hlt_counter)
iomd_writeb(0, IOMD_SUSMODE);
}
diff --git a/include/asm-arm/arch-ebsa110/system.h b/include/asm-arm/arch-ebsa110/system.h
index c4af29bef..e33951995 100644
--- a/include/asm-arm/arch-ebsa110/system.h
+++ b/include/asm-arm/arch-ebsa110/system.h
@@ -17,7 +17,7 @@
* will stop our MCLK signal (which provides the clock for the glue
* logic, and therefore the timer interrupt).
*
- * Instead, we spin, waiting for either hlt_counter or need_resched
+ * Instead, we spin, waiting for either hlt_counter or need_resched()
* to be set. If we have been spinning for 2cs, then we drop the
* core clock down to the memory clock.
*/
@@ -28,13 +28,13 @@ static void arch_idle(void)
start_idle = jiffies;
do {
- if (current->need_resched || hlt_counter)
+ if (need_resched() || hlt_counter)
goto slow_out;
} while (time_before(jiffies, start_idle + HZ/50));
cpu_do_idle(IDLE_CLOCK_SLOW);
- while (!current->need_resched && !hlt_counter) {
+ while (!need_resched() && !hlt_counter) {
/* do nothing slowly */
}
diff --git a/include/asm-arm/arch-ebsa285/system.h b/include/asm-arm/arch-ebsa285/system.h
index e9b4da1e9..9559db044 100644
--- a/include/asm-arm/arch-ebsa285/system.h
+++ b/include/asm-arm/arch-ebsa285/system.h
@@ -20,14 +20,14 @@ static void arch_idle(void)
start_idle = jiffies;
do {
- if (current->need_resched || hlt_counter)
+ if (need_resched() || hlt_counter)
goto slow_out;
cpu_do_idle(IDLE_WAIT_FAST);
} while (time_before(jiffies, start_idle + HZ/50));
cpu_do_idle(IDLE_CLOCK_SLOW);
- while (!current->need_resched && !hlt_counter) {
+ while (!need_resched() && !hlt_counter) {
cpu_do_idle(IDLE_WAIT_SLOW);
}
diff --git a/include/asm-arm/arch-nexuspci/system.h b/include/asm-arm/arch-nexuspci/system.h
index 028788bdc..c52578070 100644
--- a/include/asm-arm/arch-nexuspci/system.h
+++ b/include/asm-arm/arch-nexuspci/system.h
@@ -16,7 +16,7 @@
static void arch_idle(void)
{
- while (!current->need_resched && !hlt_counter)
+ while (!need_resched() && !hlt_counter)
cpu_do_idle(IDLE_WAIT_SLOW);
}
diff --git a/include/asm-arm/arch-rpc/system.h b/include/asm-arm/arch-rpc/system.h
index 6e070b907..7c781a6d1 100644
--- a/include/asm-arm/arch-rpc/system.h
+++ b/include/asm-arm/arch-rpc/system.h
@@ -18,14 +18,14 @@ static void arch_idle(void)
start_idle = jiffies;
do {
- if (current->need_resched || hlt_counter)
+ if (need_resched() || hlt_counter)
goto slow_out;
cpu_do_idle(IDLE_WAIT_FAST);
} while (time_before(jiffies, start_idle + HZ/50));
cpu_do_idle(IDLE_CLOCK_SLOW);
- while (!current->need_resched && !hlt_counter) {
+ while (!need_resched() && !hlt_counter) {
cpu_do_idle(IDLE_WAIT_SLOW);
}
diff --git a/include/asm-arm/arch-sa1100/system.h b/include/asm-arm/arch-sa1100/system.h
index d020a4926..6dbf2a45b 100644
--- a/include/asm-arm/arch-sa1100/system.h
+++ b/include/asm-arm/arch-sa1100/system.h
@@ -10,7 +10,7 @@ static inline void arch_idle(void)
if (!hlt_counter) {
int flags;
local_irq_save(flags);
- if (!current->need_resched)
+ if (!need_resched())
cpu_do_idle(0);
local_irq_restore(flags);
}
diff --git a/include/asm-arm/arch-tbox/system.h b/include/asm-arm/arch-tbox/system.h
index e52bb50fd..cf90aafef 100644
--- a/include/asm-arm/arch-tbox/system.h
+++ b/include/asm-arm/arch-tbox/system.h
@@ -13,14 +13,14 @@ static void arch_idle(void)
start_idle = jiffies;
do {
- if (current->need_resched || hlt_counter)
+ if (need_resched() || hlt_counter)
goto slow_out;
cpu_do_idle(IDLE_WAIT_FAST);
} while (time_before(jiffies, start_idle + HZ/50));
cpu_do_idle(IDLE_CLOCK_SLOW);
- while (!current->need_resched && !hlt_counter) {
+ while (!need_resched() && !hlt_counter) {
cpu_do_idle(IDLE_WAIT_SLOW);
}
diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h
index 86b07d546..4d9856538 100644
--- a/include/asm-cris/bitops.h
+++ b/include/asm-cris/bitops.h
@@ -22,6 +22,7 @@
/* We use generic_ffs so get it; include guards resolve the possible
mutually inclusion. */
#include <linux/bitops.h>
+#include <linux/compiler.h>
/*
* Some hacks to defeat gcc over-optimizations..
@@ -43,6 +44,8 @@ struct __dummy { unsigned long a[100]; };
#define set_bit(nr, addr) (void)test_and_set_bit(nr, addr)
+#define __set_bit(nr, addr) (void)__test_and_set_bit(nr, addr)
+
/*
* clear_bit - Clears a bit in memory
* @nr: Bit to clear
@@ -56,6 +59,8 @@ struct __dummy { unsigned long a[100]; };
#define clear_bit(nr, addr) (void)test_and_clear_bit(nr, addr)
+#define __clear_bit(nr, addr) (void)__test_and_clear_bit(nr, addr)
+
/*
* change_bit - Toggle a bit in memory
* @nr: Bit to clear
@@ -89,7 +94,7 @@ struct __dummy { unsigned long a[100]; };
* It also implies a memory barrier.
*/
-static __inline__ int test_and_set_bit(int nr, void *addr)
+static inline int test_and_set_bit(int nr, void *addr)
{
unsigned int mask, retval;
unsigned long flags;
@@ -105,6 +110,18 @@ static __inline__ int test_and_set_bit(int nr, void *addr)
return retval;
}
+static inline int __test_and_set_bit(int nr, void *addr)
+{
+ unsigned int mask, retval;
+ unsigned int *adr = (unsigned int *)addr;
+
+ adr += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *adr) != 0;
+ *adr |= mask;
+ return retval;
+}
+
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
@@ -120,7 +137,7 @@ static __inline__ int test_and_set_bit(int nr, void *addr)
* It also implies a memory barrier.
*/
-static __inline__ int test_and_clear_bit(int nr, void *addr)
+static inline int test_and_clear_bit(int nr, void *addr)
{
unsigned int mask, retval;
unsigned long flags;
@@ -146,7 +163,7 @@ static __inline__ int test_and_clear_bit(int nr, void *addr)
* but actually fail. You must protect multiple accesses with a lock.
*/
-static __inline__ int __test_and_clear_bit(int nr, void *addr)
+static inline int __test_and_clear_bit(int nr, void *addr)
{
unsigned int mask, retval;
unsigned int *adr = (unsigned int *)addr;
@@ -166,7 +183,7 @@ static __inline__ int __test_and_clear_bit(int nr, void *addr)
* It also implies a memory barrier.
*/
-static __inline__ int test_and_change_bit(int nr, void *addr)
+static inline int test_and_change_bit(int nr, void *addr)
{
unsigned int mask, retval;
unsigned long flags;
@@ -183,7 +200,7 @@ static __inline__ int test_and_change_bit(int nr, void *addr)
/* WARNING: non atomic and it can be reordered! */
-static __inline__ int __test_and_change_bit(int nr, void *addr)
+static inline int __test_and_change_bit(int nr, void *addr)
{
unsigned int mask, retval;
unsigned int *adr = (unsigned int *)addr;
@@ -204,7 +221,7 @@ static __inline__ int __test_and_change_bit(int nr, void *addr)
* This routine doesn't need to be atomic.
*/
-static __inline__ int test_bit(int nr, const void *addr)
+static inline int test_bit(int nr, const void *addr)
{
unsigned int mask;
unsigned int *adr = (unsigned int *)addr;
@@ -225,7 +242,7 @@ static __inline__ int test_bit(int nr, const void *addr)
* number. They differ in that the first function also inverts all bits
* in the input.
*/
-static __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
+static inline unsigned long cris_swapnwbrlz(unsigned long w)
{
/* Let's just say we return the result in the same register as the
input. Saying we clobber the input but can return the result
@@ -241,7 +258,7 @@ static __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
return res;
}
-static __inline__ unsigned long cris_swapwbrlz(unsigned long w)
+static inline unsigned long cris_swapwbrlz(unsigned long w)
{
unsigned res;
__asm__ ("swapwbr %0 \n\t"
@@ -255,7 +272,7 @@ static __inline__ unsigned long cris_swapwbrlz(unsigned long w)
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
-static __inline__ unsigned long ffz(unsigned long w)
+static inline unsigned long ffz(unsigned long w)
{
/* The generic_ffs function is used to avoid the asm when the
argument is a constant. */
@@ -268,7 +285,7 @@ static __inline__ unsigned long ffz(unsigned long w)
* Somewhat like ffz but the equivalent of generic_ffs: in contrast to
* ffz we return the first one-bit *plus one*.
*/
-static __inline__ unsigned long ffs(unsigned long w)
+static inline unsigned long ffs(unsigned long w)
{
/* The generic_ffs function is used to avoid the asm when the
argument is a constant. */
@@ -283,7 +300,7 @@ static __inline__ unsigned long ffs(unsigned long w)
* @offset: The bitnumber to start searching at
* @size: The maximum size to search
*/
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+static inline int find_next_zero_bit (void * addr, int size, int offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
unsigned long result = offset & ~31UL;
@@ -331,6 +348,17 @@ static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
+/*
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
#define ext2_set_bit test_and_set_bit
#define ext2_clear_bit test_and_clear_bit
#define ext2_test_bit test_bit
@@ -343,7 +371,45 @@ static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-#endif /* __KERNEL__ */
+#if 0
+/* TODO: see below */
+#define sched_find_first_zero_bit(addr) find_first_zero_bit(addr, 168)
+
+#else
+/* TODO: left out pending where to put it.. (there are .h dependencies) */
+ /*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if 0
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+#else
+#define MAX_RT_PRIO 128
+#define MAX_PRIO 168
+#endif
+
+static inline int sched_find_first_zero_bit(char *bitmap)
+{
+ unsigned int *b = (unsigned int *)bitmap;
+ unsigned int rt;
+
+ rt = b[0] & b[1] & b[2] & b[3];
+ if (unlikely(rt != 0xffffffff))
+ return find_first_zero_bit(bitmap, MAX_RT_PRIO);
+
+ if (b[4] != ~0)
+ return ffz(b[4]) + MAX_RT_PRIO;
+ return ffz(b[5]) + 32 + MAX_RT_PRIO;
+}
+#undef MAX_PRIO
+#undef MAX_RT_PRIO
+#endif
+
+#endif /* __KERNEL__ */
#endif /* _CRIS_BITOPS_H */
diff --git a/include/asm-cris/elf.h b/include/asm-cris/elf.h
index 085c43dd7..dba80d060 100644
--- a/include/asm-cris/elf.h
+++ b/include/asm-cris/elf.h
@@ -9,8 +9,9 @@
typedef unsigned long elf_greg_t;
-/* These probably need fixing. */
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+/* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is
+ thus exposed to user-space. */
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
/* A placeholder; CRIS does not have any fp regs. */
@@ -45,7 +46,52 @@ typedef unsigned long elf_fpregset_t;
(_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \
} while (0)
-#undef USE_ELF_CORE_DUMP
+#define USE_ELF_CORE_DUMP
+
+/* The additional layer below is because the stack pointer is missing in
+ the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t,
+ and should be filled in according to the layout of the user_regs_struct
+ struct; regs is a pt_regs struct. We dump all registers, though several are
+ obviously unnecessary. That way there's less need for intelligence at
+ the receiving end (i.e. gdb). */
+#define ELF_CORE_COPY_REGS(pr_reg, regs) \
+ pr_reg[0] = regs->r0; \
+ pr_reg[1] = regs->r1; \
+ pr_reg[2] = regs->r2; \
+ pr_reg[3] = regs->r3; \
+ pr_reg[4] = regs->r4; \
+ pr_reg[5] = regs->r5; \
+ pr_reg[6] = regs->r6; \
+ pr_reg[7] = regs->r7; \
+ pr_reg[8] = regs->r8; \
+ pr_reg[9] = regs->r9; \
+ pr_reg[10] = regs->r10; \
+ pr_reg[11] = regs->r11; \
+ pr_reg[12] = regs->r12; \
+ pr_reg[13] = regs->r13; \
+ pr_reg[14] = rdusp(); /* sp */ \
+ pr_reg[15] = regs->irp; /* pc */ \
+ pr_reg[16] = 0; /* p0 */ \
+ pr_reg[17] = rdvr(); /* vr */ \
+ pr_reg[18] = 0; /* p2 */ \
+ pr_reg[19] = 0; /* p3 */ \
+ pr_reg[20] = 0; /* p4 */ \
+ pr_reg[21] = (regs->dccr & 0xffff); /* ccr */ \
+ pr_reg[22] = 0; /* p6 */ \
+ pr_reg[23] = regs->mof; /* mof */ \
+ pr_reg[24] = 0; /* p8 */ \
+ pr_reg[25] = 0; /* ibr */ \
+ pr_reg[26] = 0; /* irp */ \
+ pr_reg[27] = regs->srp; /* srp */ \
+ pr_reg[28] = 0; /* bar */ \
+ pr_reg[29] = regs->dccr; /* dccr */ \
+ pr_reg[30] = 0; /* brp */ \
+ pr_reg[31] = rdusp(); /* usp */ \
+ pr_reg[32] = 0; /* csrinstr */ \
+ pr_reg[33] = 0; /* csraddr */ \
+ pr_reg[34] = 0; /* csrdata */
+
+
#define ELF_EXEC_PAGESIZE 8192
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
diff --git a/include/asm-cris/ethernet.h b/include/asm-cris/ethernet.h
new file mode 100644
index 000000000..30da58a7d
--- /dev/null
+++ b/include/asm-cris/ethernet.h
@@ -0,0 +1,18 @@
+/*
+ * ioctl defines for ethernet driver
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ *
+ * Author: Mikael Starvik
+ *
+ */
+
+#ifndef _CRIS_ETHERNET_H
+#define _CRIS_ETHERNET_H
+#define SET_ETH_SPEED_AUTO SIOCDEVPRIVATE /* Auto neg speed */
+#define SET_ETH_SPEED_10 SIOCDEVPRIVATE+1 /* 10 Mbps */
+#define SET_ETH_SPEED_100 SIOCDEVPRIVATE+2 /* 100 Mbps. */
+#define SET_ETH_DUPLEX_AUTO SIOCDEVPRIVATE+3 /* Auto neg duplex */
+#define SET_ETH_DUPLEX_HALF SIOCDEVPRIVATE+4 /* Full duplex */
+#define SET_ETH_DUPLEX_FULL SIOCDEVPRIVATE+5 /* Half duplex */
+#endif /* _CRIS_ETHERNET_H */
diff --git a/include/asm-cris/irq.h b/include/asm-cris/irq.h
index b1b5ada6f..5e4fb8db6 100644
--- a/include/asm-cris/irq.h
+++ b/include/asm-cris/irq.h
@@ -126,6 +126,9 @@ void set_break_vector(int n, irqvectptr addr);
/* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls
* do_IRQ (with irq disabled still). after that it unblocks and jumps to
* ret_from_intr (entry.S)
+ *
+ * The reason the IRQ is blocked is to allow an sti() before the handler which
+ * will acknowledge the interrupt is run.
*/
#define BUILD_IRQ(nr,mask) \
@@ -151,6 +154,41 @@ __asm__ ( \
"reti\n\t" \
"nop\n");
+/* This is subtle. The timer interrupt is crucial and it should not be disabled for
+ * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would
+ * have been BLOCK'ed, and then softirq's are run before we return here to UNBLOCK.
+ * If the softirq's take too much time to run, the timer irq won't run and the
+ * watchdog will kill us.
+ *
+ * Furthermore, if a lot of other irq's occur before we return here, the multiple_irq
+ * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed
+ * it here, we would not get the multiple_irq at all.
+ *
+ * The non-blocking here is based on the knowledge that the timer interrupt is
+ * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will not
+ * be an sti() before the timer irq handler is run to acknowledge the interrupt.
+ */
+
+#define BUILD_TIMER_IRQ(nr,mask) \
+void IRQ_NAME(nr); \
+void sIRQ_NAME(nr); \
+void BAD_IRQ_NAME(nr); \
+__asm__ ( \
+ ".text\n\t" \
+ "IRQ" #nr "_interrupt:\n\t" \
+ SAVE_ALL \
+ "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
+ "moveq "#nr",$r10\n\t" \
+ "move.d $sp,$r11\n\t" \
+ "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
+ "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
+ "jump ret_from_intr\n\t" \
+ "bad_IRQ" #nr "_interrupt:\n\t" \
+ "push $r0\n\t" \
+ BLOCK_IRQ(mask,nr) \
+ "pop $r0\n\t" \
+ "reti\n\t" \
+ "nop\n");
#endif /* _ASM_IRQ_H */
diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h
index 549345ff4..5950e9c12 100644
--- a/include/asm-cris/page.h
+++ b/include/asm-cris/page.h
@@ -105,8 +105,14 @@ typedef unsigned long pgprot_t;
* to arm and m68k I think)
*/
-#define virt_to_page(kaddr) (mem_map + (((unsigned long)kaddr - PAGE_OFFSET) >> PAGE_SHIFT))
-#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
+#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT))
+#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr)
+
+/* convert a page (based on mem_map and forward) to a physical address
+ * do this by figuring out the virtual address and then use __pa
+ */
+
+#define page_to_phys(page) __pa((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
/* from linker script */
diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h
index 550c5fab2..80e73be0d 100644
--- a/include/asm-cris/pgalloc.h
+++ b/include/asm-cris/pgalloc.h
@@ -21,7 +21,7 @@ extern struct pgtable_cache_struct {
* Allocate and free page tables.
*/
-extern __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
{
pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
@@ -33,12 +33,12 @@ extern __inline__ pgd_t *get_pgd_slow(void)
return ret;
}
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
-extern __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
{
unsigned long *ret;
@@ -51,7 +51,7 @@ extern __inline__ pgd_t *get_pgd_fast(void)
return (pgd_t *)ret;
}
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+static inline void free_pgd_fast(pgd_t *pgd)
{
*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
pgd_quicklist = (unsigned long *) pgd;
diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
index a99f35703..e53340055 100644
--- a/include/asm-cris/pgtable.h
+++ b/include/asm-cris/pgtable.h
@@ -3,6 +3,12 @@
* HISTORY:
*
* $Log: pgtable.h,v $
+ * Revision 1.14 2001/12/10 03:08:50 bjornw
+ * Added pgtable_cache_init dummy
+ *
+ * Revision 1.13 2001/11/12 18:05:38 pkj
+ * Added declaration of paging_init().
+ *
* Revision 1.12 2001/08/11 00:28:00 bjornw
* PAGE_CHG_MASK and PAGE_NONE had somewhat untraditional values
*
@@ -106,6 +112,8 @@
* the CRIS page table tree.
*/
+extern void paging_init(void);
+
/* The cache doesn't need to be flushed when TLB entries change because
* the cache is mapped to physical memory, not virtual memory
*/
@@ -507,6 +515,6 @@ static inline void update_mmu_cache(struct vm_area_struct * vma,
/*
* No page table caches to initialise
*/
-#define pgtable_cache_init() do { } while (0)
+#define pgtable_cache_init() do { } while (0)
#endif /* _CRIS_PGTABLE_H */
diff --git a/include/asm-cris/processor.h b/include/asm-cris/processor.h
index a9b11b89e..7fba87a5a 100644
--- a/include/asm-cris/processor.h
+++ b/include/asm-cris/processor.h
@@ -142,6 +142,6 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t)
#define init_task (init_task_union.task)
#define init_stack (init_task_union.stack)
-#define cpu_relax() do { } while (0)
+#define cpu_relax() do { } while (0)
#endif /* __ASM_CRIS_PROCESSOR_H */
diff --git a/include/asm-cris/scatterlist.h b/include/asm-cris/scatterlist.h
new file mode 100644
index 000000000..5836b61d2
--- /dev/null
+++ b/include/asm-cris/scatterlist.h
@@ -0,0 +1,14 @@
+#ifndef __ASM_CRIS_SCATTERLIST_H
+#define __ASM_CRIS_SCATTERLIST_H
+
+struct scatterlist {
+ struct page * page; /* Location of data */
+ unsigned int offset;/* page offset */
+ unsigned int length;
+};
+
+/* i386 junk */
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* !(__ASM_CRIS_SCATTERLIST_H) */
diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h
index d42c6b383..9fe719c80 100644
--- a/include/asm-cris/unistd.h
+++ b/include/asm-cris/unistd.h
@@ -378,6 +378,7 @@ static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
static inline _syscall1(int,close,int,fd)
static inline _syscall1(int,_exit,int,exitcode)
static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
/* the following are just while developing the elinux port! */
diff --git a/include/asm-cris/user.h b/include/asm-cris/user.h
index 79c7048a3..982f4163b 100644
--- a/include/asm-cris/user.h
+++ b/include/asm-cris/user.h
@@ -28,8 +28,51 @@
* to write an integer number of pages.
*/
+/* User mode registers, used for core dumps. In order to keep ELF_NGREG
+ sensible we let all registers be 32 bits. The csr registers are included
+ for future use. */
+struct user_regs_struct {
+ unsigned long r0; /* General registers. */
+ unsigned long r1;
+ unsigned long r2;
+ unsigned long r3;
+ unsigned long r4;
+ unsigned long r5;
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long r8;
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long r11;
+ unsigned long r12;
+ unsigned long r13;
+ unsigned long sp; /* Stack pointer. */
+ unsigned long pc; /* Program counter. */
+ unsigned long p0; /* Constant zero (only 8 bits). */
+ unsigned long vr; /* Version register (only 8 bits). */
+ unsigned long p2; /* Reserved. */
+ unsigned long p3; /* Reserved. */
+ unsigned long p4; /* Constant zero (only 16 bits). */
+ unsigned long ccr; /* Condition code register (only 16 bits). */
+ unsigned long p6; /* Reserved. */
+ unsigned long mof; /* Multiply overflow register. */
+ unsigned long p8; /* Constant zero. */
+ unsigned long ibr; /* Not accessible. */
+ unsigned long irp; /* Not accessible. */
+ unsigned long srp; /* Subroutine return pointer. */
+ unsigned long bar; /* Not accessible. */
+ unsigned long dccr; /* Dword condition code register. */
+ unsigned long brp; /* Not accessible. */
+ unsigned long usp; /* User-mode stack pointer. Same as sp when
+ in user mode. */
+ unsigned long csrinstr; /* Internal status registers. */
+ unsigned long csraddr;
+ unsigned long csrdata;
+};
+
+
struct user {
- struct pt_regs regs; /* entire machine state */
+ struct user_regs_struct regs; /* entire machine state */
size_t u_tsize; /* text size (pages) */
size_t u_dsize; /* data size (pages) */
size_t u_ssize; /* stack size (pages) */
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index fc8b17144..e6d7377a7 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -35,13 +35,14 @@
* into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
* TLB, reschedule and local APIC vectors are performance-critical.
*
- * Vectors 0xf0-0xfa are free (reserved for future Linux use).
+ * Vectors 0xf0-0xf9 are free (reserved for future Linux use).
*/
#define SPURIOUS_APIC_VECTOR 0xff
#define ERROR_APIC_VECTOR 0xfe
#define INVALIDATE_TLB_VECTOR 0xfd
#define RESCHEDULE_VECTOR 0xfc
-#define CALL_FUNCTION_VECTOR 0xfb
+#define TASK_MIGRATION_VECTOR 0xfb
+#define CALL_FUNCTION_VECTOR 0xfa
/*
* Local APIC timer IRQ vector is on a different priority level,
diff --git a/include/asm-i386/smplock.h b/include/asm-i386/smplock.h
index 10cfc1fd0..c270defe9 100644
--- a/include/asm-i386/smplock.h
+++ b/include/asm-i386/smplock.h
@@ -19,8 +19,8 @@ extern spinlock_t kernel_flag;
do { \
if (unlikely(task->lock_depth >= 0)) { \
spin_unlock(&kernel_flag); \
- release_irqlock(cpu); \
- __sti(); \
+ if (global_irq_holder == (cpu)) \
+ BUG(); \
} \
} while (0)
diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
index c64aa4276..2b789faa0 100644
--- a/include/asm-sparc64/irq.h
+++ b/include/asm-sparc64/irq.h
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.20 2001-03-09 01:31:40 davem Exp $
+/* $Id: irq.h,v 1.21 2002-01-23 11:27:36 davem Exp $
* irq.h: IRQ registers on the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,10 +11,7 @@
#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
-
-struct devid_cookie {
- int dummy;
-};
+#include <asm/pil.h>
/* You should not mess with this directly. That's the job of irq.c.
*
diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h
new file mode 100644
index 000000000..9e3adb0f5
--- /dev/null
+++ b/include/asm-sparc64/pil.h
@@ -0,0 +1,21 @@
+/* $Id: pil.h,v 1.1 2002-01-23 11:27:36 davem Exp $ */
+#ifndef _SPARC64_PIL_H
+#define _SPARC64_PIL_H
+
+/* To avoid some locking problems, we hard allocate certain PILs
+ * for SMP cross call messages. cli() does not block the cross
+ * call delivery, so when SMP locking is an issue we reschedule
+ * the event into a PIL interrupt which is blocked by cli().
+ *
+ * XXX In fact the whole set of PILs used for hardware interrupts
+ * XXX may be allocated in this manner. All of the devices can
+ * XXX happily sit at the same PIL. We would then need only two
+ * XXX PILs, one for devices and one for the CPU local timer tick.
+ */
+#define PIL_MIGRATE 1
+
+#ifndef __ASSEMBLY__
+#define PIL_RESERVED(PIL) ((PIL) == PIL_MIGRATE)
+#endif
+
+#endif /* !(_SPARC64_PIL_H) */
diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h
index 68ba0f768..7859a5e18 100644
--- a/include/linux/affs_fs.h
+++ b/include/linux/affs_fs.h
@@ -6,6 +6,8 @@
#include <linux/types.h>
+#include <linux/affs_fs_i.h>
+
#define AFFS_SUPER_MAGIC 0xadff
struct affs_date;
diff --git a/include/linux/affs_fs_i.h b/include/linux/affs_fs_i.h
index 430ff682f..c32f69ca1 100644
--- a/include/linux/affs_fs_i.h
+++ b/include/linux/affs_fs_i.h
@@ -3,9 +3,6 @@
#include <linux/a.out.h>
-// move this to linux/coda.h!!!
-#include <linux/time.h>
-
#define AFFS_CACHE_SIZE PAGE_SIZE
//#define AFFS_CACHE_SIZE (4*4)
@@ -48,10 +45,13 @@ struct affs_inode_info {
unsigned char i_pad;
s32 i_parent; /* parent ino */
#endif
+ struct inode vfs_inode;
};
/* short cut to get to the affs specific inode data */
-#define AFFS_INODE (&inode->u.affs_i)
-#define AFFS_DIR (&dir->u.affs_i)
+static inline struct affs_inode_info *AFFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct affs_inode_info, vfs_inode);
+}
#endif
diff --git a/include/linux/amigaffs.h b/include/linux/amigaffs.h
index 1e7d6e8fa..b4b1d430c 100644
--- a/include/linux/amigaffs.h
+++ b/include/linux/amigaffs.h
@@ -93,32 +93,32 @@ affs_adjust_bitmapchecksum(struct buffer_head *bh, u32 val)
static inline void
affs_lock_link(struct inode *inode)
{
- down(&AFFS_INODE->i_link_lock);
+ down(&AFFS_I(inode)->i_link_lock);
}
static inline void
affs_unlock_link(struct inode *inode)
{
- up(&AFFS_INODE->i_link_lock);
+ up(&AFFS_I(inode)->i_link_lock);
}
static inline void
affs_lock_dir(struct inode *inode)
{
- down(&AFFS_INODE->i_hash_lock);
+ down(&AFFS_I(inode)->i_hash_lock);
}
static inline void
affs_unlock_dir(struct inode *inode)
{
- up(&AFFS_INODE->i_hash_lock);
+ up(&AFFS_I(inode)->i_hash_lock);
}
static inline void
affs_lock_ext(struct inode *inode)
{
- down(&AFFS_INODE->i_ext_lock);
+ down(&AFFS_I(inode)->i_ext_lock);
}
static inline void
affs_unlock_ext(struct inode *inode)
{
- up(&AFFS_INODE->i_ext_lock);
+ up(&AFFS_I(inode)->i_ext_lock);
}
#ifdef __LITTLE_ENDIAN
diff --git a/include/linux/blk.h b/include/linux/blk.h
index efede40e2..b6507e62e 100644
--- a/include/linux/blk.h
+++ b/include/linux/blk.h
@@ -90,9 +90,9 @@ extern inline struct request *elv_next_request(request_queue_t *q)
#define _elv_add_request(q, rq, back, p) do { \
if ((back)) \
- _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+ _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
else \
- _elv_add_request_core((q), (rq), &(q)->queue_head, 0); \
+ _elv_add_request_core((q), (rq), &(q)->queue_head, (p)); \
} while (0)
#define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
diff --git a/include/linux/cciss_ioctl.h b/include/linux/cciss_ioctl.h
index 54e513cf7..2f7e00b5b 100644
--- a/include/linux/cciss_ioctl.h
+++ b/include/linux/cciss_ioctl.h
@@ -184,6 +184,11 @@ typedef struct _IOCTL_Command_struct {
#define CCISS_GETDRIVVER _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
#define CCISS_REVALIDVOLS _IO(CCISS_IOC_MAGIC, 10)
#define CCISS_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_DEREGDISK _IO(CCISS_IOC_MAGIC, 12)
+/* no longer used... use REGNEWD instead */
+#define CCISS_REGNEWDISK _IOW(CCISS_IOC_MAGIC, 13, int)
+
+#define CCISS_REGNEWD _IO(CCISS_IOC_MAGIC, 14)
#endif
diff --git a/include/linux/coda.h b/include/linux/coda.h
index f96edc7c7..0d168b715 100644
--- a/include/linux/coda.h
+++ b/include/linux/coda.h
@@ -99,6 +99,7 @@ typedef unsigned long long u_quad_t;
#if defined(__linux__)
+#include <linux/time.h>
#define cdev_t u_quad_t
#ifndef __KERNEL__
#if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2)
diff --git a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h
index 43d63d776..959fb24a9 100644
--- a/include/linux/coda_fs_i.h
+++ b/include/linux/coda_fs_i.h
@@ -24,6 +24,7 @@ struct coda_inode_info {
unsigned int c_contcount; /* refcount for container file */
struct coda_cred c_cached_cred; /* credentials of cached perms */
unsigned int c_cached_perm; /* cached access permissions */
+ struct inode vfs_inode;
};
/* flags */
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index d514f908a..de66780b8 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -111,7 +111,10 @@ do { \
/* inode to cnode access functions */
-#define ITOC(inode) (&((inode)->u.coda_i))
+static inline struct coda_inode_info *ITOC(struct inode *inode)
+{
+ return list_entry(inode, struct coda_inode_info, vfs_inode);
+}
static __inline__ struct ViceFid *coda_i2f(struct inode *inode)
{
diff --git a/include/linux/dnotify.h b/include/linux/dnotify.h
index 5e231462b..90813c505 100644
--- a/include/linux/dnotify.h
+++ b/include/linux/dnotify.h
@@ -4,6 +4,8 @@
* Copyright 2000 (C) Stephen Rothwell
*/
+#include <linux/fs.h>
+
struct dnotify_struct {
struct dnotify_struct * dn_next;
int dn_magic;
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
index ae049ed2f..99d468975 100644
--- a/include/linux/efs_fs.h
+++ b/include/linux/efs_fs.h
@@ -37,13 +37,11 @@ static const char cprt[] = "EFS: "EFS_VERSION" - (c) 1999 Al Smith <Al.Smith@aes
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
-#ifdef _EFS_USE_GENERIC
-#define INODE_INFO(i) (struct efs_inode_info *) &((i)->u.generic_ip)
-#define SUPER_INFO(s) (struct efs_sb_info *) &((s)->u.generic_sbp)
-#else
-#define INODE_INFO(i) &((i)->u.efs_i)
+static inline struct efs_inode_info *INODE_INFO(struct inode *inode)
+{
+ return list_entry(inode, struct efs_inode_info, vfs_inode);
+}
#define SUPER_INFO(s) &((s)->u.efs_sb)
-#endif
extern struct inode_operations efs_dir_inode_operations;
extern struct file_operations efs_dir_operations;
diff --git a/include/linux/efs_fs_i.h b/include/linux/efs_fs_i.h
new file mode 100644
index 000000000..64fe538ac
--- /dev/null
+++ b/include/linux/efs_fs_i.h
@@ -0,0 +1,68 @@
+/*
+ * efs_fs_i.h
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from IRIX header files (c) 1988 Silicon Graphics
+ */
+
+#ifndef __EFS_FS_I_H__
+#define __EFS_FS_I_H__
+
+typedef int32_t efs_block_t;
+typedef uint32_t efs_ino_t;
+
+#define EFS_DIRECTEXTENTS 12
+
+/*
+ * layout of an extent, in memory and on disk. 8 bytes exactly.
+ */
+typedef union extent_u {
+ unsigned char raw[8];
+ struct extent_s {
+ unsigned int ex_magic:8; /* magic # (zero) */
+ unsigned int ex_bn:24; /* basic block */
+ unsigned int ex_length:8; /* numblocks in this extent */
+ unsigned int ex_offset:24; /* logical offset into file */
+ } cooked;
+} efs_extent;
+
+typedef struct edevs {
+ short odev;
+ unsigned int ndev;
+} efs_devs;
+
+/*
+ * extent based filesystem inode as it appears on disk. The efs inode
+ * is exactly 128 bytes long.
+ */
+struct efs_dinode {
+ u_short di_mode; /* mode and type of file */
+ short di_nlink; /* number of links to file */
+ u_short di_uid; /* owner's user id */
+ u_short di_gid; /* owner's group id */
+ int32_t di_size; /* number of bytes in file */
+ int32_t di_atime; /* time last accessed */
+ int32_t di_mtime; /* time last modified */
+ int32_t di_ctime; /* time created */
+ uint32_t di_gen; /* generation number */
+ short di_numextents; /* # of extents */
+ u_char di_version; /* version of inode */
+ u_char di_spare; /* spare - used by AFS */
+ union di_addr {
+ efs_extent di_extents[EFS_DIRECTEXTENTS];
+ efs_devs di_dev; /* device for IFCHR/IFBLK */
+ } di_u;
+};
+
+/* efs inode storage in memory */
+struct efs_inode_info {
+ int numextents;
+ int lastextent;
+
+ efs_extent extents[EFS_DIRECTEXTENTS];
+ struct inode vfs_inode;
+};
+
+#endif /* __EFS_FS_I_H__ */
+
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 03112a82f..2b3624d80 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -532,101 +532,4 @@ enum {
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
-#ifdef __KERNEL__
-/*
- * Function prototypes
- */
-
-/*
- * Ok, these declarations are also in <linux/kernel.h> but none of the
- * ext2 source programs needs to include it so they are duplicated here.
- */
-# define NORET_TYPE /**/
-# define ATTRIB_NORET __attribute__((noreturn))
-# define NORET_AND noreturn,
-
-/* balloc.c */
-extern int ext2_bg_has_super(struct super_block *sb, int group);
-extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
-extern int ext2_new_block (struct inode *, unsigned long,
- __u32 *, __u32 *, int *);
-extern void ext2_free_blocks (struct inode *, unsigned long,
- unsigned long);
-extern unsigned long ext2_count_free_blocks (struct super_block *);
-extern void ext2_check_blocks_bitmap (struct super_block *);
-extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
- unsigned int block_group,
- struct buffer_head ** bh);
-
-/* dir.c */
-extern int ext2_add_link (struct dentry *, struct inode *);
-extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
-extern int ext2_make_empty(struct inode *, struct inode *);
-extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
-extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
-extern int ext2_empty_dir (struct inode *);
-extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
-extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
-
-/* fsync.c */
-extern int ext2_sync_file (struct file *, struct dentry *, int);
-extern int ext2_fsync_inode (struct inode *, int);
-
-/* ialloc.c */
-extern struct inode * ext2_new_inode (const struct inode *, int);
-extern void ext2_free_inode (struct inode *);
-extern unsigned long ext2_count_free_inodes (struct super_block *);
-extern void ext2_check_inodes_bitmap (struct super_block *);
-extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
-
-/* inode.c */
-extern void ext2_read_inode (struct inode *);
-extern void ext2_write_inode (struct inode *, int);
-extern void ext2_put_inode (struct inode *);
-extern void ext2_delete_inode (struct inode *);
-extern int ext2_sync_inode (struct inode *);
-extern void ext2_discard_prealloc (struct inode *);
-extern void ext2_truncate (struct inode *);
-
-/* ioctl.c */
-extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
- unsigned long);
-
-/* super.c */
-extern void ext2_error (struct super_block *, const char *, const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
- const char *, ...)
- __attribute__ ((NORET_AND format (printf, 3, 4)));
-extern void ext2_warning (struct super_block *, const char *, const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-extern void ext2_update_dynamic_rev (struct super_block *sb);
-extern void ext2_put_super (struct super_block *);
-extern void ext2_write_super (struct super_block *);
-extern int ext2_remount (struct super_block *, int *, char *);
-extern struct super_block * ext2_read_super (struct super_block *,void *,int);
-extern int ext2_statfs (struct super_block *, struct statfs *);
-
-/*
- * Inodes and files operations
- */
-
-/* dir.c */
-extern struct file_operations ext2_dir_operations;
-
-/* file.c */
-extern struct inode_operations ext2_file_inode_operations;
-extern struct file_operations ext2_file_operations;
-
-/* inode.c */
-extern struct address_space_operations ext2_aops;
-
-/* namei.c */
-extern struct inode_operations ext2_dir_inode_operations;
-
-/* symlink.c */
-extern struct inode_operations ext2_fast_symlink_inode_operations;
-
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_EXT2_FS_H */
diff --git a/include/linux/ext2_fs_i.h b/include/linux/ext2_fs_i.h
deleted file mode 100644
index 7f02e7537..000000000
--- a/include/linux/ext2_fs_i.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * linux/include/linux/ext2_fs_i.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/include/linux/minix_fs_i.h
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-#ifndef _LINUX_EXT2_FS_I
-#define _LINUX_EXT2_FS_I
-
-/*
- * second extended file system inode data in memory
- */
-struct ext2_inode_info {
- __u32 i_data[15];
- __u32 i_flags;
- __u32 i_faddr;
- __u8 i_frag_no;
- __u8 i_frag_size;
- __u16 i_osync;
- __u32 i_file_acl;
- __u32 i_dir_acl;
- __u32 i_dtime;
- __u32 i_block_group;
- __u32 i_next_alloc_block;
- __u32 i_next_alloc_goal;
- __u32 i_prealloc_block;
- __u32 i_prealloc_count;
- __u32 i_dir_start_lookup;
- int i_new_inode:1; /* Is a freshly allocated inode */
-};
-
-#endif /* _LINUX_EXT2_FS_I */
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index db5de1462..c7fed24a7 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -443,7 +443,10 @@ struct ext3_super_block {
#ifdef __KERNEL__
#define EXT3_SB(sb) (&((sb)->u.ext3_sb))
-#define EXT3_I(inode) (&((inode)->u.ext3_i))
+static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
+{
+ return list_entry(inode, struct ext3_inode_info, vfs_inode);
+}
#else
/* Assume that user mode programs are passing in an ext3fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
@@ -451,7 +454,7 @@ struct ext3_super_block {
#define EXT3_SB(sb) (sb)
#endif
-#define NEXT_ORPHAN(inode) (inode)->u.ext3_i.i_dtime
+#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime
/*
* Codes for operating systems
@@ -620,7 +623,7 @@ extern int ext3_check_dir_entry(const char *, struct inode *,
extern int ext3_sync_file (struct file *, struct dentry *, int);
/* ialloc.c */
-extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int);
+extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
extern void ext3_free_inode (handle_t *, struct inode *);
extern struct inode * ext3_orphan_get (struct super_block *, ino_t);
extern unsigned long ext3_count_free_inodes (struct super_block *);
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
index 3c8d398a8..104aea4e0 100644
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -73,6 +73,7 @@ struct ext3_inode_info {
* by other means, so we have truncate_sem.
*/
struct rw_semaphore truncate_sem;
+ struct inode vfs_inode;
};
#endif /* _LINUX_EXT3_FS_I */
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
index 88bb8a516..ece9ec115 100644
--- a/include/linux/ext3_jbd.h
+++ b/include/linux/ext3_jbd.h
@@ -289,7 +289,7 @@ static inline int ext3_should_journal_data(struct inode *inode)
return 1;
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
return 1;
- if (inode->u.ext3_i.i_flags & EXT3_JOURNAL_DATA_FL)
+ if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
return 1;
return 0;
}
diff --git a/include/linux/file.h b/include/linux/file.h
index bac312507..5e006ad08 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -5,12 +5,9 @@
#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
-#ifndef _LINUX_POSIX_TYPES_H /* __FD_CLR */
+#include <asm/atomic.h>
#include <linux/posix_types.h>
-#endif
-#ifndef __LINUX_COMPILER_H /* unlikely */
#include <linux/compiler.h>
-#endif
/*
* The default fd array needs to be at least BITS_PER_LONG,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a01f0c3b4..6bda17aed 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -262,7 +262,7 @@ struct buffer_head {
wait_queue_head_t b_wait;
- struct inode * b_inode;
+ int b_inode; /* will go away */
struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */
};
@@ -288,25 +288,15 @@ extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long
#include <linux/pipe_fs_i.h>
#include <linux/minix_fs_i.h>
-#include <linux/ext2_fs_i.h>
-#include <linux/ext3_fs_i.h>
-#include <linux/hpfs_fs_i.h>
#include <linux/ntfs_fs_i.h>
#include <linux/msdos_fs_i.h>
#include <linux/umsdos_fs_i.h>
#include <linux/iso_fs_i.h>
-#include <linux/nfs_fs_i.h>
#include <linux/sysv_fs_i.h>
-#include <linux/affs_fs_i.h>
-#include <linux/ufs_fs_i.h>
-#include <linux/efs_fs_i.h>
-#include <linux/coda_fs_i.h>
#include <linux/romfs_fs_i.h>
-#include <linux/shmem_fs.h>
#include <linux/smb_fs_i.h>
#include <linux/hfs_fs_i.h>
#include <linux/adfs_fs_i.h>
-#include <linux/qnx4_fs_i.h>
#include <linux/reiserfs_fs_i.h>
#include <linux/bfs_fs_i.h>
#include <linux/udf_fs_i.h>
@@ -477,25 +467,15 @@ struct inode {
__u32 i_generation;
union {
struct minix_inode_info minix_i;
- struct ext2_inode_info ext2_i;
- struct ext3_inode_info ext3_i;
- struct hpfs_inode_info hpfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_info msdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_info isofs_i;
- struct nfs_inode_info nfs_i;
struct sysv_inode_info sysv_i;
- struct affs_inode_info affs_i;
- struct ufs_inode_info ufs_i;
- struct efs_inode_info efs_i;
struct romfs_inode_info romfs_i;
- struct shmem_inode_info shmem_i;
- struct coda_inode_info coda_i;
struct smb_inode_info smbfs_i;
struct hfs_inode_info hfs_i;
struct adfs_inode_info adfs_i;
- struct qnx4_inode_info qnx4_i;
struct reiserfs_inode_info reiserfs_i;
struct bfs_inode_info bfs_i;
struct udf_inode_info udf_i;
@@ -507,6 +487,12 @@ struct inode {
} u;
};
+#include <linux/shmem_fs.h>
+/* will die */
+#include <linux/coda_fs_i.h>
+#include <linux/ext3_fs_i.h>
+#include <linux/efs_fs_i.h>
+
struct fown_struct {
int pid; /* pid or -pgrp where SIGIO should be sent */
uid_t uid, euid; /* uid/euid of process setting the owner */
@@ -563,6 +549,9 @@ extern int init_private_file(struct file *, struct dentry *, int);
*/
typedef struct files_struct *fl_owner_t;
+/* that will die - we need it for nfs_lock_info */
+#include <linux/nfs_fs_i.h>
+
struct file_lock {
struct file_lock *fl_next; /* singly linked list for this inode */
struct list_head fl_link; /* doubly linked list of all locks */
@@ -859,6 +848,9 @@ struct seq_file;
* without the big kernel lock held in all filesystems.
*/
struct super_operations {
+ struct inode *(*alloc_inode)(struct super_block *sb);
+ void (*destroy_inode)(struct inode *);
+
void (*read_inode) (struct inode *);
/* reiserfs kludge. reiserfs needs 64 bits of information to
@@ -1151,7 +1143,16 @@ static inline void mark_buffer_clean(struct buffer_head * bh)
extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+ buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+ buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
#define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
@@ -1219,10 +1220,16 @@ extern int fsync_dev(kdev_t);
extern int fsync_super(struct super_block *);
extern int fsync_no_super(struct block_device *);
extern void sync_inodes_sb(struct super_block *);
-extern int osync_inode_buffers(struct inode *);
-extern int osync_inode_data_buffers(struct inode *);
-extern int fsync_inode_buffers(struct inode *);
-extern int fsync_inode_data_buffers(struct inode *);
+extern int osync_buffers_list(struct list_head *);
+extern int fsync_buffers_list(struct list_head *);
+static inline int fsync_inode_buffers(struct inode *inode)
+{
+ return fsync_buffers_list(&inode->i_dirty_buffers);
+}
+static inline int fsync_inode_data_buffers(struct inode *inode)
+{
+ return fsync_buffers_list(&inode->i_dirty_data_buffers);
+}
extern int inode_has_buffers(struct inode *);
extern void filemap_fdatasync(struct address_space *);
extern void filemap_fdatawait(struct address_space *);
@@ -1327,6 +1334,7 @@ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+extern void inode_init_once(struct inode *);
extern void iput(struct inode *);
extern void force_delete(struct inode *);
extern struct inode * igrab(struct inode *);
@@ -1340,20 +1348,8 @@ static inline struct inode *iget(struct super_block *sb, unsigned long ino)
}
extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
- struct inode *inode = get_empty_inode();
- if (inode) {
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_blkbits = sb->s_blocksize_bits;
- }
- return inode;
-}
+extern struct inode *new_inode(struct super_block *);
extern void remove_suid(struct inode *inode);
-
extern void insert_inode_hash(struct inode *);
extern void remove_inode_hash(struct inode *);
extern struct file * get_empty_filp(void);
diff --git a/include/linux/hpfs_fs_i.h b/include/linux/hpfs_fs_i.h
index 56a758b16..c4d6cce5d 100644
--- a/include/linux/hpfs_fs_i.h
+++ b/include/linux/hpfs_fs_i.h
@@ -18,24 +18,7 @@ struct hpfs_inode_info {
unsigned i_dirty : 1;
struct semaphore i_sem; /* semaphore */
loff_t **i_rddir_off;
+ struct inode vfs_inode;
};
-#define i_hpfs_dno u.hpfs_i.i_dno
-#define i_hpfs_parent_dir u.hpfs_i.i_parent_dir
-#define i_hpfs_n_secs u.hpfs_i.i_n_secs
-#define i_hpfs_file_sec u.hpfs_i.i_file_sec
-#define i_hpfs_disk_sec u.hpfs_i.i_disk_sec
-#define i_hpfs_dpos u.hpfs_i.i_dpos
-#define i_hpfs_dsubdno u.hpfs_i.i_dsubdno
-#define i_hpfs_ea_size u.hpfs_i.i_ea_size
-#define i_hpfs_conv u.hpfs_i.i_conv
-#define i_hpfs_ea_mode u.hpfs_i.i_ea_mode
-#define i_hpfs_ea_uid u.hpfs_i.i_ea_uid
-#define i_hpfs_ea_gid u.hpfs_i.i_ea_gid
-/*#define i_hpfs_lock u.hpfs_i.i_lock*/
-/*#define i_hpfs_queue u.hpfs_i.i_queue*/
-#define i_hpfs_sem u.hpfs_i.i_sem
-#define i_hpfs_rddir_off u.hpfs_i.i_rddir_off
-#define i_hpfs_dirty u.hpfs_i.i_dirty
-
#endif
diff --git a/include/linux/ide.h b/include/linux/ide.h
index b5e752a49..8b81bcc98 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -884,6 +884,9 @@ typedef enum {
*/
#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
+#define task_rq_offset(rq) \
+ (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
{
return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
@@ -895,6 +898,24 @@ extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
}
/*
+ * for now, taskfile requests are special :/
+ */
+extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+ if (rq->bio)
+ return ide_map_buffer(rq, flags);
+ else
+ return rq->buffer + task_rq_offset(rq);
+}
+
+extern inline void ide_unmap_rq(struct request *rq, char *buf,
+ unsigned long *flags)
+{
+ if (rq->bio)
+ ide_unmap_buffer(buf, flags);
+}
+
+/*
* This function issues a special IDE device request
* onto the request queue.
*
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 3c4e71fc0..b496169b6 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -1,9 +1,7 @@
#ifndef _LINUX__INIT_TASK_H
#define _LINUX__INIT_TASK_H
-#ifndef __LINUX_FILE_H
#include <linux/file.h>
-#endif
#define INIT_FILES \
{ \
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 6f6ae5160..b59350f01 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -178,8 +178,6 @@ typedef struct {
* the correspondent code in isdn.c
*/
-#define ISDN_MINOR_B 0
-#define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1)
#define ISDN_MINOR_CTRL 64
#define ISDN_MINOR_CTRLMAX (64 + (ISDN_MAX_CHANNELS-1))
#define ISDN_MINOR_PPP 128
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index 7d6b31638..0ad3d1865 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -368,7 +368,7 @@ static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
static inline void cfi_udelay(int us)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- if (current->need_resched) {
+ if (need_resched()) {
unsigned long t = us * HZ / 1000000;
if (t < 1)
t = 1;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 97f3ecaf1..8096e640c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -278,6 +278,10 @@ struct net_device
struct net_device_stats* (*get_stats)(struct net_device *dev);
struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
+ /* List of functions to handle Wireless Extensions (instead of ioctl).
+ * See <net/iw_handler.h> for details. Jean II */
+ struct iw_handler_def * wireless_handlers;
+
/*
* This marks the end of the "visible" part of the structure. All
* fields hereafter are internal to the system, and may change at
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index efbbdba3a..93aae0c5f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -63,67 +63,154 @@
*/
#define NFS_SUPER_MAGIC 0x6969
-static inline struct nfs_inode_info *NFS_I(struct inode *inode)
+/*
+ * These are the default flags for swap requests
+ */
+#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
+
+/* Flags in the RPC client structure */
+#define NFS_CLNTF_BUFSIZE 0x0001 /* readdir buffer in longwords */
+
+#define NFS_RW_SYNC 0x0001 /* O_SYNC handling */
+#define NFS_RW_SWAP 0x0002 /* This is a swap request */
+
+/*
+ * When flushing a cluster of dirty pages, there can be different
+ * strategies:
+ */
+#define FLUSH_AGING 0 /* only flush old buffers */
+#define FLUSH_SYNC 1 /* file being synced, or contention */
+#define FLUSH_WAIT 2 /* wait for completion */
+#define FLUSH_STABLE 4 /* commit to stable storage */
+
+#ifdef __KERNEL__
+
+/*
+ * nfs fs inode data in memory
+ */
+struct nfs_inode {
+ /*
+ * The 64bit 'inode number'
+ */
+ __u64 fsid;
+ __u64 fileid;
+
+ /*
+ * NFS file handle
+ */
+ struct nfs_fh fh;
+
+ /*
+ * Various flags
+ */
+ unsigned short flags;
+
+ /*
+ * read_cache_jiffies is when we started read-caching this inode,
+ * and read_cache_mtime is the mtime of the inode at that time.
+ * attrtimeo is for how long the cached information is assumed
+ * to be valid. A successful attribute revalidation doubles
+ * attrtimeo (up to acregmax/acdirmax), a failure resets it to
+ * acregmin/acdirmin.
+ *
+ * We need to revalidate the cached attrs for this inode if
+ *
+ * jiffies - read_cache_jiffies > attrtimeo
+ *
+ * and invalidate any cached data/flush out any dirty pages if
+ * we find that
+ *
+ * mtime != read_cache_mtime
+ */
+ unsigned long read_cache_jiffies;
+ __u64 read_cache_ctime;
+ __u64 read_cache_mtime;
+ __u64 read_cache_isize;
+ unsigned long attrtimeo;
+ unsigned long attrtimeo_timestamp;
+
+ /*
+ * This is the cookie verifier used for NFSv3 readdir
+ * operations
+ */
+ __u32 cookieverf[2];
+
+ /*
+ * This is the list of dirty unwritten pages.
+ */
+ struct list_head read;
+ struct list_head dirty;
+ struct list_head commit;
+ struct list_head writeback;
+
+ unsigned int nread,
+ ndirty,
+ ncommit,
+ npages;
+
+ /* Flush daemon info */
+ struct inode *hash_next,
+ *hash_prev;
+ unsigned long nextscan;
+
+ /* Credentials for shared mmap */
+ struct rpc_cred *mm_cred;
+
+ struct inode vfs_inode;
+};
+
+/*
+ * Legal inode flag values
+ */
+#define NFS_INO_STALE 0x0001 /* possible stale inode */
+#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */
+#define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */
+#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */
+#define NFS_INO_FLUSH 0x0020 /* inode is due for flushing */
+#define NFS_INO_NEW 0x0040 /* hadn't been filled yet */
+
+static inline struct nfs_inode *NFS_I(struct inode *inode)
{
- return &inode->u.nfs_i;
+ return list_entry(inode, struct nfs_inode, vfs_inode);
}
-#define NFS_FH(inode) (&(inode)->u.nfs_i.fh)
+#define NFS_FH(inode) (&NFS_I(inode)->fh)
#define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server)
#define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
#define NFS_PROTO(inode) (NFS_SERVER(inode)->rpc_ops)
#define NFS_REQUESTLIST(inode) (NFS_SERVER(inode)->rw_requests)
#define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode)))
#define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode)))
-#define NFS_COOKIEVERF(inode) ((inode)->u.nfs_i.cookieverf)
-#define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies)
-#define NFS_CACHE_CTIME(inode) ((inode)->u.nfs_i.read_cache_ctime)
-#define NFS_CACHE_MTIME(inode) ((inode)->u.nfs_i.read_cache_mtime)
-#define NFS_CACHE_ISIZE(inode) ((inode)->u.nfs_i.read_cache_isize)
-#define NFS_NEXTSCAN(inode) ((inode)->u.nfs_i.nextscan)
+#define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf)
+#define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies)
+#define NFS_CACHE_CTIME(inode) (NFS_I(inode)->read_cache_ctime)
+#define NFS_CACHE_MTIME(inode) (NFS_I(inode)->read_cache_mtime)
+#define NFS_CACHE_ISIZE(inode) (NFS_I(inode)->read_cache_isize)
+#define NFS_NEXTSCAN(inode) (NFS_I(inode)->nextscan)
#define NFS_CACHEINV(inode) \
do { \
NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
} while (0)
-#define NFS_ATTRTIMEO(inode) ((inode)->u.nfs_i.attrtimeo)
+#define NFS_ATTRTIMEO(inode) (NFS_I(inode)->attrtimeo)
#define NFS_MINATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
: NFS_SERVER(inode)->acregmin)
#define NFS_MAXATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
: NFS_SERVER(inode)->acregmax)
-#define NFS_ATTRTIMEO_UPDATE(inode) ((inode)->u.nfs_i.attrtimeo_timestamp)
+#define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp)
-#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
+#define NFS_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE)
+#define NFS_NEW(inode) (NFS_FLAGS(inode) & NFS_INO_NEW)
-#define NFS_FILEID(inode) ((inode)->u.nfs_i.fileid)
-#define NFS_FSID(inode) ((inode)->u.nfs_i.fsid)
+#define NFS_FILEID(inode) (NFS_I(inode)->fileid)
+#define NFS_FSID(inode) (NFS_I(inode)->fsid)
/* Inode Flags */
#define NFS_USE_READDIRPLUS(inode) ((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
-/*
- * These are the default flags for swap requests
- */
-#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
-
-/* Flags in the RPC client structure */
-#define NFS_CLNTF_BUFSIZE 0x0001 /* readdir buffer in longwords */
-
-#define NFS_RW_SYNC 0x0001 /* O_SYNC handling */
-#define NFS_RW_SWAP 0x0002 /* This is a swap request */
-
-/*
- * When flushing a cluster of dirty pages, there can be different
- * strategies:
- */
-#define FLUSH_AGING 0 /* only flush old buffers */
-#define FLUSH_SYNC 1 /* file being synced, or contention */
-#define FLUSH_WAIT 2 /* wait for completion */
-#define FLUSH_STABLE 4 /* commit to stable storage */
-
static inline
loff_t page_offset(struct page *page)
{
@@ -136,7 +223,6 @@ unsigned long page_index(struct page *page)
return page->index;
}
-#ifdef __KERNEL__
/*
* linux/fs/nfs/inode.c
*/
@@ -220,13 +306,13 @@ extern int nfs_scan_lru_commit_timeout(struct nfs_server *, struct list_head *)
static inline int
nfs_have_read(struct inode *inode)
{
- return !list_empty(&inode->u.nfs_i.read);
+ return !list_empty(&NFS_I(inode)->read);
}
static inline int
nfs_have_writebacks(struct inode *inode)
{
- return !list_empty(&inode->u.nfs_i.writeback);
+ return !list_empty(&NFS_I(inode)->writeback);
}
static inline int
diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h
index 7fc3bae22..5a4fa8d54 100644
--- a/include/linux/nfs_fs_i.h
+++ b/include/linux/nfs_fs_i.h
@@ -6,87 +6,6 @@
#include <linux/nfs.h>
/*
- * nfs fs inode data in memory
- */
-struct nfs_inode_info {
- /*
- * The 64bit 'inode number'
- */
- __u64 fsid;
- __u64 fileid;
-
- /*
- * NFS file handle
- */
- struct nfs_fh fh;
-
- /*
- * Various flags
- */
- unsigned short flags;
-
- /*
- * read_cache_jiffies is when we started read-caching this inode,
- * and read_cache_mtime is the mtime of the inode at that time.
- * attrtimeo is for how long the cached information is assumed
- * to be valid. A successful attribute revalidation doubles
- * attrtimeo (up to acregmax/acdirmax), a failure resets it to
- * acregmin/acdirmin.
- *
- * We need to revalidate the cached attrs for this inode if
- *
- * jiffies - read_cache_jiffies > attrtimeo
- *
- * and invalidate any cached data/flush out any dirty pages if
- * we find that
- *
- * mtime != read_cache_mtime
- */
- unsigned long read_cache_jiffies;
- __u64 read_cache_ctime;
- __u64 read_cache_mtime;
- __u64 read_cache_isize;
- unsigned long attrtimeo;
- unsigned long attrtimeo_timestamp;
-
- /*
- * This is the cookie verifier used for NFSv3 readdir
- * operations
- */
- __u32 cookieverf[2];
-
- /*
- * This is the list of dirty unwritten pages.
- */
- struct list_head read;
- struct list_head dirty;
- struct list_head commit;
- struct list_head writeback;
-
- unsigned int nread,
- ndirty,
- ncommit,
- npages;
-
- /* Flush daemon info */
- struct inode *hash_next,
- *hash_prev;
- unsigned long nextscan;
-
- /* Credentials for shared mmap */
- struct rpc_cred *mm_cred;
-};
-
-/*
- * Legal inode flag values
- */
-#define NFS_INO_STALE 0x0001 /* possible stale inode */
-#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */
-#define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */
-#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */
-#define NFS_INO_FLUSH 0x0020 /* inode is due for flushing */
-
-/*
* NFS lock info
*/
struct nfs_lock_info {
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
index 55ba2f99d..fc1912a3f 100644
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -97,6 +97,12 @@ struct qnx4_super_block {
#define QNX4DEBUG(X) (void) 0
#endif
+struct qnx4_inode_info {
+ struct qnx4_inode_entry raw;
+ unsigned long mmu_private;
+ struct inode vfs_inode;
+};
+
extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
@@ -120,6 +126,16 @@ extern int qnx4_sync_file(struct file *file, struct dentry *dentry, int);
extern int qnx4_sync_inode(struct inode *inode);
extern int qnx4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create);
+static inline struct qnx4_inode_info *qnx4_i(struct inode *inode)
+{
+ return list_entry(inode, struct qnx4_inode_info, vfs_inode);
+}
+
+static inline struct qnx4_inode_entry *qnx4_raw_inode(struct inode *inode)
+{
+ return &qnx4_i(inode)->raw;
+}
+
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/qnx4_fs_i.h b/include/linux/qnx4_fs_i.h
deleted file mode 100644
index b0fe8463e..000000000
--- a/include/linux/qnx4_fs_i.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Name : qnx4_fs_i.h
- * Author : Richard Frowijn
- * Function : qnx4 inode definitions
- * Version : 1.0.2
- * Last modified : 2000-01-06
- *
- * History : 23-03-1998 created
- *
- */
-#ifndef _QNX4_FS_I
-#define _QNX4_FS_I
-
-#include <linux/qnxtypes.h>
-
-/*
- * qnx4 fs inode entry
- */
-struct qnx4_inode_info {
- char i_reserved[16]; /* 16 */
- qnx4_off_t i_size; /* 4 */
- qnx4_xtnt_t i_first_xtnt; /* 8 */
- __u32 i_xblk; /* 4 */
- __s32 i_ftime; /* 4 */
- __s32 i_mtime; /* 4 */
- __s32 i_atime; /* 4 */
- __s32 i_ctime; /* 4 */
- qnx4_nxtnt_t i_num_xtnts; /* 2 */
- qnx4_mode_t i_mode; /* 2 */
- qnx4_muid_t i_uid; /* 2 */
- qnx4_mgid_t i_gid; /* 2 */
- qnx4_nlink_t i_nlink; /* 2 */
- __u8 i_zero[4]; /* 4 */
- qnx4_ftype_t i_type; /* 1 */
- __u8 i_status; /* 1 */
- unsigned long mmu_private;
-};
-
-#endif
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index a78f78986..73d6d823f 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -300,7 +300,7 @@ struct reiserfs_journal {
int j_free_bitmap_nodes ;
int j_used_bitmap_nodes ;
struct list_head j_bitmap_nodes ;
- struct inode j_dummy_inode ;
+ struct list_head j_dirty_buffers ;
struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ; /* array of bitmaps to record the deleted blocks */
struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ; /* array of all the journal lists */
struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for real buffer heads in current trans */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index b8d564fd0..b34544b83 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -25,6 +25,7 @@ extern unsigned long event;
#include <linux/signal.h>
#include <linux/securebits.h>
#include <linux/fs_struct.h>
+#include <linux/compiler.h>
struct exec_domain;
@@ -136,16 +137,20 @@ struct completion;
extern rwlock_t tasklist_lock;
extern spinlock_t mmlist_lock;
+typedef struct task_struct task_t;
+
extern void sched_init(void);
extern void init_idle(void);
+extern void idle_startup_done(void);
extern void show_state(void);
extern void cpu_init (void);
extern void trap_init(void);
extern void update_process_times(int user);
extern void update_one_process(struct task_struct *p, unsigned long user,
unsigned long system, int cpu);
-extern void expire_task(struct task_struct *p);
-extern void idle_tick(void);
+extern void scheduler_tick(struct task_struct *p);
+extern void sched_task_migrated(struct task_struct *p);
+extern void smp_migrate_task(int cpu, task_t *task);
#define MAX_SCHEDULE_TIMEOUT LONG_MAX
extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -221,7 +226,6 @@ struct user_struct {
extern struct user_struct root_user;
#define INIT_USER (&root_user)
-typedef struct task_struct task_t;
typedef struct prio_array prio_array_t;
struct task_struct {
@@ -251,7 +255,10 @@ struct task_struct {
prio_array_t *array;
unsigned int time_slice;
- unsigned long sleep_jtime;
+
+ #define MAX_SLEEP_AVG (2*HZ)
+ unsigned long sleep_avg;
+ unsigned long sleep_timestamp;
unsigned long policy;
unsigned long cpus_allowed;
@@ -390,30 +397,47 @@ struct task_struct {
* them out at 128 to make it easier to search the
* scheduler bitmap.
*/
-#define MAX_RT_PRIO 128
+#define MAX_RT_PRIO 128
/*
* The lower the priority of a process, the more likely it is
* to run. Priority of a process goes from 0 to 167. The 0-99
* priority range is allocated to RT tasks, the 128-167 range
* is for SCHED_OTHER tasks.
*/
-#define MAX_PRIO (MAX_RT_PRIO+40)
-#define DEF_USER_NICE 0
+#define MAX_PRIO (MAX_RT_PRIO + 40)
/*
- * Default timeslice is 80 msecs, maximum is 160 msecs.
+ * Scales user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ 128 ... 167 (MAX_PRIO-1) ]
+ *
+ * User-nice value of -20 == static priority 128, and
+ * user-nice value 19 == static priority 167. The lower
+ * the priority value, the higher the task's priority.
+ */
+#define NICE_TO_PRIO(n) (MAX_RT_PRIO + (n) + 20)
+#define DEF_USER_NICE 0
+
+/*
+ * Default timeslice is 90 msecs, maximum is 180 msecs.
* Minimum timeslice is 10 msecs.
*/
-#define MIN_TIMESLICE (10 * HZ / 1000)
-#define MAX_TIMESLICE (160 * HZ / 1000)
+#define MIN_TIMESLICE ( 10 * HZ / 1000)
+#define MAX_TIMESLICE (180 * HZ / 1000)
-#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
-#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
-#define DEF_PRIO (MAX_RT_PRIO + MAX_USER_PRIO / 3)
-#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19)
+#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
+#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
-#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
- ((MAX_TIMESLICE - MIN_TIMESLICE) * (19 - (n))) / 39)
+/*
+ * NICE_TO_TIMESLICE scales nice values [ -20 ... 19 ]
+ * to time slice values.
+ *
+ * The higher a process's priority, the bigger timeslices
+ * it gets during one round of execution. But even the lowest
+ * priority process gets MIN_TIMESLICE worth of execution time.
+ */
+
+#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
+ ((MAX_TIMESLICE - MIN_TIMESLICE) * (19-(n))) / 39)
extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
extern void set_user_nice(task_t *p, long nice);
@@ -542,6 +566,17 @@ static inline int signal_pending(struct task_struct *p)
{
return (p->sigpending != 0);
}
+
+static inline int need_resched(void)
+{
+ return unlikely(current->need_resched != 0);
+}
+
+static inline void cond_resched(void)
+{
+ if (need_resched())
+ schedule();
+}
/*
* Re-calculate pending state from the set of locally pending
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 070eef7b5..183b1e49d 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -28,7 +28,7 @@ struct shmem_inode_info {
unsigned long swapped;
int locked; /* into memory */
struct list_head list;
- struct inode *inode;
+ struct inode vfs_inode;
};
struct shmem_sb_info {
@@ -39,6 +39,9 @@ struct shmem_sb_info {
spinlock_t stat_lock;
};
-#define SHMEM_I(inode) (&inode->u.shmem_i)
+static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
+{
+ return list_entry(inode, struct shmem_inode_info, vfs_inode);
+}
#endif
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index f776030c8..609d0dab2 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -223,7 +223,7 @@
#define UFS_MAXNAMLEN 255
#define UFS_MAXMNTLEN 512
-#define UFS_MAXCSBUFS 31
+/* #define UFS_MAXCSBUFS 31 */
#define UFS_LINK_MAX 32000
/*
@@ -508,6 +508,218 @@ struct ufs_inode {
#define UFS_SF_APPEND 0x00040000 /* append-only */
#define UFS_SF_NOUNLINK 0x00100000 /* can't be removed or renamed */
+/*
+ * This structure is used for reading disk structures larger
+ * than the size of fragment.
+ */
+struct ufs_buffer_head {
+ unsigned fragment; /* first fragment */
+ unsigned count; /* number of fragments */
+ struct buffer_head * bh[UFS_MAXFRAG]; /* buffers */
+};
+
+struct ufs_cg_private_info {
+ struct ufs_cylinder_group ucg;
+ __u32 c_cgx; /* number of cylidner group */
+ __u16 c_ncyl; /* number of cyl's this cg */
+ __u16 c_niblk; /* number of inode blocks this cg */
+ __u32 c_ndblk; /* number of data blocks this cg */
+ __u32 c_rotor; /* position of last used block */
+ __u32 c_frotor; /* position of last used frag */
+ __u32 c_irotor; /* position of last used inode */
+ __u32 c_btotoff; /* (__u32) block totals per cylinder */
+ __u32 c_boff; /* (short) free block positions */
+ __u32 c_iusedoff; /* (char) used inode map */
+ __u32 c_freeoff; /* (u_char) free block map */
+ __u32 c_nextfreeoff; /* (u_char) next available space */
+ __u32 c_clustersumoff;/* (u_int32) counts of avail clusters */
+ __u32 c_clusteroff; /* (u_int8) free cluster map */
+ __u32 c_nclusterblks; /* number of clusters this cg */
+};
+
+struct ufs_sb_private_info {
+ struct ufs_buffer_head s_ubh; /* buffer containing super block */
+ __u32 s_sblkno; /* offset of super-blocks in filesys */
+ __u32 s_cblkno; /* offset of cg-block in filesys */
+ __u32 s_iblkno; /* offset of inode-blocks in filesys */
+ __u32 s_dblkno; /* offset of first data after cg */
+ __u32 s_cgoffset; /* cylinder group offset in cylinder */
+ __u32 s_cgmask; /* used to calc mod fs_ntrak */
+ __u32 s_size; /* number of blocks (fragments) in fs */
+ __u32 s_dsize; /* number of data blocks in fs */
+ __u32 s_ncg; /* number of cylinder groups */
+ __u32 s_bsize; /* size of basic blocks */
+ __u32 s_fsize; /* size of fragments */
+ __u32 s_fpb; /* fragments per block */
+ __u32 s_minfree; /* minimum percentage of free blocks */
+ __u32 s_bmask; /* `blkoff'' calc of blk offsets */
+ __u32 s_fmask; /* s_fsize mask */
+ __u32 s_bshift; /* `lblkno'' calc of logical blkno */
+ __u32 s_fshift; /* s_fsize shift */
+ __u32 s_fpbshift; /* fragments per block shift */
+ __u32 s_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ __u32 s_sbsize; /* actual size of super block */
+ __u32 s_csmask; /* csum block offset */
+ __u32 s_csshift; /* csum block number */
+ __u32 s_nindir; /* value of NINDIR */
+ __u32 s_inopb; /* value of INOPB */
+ __u32 s_nspf; /* value of NSPF */
+ __u32 s_npsect; /* # sectors/track including spares */
+ __u32 s_interleave; /* hardware sector interleave */
+ __u32 s_trackskew; /* sector 0 skew, per track */
+ __u32 s_csaddr; /* blk addr of cyl grp summary area */
+ __u32 s_cssize; /* size of cyl grp summary area */
+ __u32 s_cgsize; /* cylinder group size */
+ __u32 s_ntrak; /* tracks per cylinder */
+ __u32 s_nsect; /* sectors per track */
+ __u32 s_spc; /* sectors per cylinder */
+ __u32 s_ipg; /* inodes per group */
+ __u32 s_fpg; /* fragments per group */
+ __u32 s_cpc; /* cyl per cycle in postbl */
+ __s32 s_contigsumsize;/* size of cluster summary array, 44bsd */
+ __s64 s_qbmask; /* ~usb_bmask */
+ __s64 s_qfmask; /* ~usb_fmask */
+ __s32 s_postblformat; /* format of positional layout tables */
+ __s32 s_nrpos; /* number of rotational positions */
+ __s32 s_postbloff; /* (__s16) rotation block list head */
+ __s32 s_rotbloff; /* (__u8) blocks for each rotation */
+
+ __u32 s_fpbmask; /* fragments per block mask */
+ __u32 s_apb; /* address per block */
+ __u32 s_2apb; /* address per block^2 */
+ __u32 s_3apb; /* address per block^3 */
+ __u32 s_apbmask; /* address per block mask */
+ __u32 s_apbshift; /* address per block shift */
+ __u32 s_2apbshift; /* address per block shift * 2 */
+ __u32 s_3apbshift; /* address per block shift * 3 */
+ __u32 s_nspfshift; /* number of sector per fragment shift */
+ __u32 s_nspb; /* number of sector per block */
+ __u32 s_inopf; /* inodes per fragment */
+ __u32 s_sbbase; /* offset of NeXTstep superblock */
+ __u32 s_bpf; /* bits per fragment */
+ __u32 s_bpfshift; /* bits per fragment shift*/
+ __u32 s_bpfmask; /* bits per fragment mask */
+
+ __u32 s_maxsymlinklen;/* upper limit on fast symlinks' size */
+};
+
+/*
+ * Sizes of this structures are:
+ * ufs_super_block_first 512
+ * ufs_super_block_second 512
+ * ufs_super_block_third 356
+ */
+struct ufs_super_block_first {
+ __u32 fs_link;
+ __u32 fs_rlink;
+ __u32 fs_sblkno;
+ __u32 fs_cblkno;
+ __u32 fs_iblkno;
+ __u32 fs_dblkno;
+ __u32 fs_cgoffset;
+ __u32 fs_cgmask;
+ __u32 fs_time;
+ __u32 fs_size;
+ __u32 fs_dsize;
+ __u32 fs_ncg;
+ __u32 fs_bsize;
+ __u32 fs_fsize;
+ __u32 fs_frag;
+ __u32 fs_minfree;
+ __u32 fs_rotdelay;
+ __u32 fs_rps;
+ __u32 fs_bmask;
+ __u32 fs_fmask;
+ __u32 fs_bshift;
+ __u32 fs_fshift;
+ __u32 fs_maxcontig;
+ __u32 fs_maxbpg;
+ __u32 fs_fragshift;
+ __u32 fs_fsbtodb;
+ __u32 fs_sbsize;
+ __u32 fs_csmask;
+ __u32 fs_csshift;
+ __u32 fs_nindir;
+ __u32 fs_inopb;
+ __u32 fs_nspf;
+ __u32 fs_optim;
+ union {
+ struct {
+ __u32 fs_npsect;
+ } fs_sun;
+ struct {
+ __s32 fs_state;
+ } fs_sunx86;
+ } fs_u1;
+ __u32 fs_interleave;
+ __u32 fs_trackskew;
+ __u32 fs_id[2];
+ __u32 fs_csaddr;
+ __u32 fs_cssize;
+ __u32 fs_cgsize;
+ __u32 fs_ntrak;
+ __u32 fs_nsect;
+ __u32 fs_spc;
+ __u32 fs_ncyl;
+ __u32 fs_cpg;
+ __u32 fs_ipg;
+ __u32 fs_fpg;
+ struct ufs_csum fs_cstotal;
+ __s8 fs_fmod;
+ __s8 fs_clean;
+ __s8 fs_ronly;
+ __s8 fs_flags;
+ __s8 fs_fsmnt[UFS_MAXMNTLEN - 212];
+
+};
+
+struct ufs_super_block_second {
+ __s8 fs_fsmnt[212];
+ __u32 fs_cgrotor;
+ __u32 fs_csp[UFS_MAXCSBUFS];
+ __u32 fs_maxcluster;
+ __u32 fs_cpc;
+ __u16 fs_opostbl[82];
+};
+
+struct ufs_super_block_third {
+ __u16 fs_opostbl[46];
+ union {
+ struct {
+ __s32 fs_sparecon[53];/* reserved for future constants */
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __s32 fs_state; /* file system state time stamp */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sun;
+ struct {
+ __s32 fs_sparecon[53];/* reserved for future constants */
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __u32 fs_npsect; /* # sectors/track including spares */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sunx86;
+ struct {
+ __s32 fs_sparecon[50];/* reserved for future constants */
+ __s32 fs_contigsumsize;/* size of cluster summary array */
+ __s32 fs_maxsymlinklen;/* max length of an internal symlink */
+ __s32 fs_inodefmt; /* format of on-disk inodes */
+ __u32 fs_maxfilesize[2]; /* max representable file size */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ __s32 fs_state; /* file system state time stamp */
+ } fs_44;
+ } fs_u2;
+ __s32 fs_postblformat;
+ __s32 fs_nrpos;
+ __s32 fs_postbloff;
+ __s32 fs_rotbloff;
+ __s32 fs_magic;
+ __u8 fs_space[1];
+};
+
#ifdef __KERNEL__
/* balloc.c */
@@ -539,7 +751,7 @@ extern struct address_space_operations ufs_aops;
/* ialloc.c */
extern void ufs_free_inode (struct inode *inode);
-extern struct inode * ufs_new_inode (const struct inode *, int);
+extern struct inode * ufs_new_inode (struct inode *, int);
/* inode.c */
extern int ufs_frag_map (struct inode *, int);
@@ -567,6 +779,13 @@ extern struct inode_operations ufs_fast_symlink_inode_operations;
/* truncate.c */
extern void ufs_truncate (struct inode *);
+#include <linux/ufs_fs_i.h>
+
+static inline struct ufs_inode_info *UFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct ufs_inode_info, vfs_inode);
+}
+
#endif /* __KERNEL__ */
#endif /* __LINUX_UFS_FS_H */
diff --git a/include/linux/ufs_fs_i.h b/include/linux/ufs_fs_i.h
index 5f0287ab0..1b7586441 100644
--- a/include/linux/ufs_fs_i.h
+++ b/include/linux/ufs_fs_i.h
@@ -26,6 +26,7 @@ struct ufs_inode_info {
__u32 i_oeftflag;
__u16 i_osync;
__u32 i_lastfrag;
+ struct inode vfs_inode;
};
#endif /* _LINUX_UFS_FS_I_H */
diff --git a/include/linux/ufs_fs_sb.h b/include/linux/ufs_fs_sb.h
index 41b6ccc1e..c1be4c226 100644
--- a/include/linux/ufs_fs_sb.h
+++ b/include/linux/ufs_fs_sb.h
@@ -14,107 +14,15 @@
#ifndef __LINUX_UFS_FS_SB_H
#define __LINUX_UFS_FS_SB_H
-#include <linux/ufs_fs.h>
-
-/*
- * This structure is used for reading disk structures larger
- * than the size of fragment.
- */
-struct ufs_buffer_head {
- unsigned fragment; /* first fragment */
- unsigned count; /* number of fragments */
- struct buffer_head * bh[UFS_MAXFRAG]; /* buffers */
-};
-
-struct ufs_cg_private_info {
- struct ufs_cylinder_group ucg;
- __u32 c_cgx; /* number of cylidner group */
- __u16 c_ncyl; /* number of cyl's this cg */
- __u16 c_niblk; /* number of inode blocks this cg */
- __u32 c_ndblk; /* number of data blocks this cg */
- __u32 c_rotor; /* position of last used block */
- __u32 c_frotor; /* position of last used frag */
- __u32 c_irotor; /* position of last used inode */
- __u32 c_btotoff; /* (__u32) block totals per cylinder */
- __u32 c_boff; /* (short) free block positions */
- __u32 c_iusedoff; /* (char) used inode map */
- __u32 c_freeoff; /* (u_char) free block map */
- __u32 c_nextfreeoff; /* (u_char) next available space */
- __u32 c_clustersumoff;/* (u_int32) counts of avail clusters */
- __u32 c_clusteroff; /* (u_int8) free cluster map */
- __u32 c_nclusterblks; /* number of clusters this cg */
-};
-
-struct ufs_sb_private_info {
- struct ufs_buffer_head s_ubh; /* buffer containing super block */
- __u32 s_sblkno; /* offset of super-blocks in filesys */
- __u32 s_cblkno; /* offset of cg-block in filesys */
- __u32 s_iblkno; /* offset of inode-blocks in filesys */
- __u32 s_dblkno; /* offset of first data after cg */
- __u32 s_cgoffset; /* cylinder group offset in cylinder */
- __u32 s_cgmask; /* used to calc mod fs_ntrak */
- __u32 s_size; /* number of blocks (fragments) in fs */
- __u32 s_dsize; /* number of data blocks in fs */
- __u32 s_ncg; /* number of cylinder groups */
- __u32 s_bsize; /* size of basic blocks */
- __u32 s_fsize; /* size of fragments */
- __u32 s_fpb; /* fragments per block */
- __u32 s_minfree; /* minimum percentage of free blocks */
- __u32 s_bmask; /* `blkoff'' calc of blk offsets */
- __u32 s_fmask; /* s_fsize mask */
- __u32 s_bshift; /* `lblkno'' calc of logical blkno */
- __u32 s_fshift; /* s_fsize shift */
- __u32 s_fpbshift; /* fragments per block shift */
- __u32 s_fsbtodb; /* fsbtodb and dbtofsb shift constant */
- __u32 s_sbsize; /* actual size of super block */
- __u32 s_csmask; /* csum block offset */
- __u32 s_csshift; /* csum block number */
- __u32 s_nindir; /* value of NINDIR */
- __u32 s_inopb; /* value of INOPB */
- __u32 s_nspf; /* value of NSPF */
- __u32 s_npsect; /* # sectors/track including spares */
- __u32 s_interleave; /* hardware sector interleave */
- __u32 s_trackskew; /* sector 0 skew, per track */
- __u32 s_csaddr; /* blk addr of cyl grp summary area */
- __u32 s_cssize; /* size of cyl grp summary area */
- __u32 s_cgsize; /* cylinder group size */
- __u32 s_ntrak; /* tracks per cylinder */
- __u32 s_nsect; /* sectors per track */
- __u32 s_spc; /* sectors per cylinder */
- __u32 s_ipg; /* inodes per group */
- __u32 s_fpg; /* fragments per group */
- __u32 s_cpc; /* cyl per cycle in postbl */
- __s32 s_contigsumsize;/* size of cluster summary array, 44bsd */
- __s64 s_qbmask; /* ~usb_bmask */
- __s64 s_qfmask; /* ~usb_fmask */
- __s32 s_postblformat; /* format of positional layout tables */
- __s32 s_nrpos; /* number of rotational positions */
- __s32 s_postbloff; /* (__s16) rotation block list head */
- __s32 s_rotbloff; /* (__u8) blocks for each rotation */
-
- __u32 s_fpbmask; /* fragments per block mask */
- __u32 s_apb; /* address per block */
- __u32 s_2apb; /* address per block^2 */
- __u32 s_3apb; /* address per block^3 */
- __u32 s_apbmask; /* address per block mask */
- __u32 s_apbshift; /* address per block shift */
- __u32 s_2apbshift; /* address per block shift * 2 */
- __u32 s_3apbshift; /* address per block shift * 3 */
- __u32 s_nspfshift; /* number of sector per fragment shift */
- __u32 s_nspb; /* number of sector per block */
- __u32 s_inopf; /* inodes per fragment */
- __u32 s_sbbase; /* offset of NeXTstep superblock */
- __u32 s_bpf; /* bits per fragment */
- __u32 s_bpfshift; /* bits per fragment shift*/
- __u32 s_bpfmask; /* bits per fragment mask */
-
- __u32 s_maxsymlinklen;/* upper limit on fast symlinks' size */
-};
-
#define UFS_MAX_GROUP_LOADED 8
#define UFS_CGNO_EMPTY ((unsigned)-1)
+struct ufs_sb_private_info;
+struct ufs_cg_private_info;
+struct ufs_csum;
+#define UFS_MAXCSBUFS 31
+
struct ufs_sb_info {
struct ufs_sb_private_info * s_uspi;
struct ufs_csum * s_csp[UFS_MAXCSBUFS];
@@ -127,121 +35,4 @@ struct ufs_sb_info {
unsigned s_mount_opt;
};
-/*
- * Sizes of this structures are:
- * ufs_super_block_first 512
- * ufs_super_block_second 512
- * ufs_super_block_third 356
- */
-struct ufs_super_block_first {
- __u32 fs_link;
- __u32 fs_rlink;
- __u32 fs_sblkno;
- __u32 fs_cblkno;
- __u32 fs_iblkno;
- __u32 fs_dblkno;
- __u32 fs_cgoffset;
- __u32 fs_cgmask;
- __u32 fs_time;
- __u32 fs_size;
- __u32 fs_dsize;
- __u32 fs_ncg;
- __u32 fs_bsize;
- __u32 fs_fsize;
- __u32 fs_frag;
- __u32 fs_minfree;
- __u32 fs_rotdelay;
- __u32 fs_rps;
- __u32 fs_bmask;
- __u32 fs_fmask;
- __u32 fs_bshift;
- __u32 fs_fshift;
- __u32 fs_maxcontig;
- __u32 fs_maxbpg;
- __u32 fs_fragshift;
- __u32 fs_fsbtodb;
- __u32 fs_sbsize;
- __u32 fs_csmask;
- __u32 fs_csshift;
- __u32 fs_nindir;
- __u32 fs_inopb;
- __u32 fs_nspf;
- __u32 fs_optim;
- union {
- struct {
- __u32 fs_npsect;
- } fs_sun;
- struct {
- __s32 fs_state;
- } fs_sunx86;
- } fs_u1;
- __u32 fs_interleave;
- __u32 fs_trackskew;
- __u32 fs_id[2];
- __u32 fs_csaddr;
- __u32 fs_cssize;
- __u32 fs_cgsize;
- __u32 fs_ntrak;
- __u32 fs_nsect;
- __u32 fs_spc;
- __u32 fs_ncyl;
- __u32 fs_cpg;
- __u32 fs_ipg;
- __u32 fs_fpg;
- struct ufs_csum fs_cstotal;
- __s8 fs_fmod;
- __s8 fs_clean;
- __s8 fs_ronly;
- __s8 fs_flags;
- __s8 fs_fsmnt[UFS_MAXMNTLEN - 212];
-
-};
-
-struct ufs_super_block_second {
- __s8 fs_fsmnt[212];
- __u32 fs_cgrotor;
- __u32 fs_csp[UFS_MAXCSBUFS];
- __u32 fs_maxcluster;
- __u32 fs_cpc;
- __u16 fs_opostbl[82];
-};
-
-struct ufs_super_block_third {
- __u16 fs_opostbl[46];
- union {
- struct {
- __s32 fs_sparecon[53];/* reserved for future constants */
- __s32 fs_reclaim;
- __s32 fs_sparecon2[1];
- __s32 fs_state; /* file system state time stamp */
- __u32 fs_qbmask[2]; /* ~usb_bmask */
- __u32 fs_qfmask[2]; /* ~usb_fmask */
- } fs_sun;
- struct {
- __s32 fs_sparecon[53];/* reserved for future constants */
- __s32 fs_reclaim;
- __s32 fs_sparecon2[1];
- __u32 fs_npsect; /* # sectors/track including spares */
- __u32 fs_qbmask[2]; /* ~usb_bmask */
- __u32 fs_qfmask[2]; /* ~usb_fmask */
- } fs_sunx86;
- struct {
- __s32 fs_sparecon[50];/* reserved for future constants */
- __s32 fs_contigsumsize;/* size of cluster summary array */
- __s32 fs_maxsymlinklen;/* max length of an internal symlink */
- __s32 fs_inodefmt; /* format of on-disk inodes */
- __u32 fs_maxfilesize[2]; /* max representable file size */
- __u32 fs_qbmask[2]; /* ~usb_bmask */
- __u32 fs_qfmask[2]; /* ~usb_fmask */
- __s32 fs_state; /* file system state time stamp */
- } fs_44;
- } fs_u2;
- __s32 fs_postblformat;
- __s32 fs_nrpos;
- __s32 fs_postbloff;
- __s32 fs_rotbloff;
- __s32 fs_magic;
- __u8 fs_space[1];
-};
-
-#endif /* __LINUX_UFS_FS_SB_H */
+#endif
diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p
index 2752cb004..99e6eefa8 100644
--- a/include/linux/umsdos_fs.p
+++ b/include/linux/umsdos_fs.p
@@ -93,3 +93,8 @@ int UMSDOS_rename (struct inode *old_dir,
/* rdir.c 22/03/95 03.31.42 */
struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
+
+static inline struct umsdos_inode_info *UMSDOS_I(struct inode *inode)
+{
+ return &inode->u.umsdos_i;
+}
diff --git a/include/linux/usb.h b/include/linux/usb.h
index d53844b91..5309034e5 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -576,13 +576,12 @@ extern void usb_deregister(struct usb_driver *);
/* ... less overhead for QUEUE_BULK */
#define USB_TIMEOUT_KILLED 0x1000 /* only set by HCD! */
-typedef struct
-{
+struct usb_iso_packet_descriptor {
unsigned int offset;
unsigned int length; /* expected length */
unsigned int actual_length;
unsigned int status;
-} iso_packet_descriptor_t;
+};
struct urb;
@@ -741,11 +740,9 @@ struct urb
int timeout; /* (in) timeout, in jiffies */
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
- iso_packet_descriptor_t iso_frame_desc[0]; /* (in) ISO ONLY */
+ struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */
};
-typedef struct urb urb_t;
-
/**
* usb_fill_control_urb - initializes a control urb
* @urb: pointer to the urb to initialize.
diff --git a/include/linux/usbdev_fs_i.h b/include/linux/usbdev_fs_i.h
deleted file mode 100644
index 13bfad540..000000000
--- a/include/linux/usbdev_fs_i.h
+++ /dev/null
@@ -1,11 +0,0 @@
-struct usb_device;
-struct usb_bus;
-
-struct usbdev_inode_info {
- struct list_head dlist;
- struct list_head slist;
- union {
- struct usb_device *dev;
- struct usb_bus *bus;
- } p;
-};
diff --git a/include/linux/usbdev_fs_sb.h b/include/linux/usbdev_fs_sb.h
deleted file mode 100644
index 6027b1a20..000000000
--- a/include/linux/usbdev_fs_sb.h
+++ /dev/null
@@ -1,13 +0,0 @@
-struct usbdev_sb_info {
- struct list_head slist;
- struct list_head ilist;
- uid_t devuid;
- gid_t devgid;
- umode_t devmode;
- uid_t busuid;
- gid_t busgid;
- umode_t busmode;
- uid_t listuid;
- gid_t listgid;
- umode_t listmode;
-};
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 3fe8709b4..fa3c64f78 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -1,9 +1,10 @@
/*
* This file define a set of standard wireless extensions
*
- * Version : 12 5.10.01
+ * Version : 13 6.12.01
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
*/
#ifndef _LINUX_WIRELESS_H
@@ -11,6 +12,8 @@
/************************** DOCUMENTATION **************************/
/*
+ * Initial APIs (1996 -> onward) :
+ * -----------------------------
* Basically, the wireless extensions are for now a set of standard ioctl
* call + /proc/net/wireless
*
@@ -27,16 +30,27 @@
* We have the list of command plus a structure descibing the
* data exchanged...
* Note that to add these ioctl, I was obliged to modify :
- * net/core/dev.c (two place + add include)
- * net/ipv4/af_inet.c (one place + add include)
+ * # net/core/dev.c (two place + add include)
+ * # net/ipv4/af_inet.c (one place + add include)
*
* /proc/net/wireless is a copy of /proc/net/dev.
* We have a structure for data passed from the driver to /proc/net/wireless
* Too add this, I've modified :
- * net/core/dev.c (two other places)
- * include/linux/netdevice.h (one place)
- * include/linux/proc_fs.h (one place)
+ * # net/core/dev.c (two other places)
+ * # include/linux/netdevice.h (one place)
+ * # include/linux/proc_fs.h (one place)
*
+ * New driver API (2001 -> onward) :
+ * -------------------------------
+ * This file is only concerned with the user space API and common definitions.
+ * The new driver API is defined and documented in :
+ * # include/net/iw_handler.h
+ *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+ * # include/linux/wireless.c
+ *
+ * Other comments :
+ * --------------
* Do not add here things that are redundant with other mechanisms
* (drivers init, ifconfig, /proc/net/dev, ...) and with are not
* wireless specific.
@@ -54,16 +68,14 @@
#include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/if.h> /* for IFNAMSIZ and co... */
-/**************************** CONSTANTS ****************************/
-
-/* --------------------------- VERSION --------------------------- */
+/***************************** VERSION *****************************/
/*
* This constant is used to know the availability of the wireless
* extensions and to know which version of wireless extensions it is
* (there is some stuff that will be added in the future...)
* I just plan to increment with each new version.
*/
-#define WIRELESS_EXT 12
+#define WIRELESS_EXT 13
/*
* Changes :
@@ -123,12 +135,20 @@
* - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
* - Add new statistics (frag, retry, beacon)
* - Add average quality (for user space calibration)
+ *
+ * V12 to V13
+ * ----------
+ * - Document creation of new driver API.
+ * - Extract union iwreq_data from struct iwreq (for new driver API).
+ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT
*/
+/**************************** CONSTANTS ****************************/
+
/* -------------------------- IOCTL LIST -------------------------- */
/* Basic operations */
-#define SIOCSIWNAME 0x8B00 /* Unused */
+#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */
#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */
#define SIOCGIWNWID 0x8B03 /* get network id */
@@ -414,13 +434,49 @@ struct iw_statistics
/* ------------------------ IOCTL REQUEST ------------------------ */
/*
+ * This structure defines the payload of an ioctl, and is used
+ * below.
+ *
+ * Note that this structure should fit on the memory footprint
+ * of iwreq (which is the same as ifreq), which mean a max size of
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * You should check this when increasing the structures defined
+ * above in this file...
+ */
+union iwreq_data
+{
+ /* Config - generic */
+ char name[IFNAMSIZ];
+ /* Name : used to verify the presence of wireless extensions.
+ * Name of the protocol/provider... */
+
+ struct iw_point essid; /* Extended network name */
+ struct iw_param nwid; /* network id (or domain - the cell) */
+ struct iw_freq freq; /* frequency or channel :
+ * 0-1000 = channel
+ * > 1000 = frequency in Hz */
+
+ struct iw_param sens; /* signal level threshold */
+ struct iw_param bitrate; /* default bit rate */
+ struct iw_param txpower; /* default transmit power */
+ struct iw_param rts; /* RTS threshold threshold */
+ struct iw_param frag; /* Fragmentation threshold */
+ __u32 mode; /* Operation mode */
+ struct iw_param retry; /* Retry limits & lifetime */
+
+ struct iw_point encoding; /* Encoding stuff : tokens */
+ struct iw_param power; /* PM duration/timeout */
+
+ struct sockaddr ap_addr; /* Access point address */
+
+ struct iw_point data; /* Other large parameters */
+};
+
+/*
* The structure to exchange data for ioctl.
* This structure is the same as 'struct ifreq', but (re)defined for
* convenience...
- *
- * Note that it should fit on the same memory footprint !
- * You should check this when increasing the above structures (16 octets)
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * Do I need to remind you about structure size (32 octets) ?
*/
struct iwreq
{
@@ -429,35 +485,8 @@ struct iwreq
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
} ifr_ifrn;
- /* Data part */
- union
- {
- /* Config - generic */
- char name[IFNAMSIZ];
- /* Name : used to verify the presence of wireless extensions.
- * Name of the protocol/provider... */
-
- struct iw_point essid; /* Extended network name */
- struct iw_param nwid; /* network id (or domain - the cell) */
- struct iw_freq freq; /* frequency or channel :
- * 0-1000 = channel
- * > 1000 = frequency in Hz */
-
- struct iw_param sens; /* signal level threshold */
- struct iw_param bitrate; /* default bit rate */
- struct iw_param txpower; /* default transmit power */
- struct iw_param rts; /* RTS threshold threshold */
- struct iw_param frag; /* Fragmentation threshold */
- __u32 mode; /* Operation mode */
- struct iw_param retry; /* Retry limits & lifetime */
-
- struct iw_point encoding; /* Encoding stuff : tokens */
- struct iw_param power; /* PM duration/timeout */
-
- struct sockaddr ap_addr; /* Access point address */
-
- struct iw_point data; /* Other large parameters */
- } u;
+ /* Data part (defined just above) */
+ union iwreq_data u;
};
/* -------------------------- IOCTL DATA -------------------------- */
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
new file mode 100644
index 000000000..7151337ee
--- /dev/null
+++ b/include/net/iw_handler.h
@@ -0,0 +1,374 @@
+/*
+ * This file define the new driver API for Wireless Extensions
+ *
+ * Version : 2 6.12.01
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
+ */
+
+#ifndef _IW_HANDLER_H
+#define _IW_HANDLER_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Initial driver API (1996 -> onward) :
+ * -----------------------------------
+ * The initial API just sends the IOCTL request received from user space
+ * to the driver (via the driver ioctl handler). The driver has to
+ * handle all the rest...
+ *
+ * The initial API also defines a specific handler in struct net_device
+ * to handle wireless statistics.
+ *
+ * The initial APIs served us well and has proven a reasonably good design.
+ * However, there is a few shortcommings :
+ * o No events, everything is a request to the driver.
+ * o Large ioctl function in driver with gigantic switch statement
+ * (i.e. spaghetti code).
+ * o Driver has to mess up with copy_to/from_user, and in many cases
+ * does it unproperly. Common mistakes are :
+ * * buffer overflows (no checks or off by one checks)
+ * * call copy_to/from_user with irq disabled
+ * o The user space interface is tied to ioctl because of the use
+ * copy_to/from_user.
+ *
+ * New driver API (2001 -> onward) :
+ * -------------------------------
+ * The new driver API is just a bunch of standard functions (handlers),
+ * each handling a specific Wireless Extension. The driver just export
+ * the list of handler it supports, and those will be called apropriately.
+ *
+ * I tried to keep the main advantage of the previous API (simplicity,
+ * efficiency and light weight), and also I provide a good dose of backward
+ * compatibility (most structures are the same, driver can use both API
+ * simultaneously, ...).
+ * Hopefully, I've also addressed the shortcomming of the initial API.
+ *
+ * The advantage of the new API are :
+ * o Handling of Extensions in driver broken in small contained functions
+ * o Tighter checks of ioctl before calling the driver
+ * o Flexible commit strategy (at least, the start of it)
+ * o Backward compatibility (can be mixed with old API)
+ * o Driver doesn't have to worry about memory and user-space issues
+ * The last point is important for the following reasons :
+ * o You are now able to call the new driver API from any API you
+ * want (including from within other parts of the kernel).
+ * o Common mistakes are avoided (buffer overflow, user space copy
+ * with irq disabled and so on).
+ *
+ * The Drawback of the new API are :
+ * o bloat (especially kernel)
+ * o need to migrate existing drivers to new API
+ * My initial testing shows that the new API adds around 3kB to the kernel
+ * and save between 0 and 5kB from a typical driver.
+ * Also, as all structures and data types are unchanged, the migration is
+ * quite straightforward (but tedious).
+ *
+ * ---
+ *
+ * The new driver API is defined below in this file. User space should
+ * not be aware of what's happening down there...
+ *
+ * A new kernel wrapper is in charge of validating the IOCTLs and calling
+ * the appropriate driver handler. This is implemented in :
+ * # net/core/wireless.c
+ *
+ * The driver export the list of handlers in :
+ * # include/linux/netdevice.h (one place)
+ *
+ * The new driver API is available for WIRELESS_EXT >= 13.
+ * Good luck with migration to the new API ;-)
+ */
+
+/* ---------------------- THE IMPLEMENTATION ---------------------- */
+/*
+ * Some of the choice I've made are pretty controversials. Defining an
+ * API is very much weighting compromises. This goes into some of the
+ * details and the thinking behind the implementation.
+ *
+ * Implementation goals :
+ * --------------------
+ * The implementation goals were as follow :
+ * o Obvious : you should not need a PhD to understand what's happening,
+ * the benefit is easier maintainance.
+ * o Flexible : it should accomodate a wide variety of driver
+ * implementations and be as flexible as the old API.
+ * o Lean : it should be efficient memory wise to minimise the impact
+ * on kernel footprint.
+ * o Transparent to user space : the large number of user space
+ * applications that use Wireless Extensions should not need
+ * any modifications.
+ *
+ * Array of functions versus Struct of functions
+ * ---------------------------------------------
+ * 1) Having an array of functions allow the kernel code to access the
+ * handler in a single lookup, which is much more efficient (think hash
+ * table here).
+ * 2) The only drawback is that driver writer may put their handler in
+ * the wrong slot. This is trivial to test (I set the frequency, the
+ * bitrate changes). Once the handler is in the proper slot, it will be
+ * there forever, because the array is only extended at the end.
+ * 3) Backward/forward compatibility : adding new handler just require
+ * extending the array, so you can put newer driver in older kernel
+ * without having to patch the kernel code (and vice versa).
+ *
+ * All handler are of the same generic type
+ * ----------------------------------------
+ * That's a feature !!!
+ * 1) Having a generic handler allow to have generic code, which is more
+ * efficient. If each of the handler was individually typed I would need
+ * to add a big switch in the kernel (== more bloat). This solution is
+ * more scalable, adding new Wireless Extensions doesn't add new code.
+ * 2) You can use the same handler in different slots of the array. For
+ * hardware, it may be more efficient or logical to handle multiple
+ * Wireless Extensions with a single function, and the API allow you to
+ * do that. (An example would be a single record on the card to control
+ * both bitrate and frequency, the handler would read the old record,
+ * modify it according to info->cmd and rewrite it).
+ *
+ * Functions prototype uses union iwreq_data
+ * -----------------------------------------
+ * Some would have prefered functions defined this way :
+ * static int mydriver_ioctl_setrate(struct net_device *dev,
+ * long rate, int auto)
+ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
+ * can't do it (different hardware may have different notion of what a
+ * valid frequency is), so we don't pretend that we do it.
+ * 2) The above form is not extendable. If I want to add a flag (for
+ * example to distinguish setting max rate and basic rate), I would
+ * break the prototype. Using iwreq_data is more flexible.
+ * 3) Also, the above form is not generic (see above).
+ * 4) I don't expect driver developper using the wrong field of the
+ * union (Doh !), so static typechecking doesn't add much value.
+ * 5) Lastly, you can skip the union by doing :
+ * static int mydriver_ioctl_setrate(struct net_device *dev,
+ * struct iw_request_info *info,
+ * struct iw_param *rrq,
+ * char *extra)
+ * And then adding the handler in the array like this :
+ * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE
+ *
+ * Using functions and not a registry
+ * ----------------------------------
+ * Another implementation option would have been for every instance to
+ * define a registry (a struct containing all the Wireless Extensions)
+ * and only have a function to commit the registry to the hardware.
+ * 1) This approach can be emulated by the current code, but not
+ * vice versa.
+ * 2) Some drivers don't keep any configuration in the driver, for them
+ * adding such a registry would be a significant bloat.
+ * 3) The code to translate from Wireless Extension to native format is
+ * needed anyway, so it would not reduce significantely the amount of code.
+ * 4) The current approach only selectively translate Wireless Extensions
+ * to native format and only selectively set, whereas the registry approach
+ * would require to translate all WE and set all parameters for any single
+ * change.
+ * 5) For many Wireless Extensions, the GET operation return the current
+ * dynamic value, not the value that was set.
+ *
+ * This header is <net/iw_handler.h>
+ * ---------------------------------
+ * 1) This header is kernel space only and should not be exported to
+ * user space. Headers in "include/linux/" are exported, headers in
+ * "include/net/" are not.
+ *
+ * Mixed 32/64 bit issues
+ * ----------------------
+ * The Wireless Extensions are designed to be 64 bit clean, by using only
+ * datatypes with explicit storage size.
+ * There are some issues related to kernel and user space using different
+ * memory model, and in particular 64bit kernel with 32bit user space.
+ * The problem is related to struct iw_point, that contains a pointer
+ * that *may* need to be translated.
+ * This is quite messy. The new API doesn't solve this problem (it can't),
+ * but is a step in the right direction :
+ * 1) Meta data about each ioctl is easily available, so we know what type
+ * of translation is needed.
+ * 2) The move of data between kernel and user space is only done in a single
+ * place in the kernel, so adding specific hooks in there is possible.
+ * 3) In the long term, it allows to move away from using ioctl as the
+ * user space API.
+ *
+ * So many comments and so few code
+ * --------------------------------
+ * That's a feature. Comments won't bloat the resulting kernel binary.
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/wireless.h> /* IOCTL user space API */
+
+/***************************** VERSION *****************************/
+/*
+ * This constant is used to know which version of the driver API is
+ * available. Hopefully, this will be pretty stable and no changes
+ * will be needed...
+ * I just plan to increment with each new version.
+ */
+#define IW_HANDLER_VERSION 2
+
+/**************************** CONSTANTS ****************************/
+
+/* Special error message for the driver to indicate that we
+ * should do a commit after return from the iw_handler */
+#define EIWCOMMIT EINPROGRESS
+
+/* Flags available in struct iw_request_info */
+#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */
+
+/* Type of headers we know about (basically union iwreq_data) */
+#define IW_HEADER_TYPE_NULL 0 /* Not available */
+#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
+#define IW_HEADER_TYPE_UINT 4 /* __u32 */
+#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
+#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */
+#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */
+#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */
+
+/* Handling flags */
+/* Most are not implemented. I just use them as a reminder of some
+ * cool features we might need one day ;-) */
+#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
+/* Wrapper level flags */
+#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
+#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
+#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */
+/* Driver level flags */
+#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
+
+/****************************** TYPES ******************************/
+
+/* ----------------------- WIRELESS HANDLER ----------------------- */
+/*
+ * A wireless handler is just a standard function, that looks like the
+ * ioctl handler.
+ * We also define there how a handler list look like... As the Wireless
+ * Extension space is quite dense, we use a simple array, which is faster
+ * (that's the perfect hash table ;-).
+ */
+
+/*
+ * Meta data about the request passed to the iw_handler.
+ * Most handlers can safely ignore what's in there.
+ * The 'cmd' field might come handy if you want to use the same handler
+ * for multiple command...
+ * This struct is also my long term insurance. I can add new fields here
+ * without breaking the prototype of iw_handler...
+ */
+struct iw_request_info
+{
+ __u16 cmd; /* Wireless Extension command */
+ __u16 flags; /* More to come ;-) */
+};
+
+/*
+ * This is how a function handling a Wireless Extension should look
+ * like (both get and set, standard and private).
+ */
+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+
+/*
+ * This define all the handler that the driver export.
+ * As you need only one per driver type, please use a static const
+ * shared by all driver instances... Same for the members...
+ * This will be linked from net_device in <linux/netdevice.h>
+ */
+struct iw_handler_def
+{
+ /* Number of handlers defined (more precisely, index of the
+ * last defined handler + 1) */
+ __u16 num_standard;
+ __u16 num_private;
+ /* Number of private arg description */
+ __u16 num_private_args;
+
+ /* Array of handlers for standard ioctls
+ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
+ */
+ iw_handler * standard;
+
+ /* Array of handlers for private ioctls
+ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
+ */
+ iw_handler * private;
+
+ /* Arguments of private handler. This one is just a list, so you
+ * can put it in any order you want and should not leave holes...
+ * We will automatically export that to user space... */
+ struct iw_priv_args * private_args;
+
+ /* In the long term, get_wireless_stats will move from
+ * 'struct net_device' to here, to minimise bloat. */
+};
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Currently we don't support events, so let's just plan for the
+ * future...
+ */
+
+/*
+ * A Wireless Event.
+ */
+// How do we define short header ? We don't want a flag on length.
+// Probably a flag on event ? Highest bit to zero...
+struct iw_event
+{
+ __u16 length; /* Lenght of this stuff */
+ __u16 event; /* Wireless IOCTL */
+ union iwreq_data header; /* IOCTL fixed payload */
+ char extra[0]; /* Optional IOCTL data */
+};
+
+/* ---------------------- IOCTL DESCRIPTION ---------------------- */
+/*
+ * One of the main goal of the new interface is to deal entirely with
+ * user space/kernel space memory move.
+ * For that, we need to know :
+ * o if iwreq is a pointer or contain the full data
+ * o what is the size of the data to copy
+ *
+ * For private IOCTLs, we use the same rules as used by iwpriv and
+ * defined in struct iw_priv_args.
+ *
+ * For standard IOCTLs, things are quite different and we need to
+ * use the stuctures below. Actually, this struct is also more
+ * efficient, but that's another story...
+ */
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+ __u8 header_type; /* NULL, iw_point or other */
+ __u8 token_type; /* Future */
+ __u16 token_size; /* Granularity of payload */
+ __u16 min_tokens; /* Min acceptable token number */
+ __u16 max_tokens; /* Max acceptable token number */
+ __u32 flags; /* Special handling of the request */
+};
+
+/* Need to think of short header translation table. Later. */
+
+/**************************** PROTOTYPES ****************************/
+/*
+ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
+ * Those may be called only within the kernel.
+ */
+
+/* First : function strictly used inside the kernel */
+
+/* Handle /proc/net/wireless, called in net/code/dev.c */
+extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+ int length);
+
+/* Handle IOCTLs, called in net/code/dev.c */
+extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+
+/* Second : functions that may be called by driver modules */
+/* None yet */
+
+#endif /* _LINUX_WIRELESS_H */
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 26ee7fea2..20624abce 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -11,78 +11,71 @@ Original driver (sg.h):
Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2001 Douglas Gilbert
- Version: 3.1.20 (20010814)
- This version is for 2.4 series kernels.
-
- Changes since 3.1.19 (20010623)
- - add SG_GET_ACCESS_COUNT ioctl
- - make open() increment and close() decrement access_count
- - only register first 256 devices, reject subsequent devices
- Changes since 3.1.18 (20010505)
- - fix bug that caused long wait when large buffer requested
- - fix leak in error case of sg_new_read() [report: Eric Barton]
- - add 'online' column to /proc/scsi/sg/devices
- Changes since 3.1.17 (20000921)
- - add CAP_SYS_RAWIO capability for sensitive stuff
- - compile in dio stuff, procfs 'allow_dio' defaulted off (0)
- - make premature close and detach more robust
- - lun masked into commands <= SCSI_2
- - poll() and async notification now yield POLL_HUP on detach
- - various 3rd party tweaks tracking lk 2.4 internal changes
+ Version: 3.5.23 (20011231)
+ This version is for 2.5 series kernels.
+
+ Changes since 3.1.22 (20011208)
+ - branch sg driver for lk 2.5 series
+ - remove lock_kernel() from sg_close()
+ - remove code based on scsi mid level dma pool
+ - change scatterlist 'address' to use page + offset
+ - add SG_INTERFACE_ID_ORIG
Map of SG verions to the Linux kernels in which they appear:
---------- ----------------------------------
original all kernels < 2.2.6
- 2.1.38 2.2.16
- 2.1.39 2.2.17 - 2.2.19
+ 2.1.40 2.2.20
3.0.x optional version 3 sg driver for 2.2 series
- 3.1.17 2.4.0 ++
+ 3.1.17++ 2.4.0++
+ 3.5.23++ 2.5.0++
Major new features in SG 3.x driver (cf SG 2.x drivers)
- SG_IO ioctl() combines function if write() and read()
- new interface (sg_io_hdr_t) but still supports old interface
- - scatter/gather in user space and direct IO supported
-
- The term "indirect IO" refers a method by which data is DMAed into kernel
- buffers from the hardware and afterwards is transferred into the user
- space (or vice versa if you are writing). Transfer speeds of up to 20 to
- 30MBytes/sec have been measured using indirect IO. For faster throughputs
- "direct IO" which cuts out the double handling of data is required.
- Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels
- and requires the use of the new interface.
-
- Requests for direct IO with the new interface will automatically fall back
- to indirect IO mode if they cannot be fulfilled. An example of such a case
- is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of
- memory due to the architecture of ISA. The 'info' field in the new
- interface indicates whether a direct or indirect data transfer took place.
-
- Obtaining memory for the kernel buffers used in indirect IO is done by
- first checking if the "reserved buffer" for the current file descriptor
- is available and large enough. If these conditions are _not_ met then
- kernel memory is obtained on a per SCSI command basis. This corresponds
- to a write(), read() sequence or a SG_IO ioctl() call. Further, the
- kernel memory that is suitable for DMA may be constrained by the
- architecture of the SCSI adapter (e.g. ISA adapters).
+ - scatter/gather in user space, direct IO, and mmap supported
+
+ The normal action of this driver is to use the adapter (HBA) driver to DMA
+ data into kernel buffers and then use the CPU to copy the data into the
+ user space (vice versa for writes). That is called "indirect" IO due to
+ the double handling of data. There are two methods offered to remove the
+ redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and
+ 2) using the mmap() system call to map the reserve buffer (this driver has
+ one reserve buffer per fd) into the user space. Both have their advantages.
+ In terms of absolute speed mmap() is faster. If speed is not a concern,
+ indirect IO should be fine. Read the documentation for more information.
** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
needed. That pseudo file's content is defaulted to 0. **
+
+ Historical note: this SCSI pass-through driver has been known as "sg" for
+ a decade. In broader kernel discussions "sg" is used to refer to scatter
+ gather techniques. The context should clarify which "sg" is referred to.
Documentation
=============
- A web site for SG device drivers can be found at:
+ A web site for the SG device driver can be found at:
http://www.torque.net/sg [alternatively check the MAINTAINERS file]
- The main documents are still based on 2.x versions:
+ The documentation for the sg version 3 driver can be found at:
+ http://www.torque.net/sg/p/sg_v3_ho.html
+ This is a rendering from DocBook source [change the extension to "sgml"
+ or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+
+ The older, version 2 documents discuss the original sg interface in detail:
http://www.torque.net/sg/p/scsi-generic.txt
http://www.torque.net/sg/p/scsi-generic_long.txt
- Documentation on the changes and additions in 3.x version of the sg driver
- can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
A version of this document (potentially out of date) may also be found in
the kernel source tree, probably at:
/usr/src/linux/Documentation/scsi-generic.txt .
- Utility and test programs are available at the sg web site.
+
+ Utility and test programs are available at the sg web site. They are
+ bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
+ lk 2.4 series).
+
+ There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
+ http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
*/
+
/* New interface introduced in the 3.x SG drivers follows */
typedef struct sg_iovec /* same structure as used by readv() Linux system */
@@ -119,20 +112,23 @@ typedef struct sg_io_hdr
unsigned int info; /* [o] auxiliary information */
} sg_io_hdr_t; /* 64 bytes long (on i386) */
+#define SG_INTERFACE_ID_ORIG 'S'
+
/* Use negative values to flag difference from original sg_header structure */
-#define SG_DXFER_NONE -1 /* e.g. a SCSI Test Unit Ready command */
-#define SG_DXFER_TO_DEV -2 /* e.g. a SCSI WRITE command */
-#define SG_DXFER_FROM_DEV -3 /* e.g. a SCSI READ command */
-#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the
+#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */
+#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */
+#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */
+#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
additional property than during indirect
IO the user buffer is copied into the
kernel buffers before the transfer */
-#define SG_DXFER_UNKNOWN -5 /* Unknown data direction */
+#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */
/* following flag values can be "or"-ed together */
#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */
-#define SG_FLAG_LUN_INHIBIT 2 /* default is to put device's lun into */
- /* the 2nd byte of SCSI command */
+#define SG_FLAG_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */
+ /* command block (when <= SCSI_2) */
+#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */
#define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
/* user space (debug indirect IO) */
diff --git a/init/main.c b/init/main.c
index f36a314cf..0f5ea3ee4 100644
--- a/init/main.c
+++ b/init/main.c
@@ -290,8 +290,6 @@ static void __init parse_options(char *line)
extern void setup_arch(char **);
extern void cpu_idle(void);
-unsigned long wait_init_idle;
-
#ifndef CONFIG_SMP
#ifdef CONFIG_X86_LOCAL_APIC
@@ -305,6 +303,16 @@ static void __init smp_init(void)
#else
+static unsigned long __initdata wait_init_idle;
+
+void __init idle_startup_done(void)
+{
+ clear_bit(smp_processor_id(), &wait_init_idle);
+ while (wait_init_idle) {
+ cpu_relax();
+ barrier();
+ }
+}
/* Called by boot processor to activate the rest. */
static void __init smp_init(void)
@@ -315,6 +323,7 @@ static void __init smp_init(void)
smp_threads_ready=1;
smp_commence();
+ idle_startup_done();
}
#endif
@@ -411,6 +420,7 @@ asmlinkage void __init start_kernel(void)
check_bugs();
printk("POSIX conformance testing by UNIFIX\n");
+ init_idle();
/*
* We count on the initial thread going ok
* Like idlers init is an unlocked kernel thread, which will
@@ -418,14 +428,6 @@ asmlinkage void __init start_kernel(void)
*/
smp_init();
- /*
- * Finally, we wait for all other CPU's, and initialize this
- * thread that will become the idle thread for the boot CPU.
- * After this, the scheduler is fully initialized, and we can
- * start creating and running new threads.
- */
- init_idle();
-
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 60dd04cb6..661f650e6 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -704,8 +704,9 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
* runqueue lock is not a problem.
*/
current->time_slice = 1;
- expire_task(current);
+ scheduler_tick(current);
}
+ p->sleep_timestamp = jiffies;
__restore_flags(flags);
if (p->policy == SCHED_OTHER)
@@ -746,23 +747,16 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
if (p->ptrace & PT_PTRACED)
send_sig(SIGSTOP, p, 1);
-#define RUN_CHILD_FIRST 1
-#if RUN_CHILD_FIRST
wake_up_forked_process(p); /* do this last */
-#else
- wake_up_process(p); /* do this last */
-#endif
++total_forks;
if (clone_flags & CLONE_VFORK)
wait_for_completion(&vfork);
-#if RUN_CHILD_FIRST
else
/*
* Let the child process run first, to avoid most of the
* COW overhead when the child exec()s afterwards.
*/
current->need_resched = 1;
-#endif
fork_out:
return retval;
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 64948098e..132e9971f 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -137,6 +137,7 @@ EXPORT_SYMBOL(igrab);
EXPORT_SYMBOL(iunique);
EXPORT_SYMBOL(iget4);
EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
EXPORT_SYMBOL(force_delete);
EXPORT_SYMBOL(follow_up);
EXPORT_SYMBOL(follow_down);
@@ -504,17 +505,16 @@ EXPORT_SYMBOL(si_meminfo);
/* Added to make file system as module */
EXPORT_SYMBOL(sys_tz);
EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_inode_buffers);
-EXPORT_SYMBOL(fsync_inode_data_buffers);
+EXPORT_SYMBOL(fsync_buffers_list);
EXPORT_SYMBOL(clear_inode);
EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode);
EXPORT_SYMBOL(read_ahead);
EXPORT_SYMBOL(__get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
EXPORT_SYMBOL(insert_inode_hash);
EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
+EXPORT_SYMBOL(buffer_insert_list);
EXPORT_SYMBOL(make_bad_inode);
EXPORT_SYMBOL(is_bad_inode);
EXPORT_SYMBOL(event);
diff --git a/kernel/printk.c b/kernel/printk.c
index 365aed1d3..00f07e116 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -524,7 +524,7 @@ void release_console_sem(void)
*/
void console_conditional_schedule(void)
{
- if (console_may_schedule && current->need_resched) {
+ if (console_may_schedule && need_resched()) {
set_current_state(TASK_RUNNING);
schedule();
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 4bf77db6f..7a8d2835e 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -21,9 +21,6 @@
#include <asm/mmu_context.h>
#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long))
-#define PRIO_INTERACTIVE (MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 3)
-#define TASK_INTERACTIVE(p) ((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
-#define JSLEEP_TO_PRIO(t) (((t) * 20) / HZ)
typedef struct runqueue runqueue_t;
@@ -40,41 +37,44 @@ struct prio_array {
*
* Locking rule: those places that want to lock multiple runqueues
* (such as the load balancing or the process migration code), lock
- * acquire operations must be ordered by rq->cpu.
- *
- * The RT event id is used to avoid calling into the the RT scheduler
- * if there is a RT task active in an SMP system but there is no
- * RT scheduling activity otherwise.
+ * acquire operations must be ordered by ascending &runqueue.
*/
-static struct runqueue {
- int cpu;
+struct runqueue {
spinlock_t lock;
unsigned long nr_running, nr_switches;
task_t *curr, *idle;
prio_array_t *active, *expired, arrays[2];
- char __pad [SMP_CACHE_BYTES];
-} runqueues [NR_CPUS] __cacheline_aligned;
+ int prev_nr_running[NR_CPUS];
+} ____cacheline_aligned;
+
+static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
-#define this_rq() (runqueues + smp_processor_id())
-#define task_rq(p) (runqueues + (p)->cpu)
#define cpu_rq(cpu) (runqueues + (cpu))
-#define cpu_curr(cpu) (runqueues[(cpu)].curr)
+#define this_rq() cpu_rq(smp_processor_id())
+#define task_rq(p) cpu_rq((p)->cpu)
+#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
#define rt_task(p) ((p)->policy != SCHED_OTHER)
-#define lock_task_rq(rq,p,flags) \
-do { \
-repeat_lock_task: \
- rq = task_rq(p); \
- spin_lock_irqsave(&rq->lock, flags); \
- if (unlikely((rq)->cpu != (p)->cpu)) { \
- spin_unlock_irqrestore(&rq->lock, flags); \
- goto repeat_lock_task; \
- } \
-} while (0)
-#define unlock_task_rq(rq,p,flags) \
- spin_unlock_irqrestore(&rq->lock, flags)
+static inline runqueue_t *lock_task_rq(task_t *p, unsigned long *flags)
+{
+ struct runqueue *__rq;
+
+repeat_lock_task:
+ __rq = task_rq(p);
+ spin_lock_irqsave(&__rq->lock, *flags);
+ if (unlikely(__rq != task_rq(p))) {
+ spin_unlock_irqrestore(&__rq->lock, *flags);
+ goto repeat_lock_task;
+ }
+ return __rq;
+}
+static inline void unlock_task_rq(runqueue_t *rq, task_t *p,
+ unsigned long *flags)
+{
+ spin_unlock_irqrestore(&rq->lock, *flags);
+}
/*
* Adding/removing a task to/from a priority array:
*/
@@ -94,18 +94,71 @@ static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
p->array = array;
}
+/*
+ * A task is 'heavily interactive' if it either has reached the
+ * bottom 25% of the SCHED_OTHER priority range, or if it is below
+ * its default priority by at least 3 priority levels. In this
+ * case we favor it by reinserting it on the active array,
+ * even after it expired its current timeslice.
+ *
+ * A task is a 'CPU hog' if it's either in the upper 25% of the
+ * SCHED_OTHER priority range, or if's not an interactive task.
+ *
+ * A task can get a priority bonus by being 'somewhat
+ * interactive' - and it will get a priority penalty for
+ * being a CPU hog.
+ *
+ */
+#define PRIO_INTERACTIVE (MAX_RT_PRIO + MAX_USER_PRIO/4)
+#define PRIO_CPU_HOG (MAX_RT_PRIO + MAX_USER_PRIO*3/4)
+
+#define TASK_INTERACTIVE(p) (((p)->prio <= PRIO_INTERACTIVE) || \
+ (((p)->prio < PRIO_CPU_HOG) && \
+ ((p)->prio <= NICE_TO_PRIO((p)->__nice)-3)))
+
+static inline int effective_prio(task_t *p)
+{
+ int bonus, prio;
+
+ /*
+ * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG]
+ * into the 19 ... -18 bonus/penalty range.
+ *
+ * We take off the 10% from the full 0...39 priority range so that:
+ *
+ * 1) nice +19 CPU hogs do not preempt nice 0 CPU hogs just yet.
+ * 2) nice -20 interactive tasks do not get preempted by
+ * nice 0 interactive tasks.
+ *
+ * Both properties are important to certain applications.
+ */
+ bonus = MAX_USER_PRIO*9/10 * p->sleep_avg / MAX_SLEEP_AVG -
+ MAX_USER_PRIO*9/10/2;
+ prio = NICE_TO_PRIO(p->__nice) - bonus;
+ if (prio < MAX_RT_PRIO)
+ prio = MAX_RT_PRIO;
+ if (prio > MAX_PRIO-1)
+ prio = MAX_PRIO-1;
+ return prio;
+}
+
static inline void activate_task(task_t *p, runqueue_t *rq)
{
+ unsigned long sleep_time = jiffies - p->sleep_timestamp;
prio_array_t *array = rq->active;
- if (!rt_task(p)) {
- unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
-
- if (prio_bonus > MAX_PRIO)
- prio_bonus = MAX_PRIO;
- p->prio -= prio_bonus;
- if (p->prio < MAX_RT_PRIO)
- p->prio = MAX_RT_PRIO;
+ if (!rt_task(p) && sleep_time) {
+ /*
+ * This code gives a bonus to interactive tasks. We update
+ * an 'average sleep time' value here, based on
+ * sleep_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;
+ if (p->sleep_avg > MAX_SLEEP_AVG)
+ p->sleep_avg = MAX_SLEEP_AVG;
+ p->prio = effective_prio(p);
}
enqueue_task(p, array);
rq->nr_running++;
@@ -116,7 +169,7 @@ static inline void deactivate_task(struct task_struct *p, runqueue_t *rq)
rq->nr_running--;
dequeue_task(p, p->array);
p->array = NULL;
- p->sleep_jtime = jiffies;
+ p->sleep_timestamp = jiffies;
}
static inline void resched_task(task_t *p)
@@ -147,12 +200,26 @@ repeat:
cpu_relax();
barrier();
}
- lock_task_rq(rq, p, flags);
+ rq = lock_task_rq(p, &flags);
if (unlikely(rq->curr == p)) {
- unlock_task_rq(rq, p, flags);
+ unlock_task_rq(rq, p, &flags);
goto repeat;
}
- unlock_task_rq(rq, p, flags);
+ unlock_task_rq(rq, p, &flags);
+}
+
+/*
+ * The SMP message passing code calls this function whenever
+ * the new task has arrived at the target CPU. We move the
+ * new task into the local runqueue.
+ *
+ * This function must be called with interrupts disabled.
+ */
+void sched_task_migrated(task_t *new_task)
+{
+ wait_task_inactive(new_task);
+ new_task->cpu = smp_processor_id();
+ wake_up_process(new_task);
}
/*
@@ -185,7 +252,7 @@ static int try_to_wake_up(task_t * p, int synchronous)
int success = 0;
runqueue_t *rq;
- lock_task_rq(rq, p, flags);
+ rq = lock_task_rq(p, &flags);
p->state = TASK_RUNNING;
if (!p->array) {
activate_task(p, rq);
@@ -193,11 +260,11 @@ static int try_to_wake_up(task_t * p, int synchronous)
resched_task(rq->curr);
success = 1;
}
- unlock_task_rq(rq, p, flags);
+ unlock_task_rq(rq, p, &flags);
return success;
}
-inline int wake_up_process(task_t * p)
+int wake_up_process(task_t * p)
{
return try_to_wake_up(p, 0);
}
@@ -206,13 +273,12 @@ void wake_up_forked_process(task_t * p)
{
runqueue_t *rq = this_rq();
- spin_lock_irq(&rq->lock);
p->state = TASK_RUNNING;
if (!rt_task(p)) {
- p->prio += MAX_USER_PRIO/10;
- if (p->prio > MAX_PRIO-1)
- p->prio = MAX_PRIO-1;
+ p->sleep_avg = (p->sleep_avg * 4) / 5;
+ p->prio = effective_prio(p);
}
+ spin_lock_irq(&rq->lock);
activate_task(p, rq);
spin_unlock_irq(&rq->lock);
}
@@ -274,72 +340,99 @@ unsigned long nr_context_switches(void)
return sum;
}
-static inline unsigned long max_rq_len(void)
-{
- unsigned long i, curr, max = 0;
-
- for (i = 0; i < smp_num_cpus; i++) {
- curr = cpu_rq(i)->nr_running;
- if (curr > max)
- max = curr;
- }
- return max;
-}
-
/*
- * Current runqueue is empty, try to find work on
- * other runqueues.
+ * Current runqueue is empty, or rebalance tick: if there is an
+ * inbalance (current runqueue is too short) then pull from
+ * busiest runqueue(s).
*
* We call this with the current runqueue locked,
* irqs disabled.
*/
-static void load_balance(runqueue_t *this_rq)
+static void load_balance(runqueue_t *this_rq, int idle)
{
- int nr_tasks, load, prev_max_load, max_load, idx, i;
+ int imbalance, nr_running, load, prev_max_load,
+ max_load, idx, i, this_cpu = smp_processor_id();
task_t *next = this_rq->idle, *tmp;
- runqueue_t *busiest, *rq_tmp;
+ runqueue_t *busiest, *rq_src;
prio_array_t *array;
list_t *head, *curr;
- prev_max_load = max_rq_len();
- nr_tasks = prev_max_load - this_rq->nr_running;
- /*
- * It needs an at least ~10% imbalance to trigger balancing:
- */
- if (nr_tasks <= 1 + prev_max_load/8)
- return;
- prev_max_load++;
-
-repeat_search:
/*
* We search all runqueues to find the most busy one.
* We do this lockless to reduce cache-bouncing overhead,
- * we re-check the source CPU with the lock held.
+ * we re-check the 'best' source CPU later on again, with
+ * the lock held.
+ *
+ * We fend off statistical fluctuations in runqueue lengths by
+ * saving the runqueue length during the previous load-balancing
+ * operation and using the smaller one the current and saved lengths.
+ * If a runqueue is long enough for a longer amount of time then
+ * we recognize it and pull tasks from it.
+ *
+ * The 'current runqueue length' is a statistical maximum variable,
+ * for that one we take the longer one - to avoid fluctuations in
+ * the other direction. So for a load-balance to happen it needs
+ * stable long runqueue on the target CPU and stable short runqueue
+ * on the local runqueue.
+ *
+ * We make an exception if this CPU is about to become idle - in
+ * that case we are less picky about moving a task across CPUs and
+ * take what can be taken.
*/
+ if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+ nr_running = this_rq->nr_running;
+ else
+ nr_running = this_rq->prev_nr_running[this_cpu];
+ prev_max_load = 1000000000;
+
busiest = NULL;
max_load = 0;
for (i = 0; i < smp_num_cpus; i++) {
- rq_tmp = cpu_rq(i);
- load = rq_tmp->nr_running;
+ rq_src = cpu_rq(i);
+ if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
+ load = rq_src->nr_running;
+ else
+ load = this_rq->prev_nr_running[i];
+ this_rq->prev_nr_running[i] = rq_src->nr_running;
+
if ((load > max_load) && (load < prev_max_load) &&
- (rq_tmp != this_rq)) {
- busiest = rq_tmp;
+ (rq_src != this_rq)) {
+ busiest = rq_src;
max_load = load;
}
}
if (likely(!busiest))
return;
- if (max_load <= this_rq->nr_running)
+
+ imbalance = (max_load - nr_running) / 2;
+
+ /*
+ * It needs an at least ~25% imbalance to trigger balancing.
+ *
+ * prev_max_load makes sure that we do not try to balance
+ * ad infinitum - certain tasks might be impossible to be
+ * pulled into this runqueue.
+ */
+ if (!idle && (imbalance < (max_load + 3)/4))
return;
prev_max_load = max_load;
- if (busiest->cpu < this_rq->cpu) {
+
+ /*
+ * Ok, lets do some actual balancing:
+ */
+
+ if (busiest < this_rq) {
spin_unlock(&this_rq->lock);
spin_lock(&busiest->lock);
spin_lock(&this_rq->lock);
} else
spin_lock(&busiest->lock);
- if (busiest->nr_running <= this_rq->nr_running + 1)
+ /*
+ * Make sure nothing changed since we checked the
+ * runqueue length.
+ */
+ if (busiest->nr_running <= nr_running + 1)
goto out_unlock;
/*
@@ -365,15 +458,14 @@ skip_bitmap:
array = busiest->active;
goto new_array;
}
- spin_unlock(&busiest->lock);
- goto repeat_search;
+ goto out_unlock;
}
head = array->queue + idx;
curr = head->next;
skip_queue:
tmp = list_entry(curr, task_t, run_list);
- if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) {
+ if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) {
curr = curr->next;
if (curr != head)
goto skip_queue;
@@ -387,64 +479,95 @@ skip_queue:
*/
dequeue_task(next, array);
busiest->nr_running--;
- next->cpu = smp_processor_id();
+ next->cpu = this_cpu;
this_rq->nr_running++;
enqueue_task(next, this_rq->active);
if (next->prio < current->prio)
current->need_resched = 1;
- if (--nr_tasks) {
+ if (!idle && --imbalance) {
if (array == busiest->expired) {
array = busiest->active;
goto new_array;
}
- spin_unlock(&busiest->lock);
- goto repeat_search;
}
out_unlock:
spin_unlock(&busiest->lock);
}
-/* Rebalance every 250 msecs */
-#define REBALANCE_TICK (HZ/4)
+/*
+ * One of the idle_cpu_tick() or the busy_cpu_tick() function will
+ * gets called every timer tick, on every CPU. Our balancing action
+ * frequency and balancing agressivity depends on whether the CPU is
+ * idle or not.
+ *
+ * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
+ * systems with HZ=100, every 10 msecs.)
+ */
+#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
+#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
-void idle_tick(void)
+static inline void idle_tick(void)
{
- unsigned long flags;
-
- if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) {
- spin_lock_irqsave(&this_rq()->lock, flags);
- load_balance(this_rq());
- spin_unlock_irqrestore(&this_rq()->lock, flags);
- }
+ if (jiffies % IDLE_REBALANCE_TICK)
+ return;
+ spin_lock(&this_rq()->lock);
+ load_balance(this_rq(), 1);
+ spin_unlock(&this_rq()->lock);
}
-void expire_task(task_t *p)
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void scheduler_tick(task_t *p)
{
+ unsigned long now = jiffies;
runqueue_t *rq = this_rq();
- unsigned long flags;
+ if (p == rq->idle)
+ return idle_tick();
+ /* Task might have expired already, but not scheduled off yet */
if (p->array != rq->active) {
p->need_resched = 1;
return;
}
+ spin_lock(&rq->lock);
+ if (unlikely(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 = NICE_TO_TIMESLICE(p->__nice);
+ p->need_resched = 1;
+
+ /* put it at the end of the queue: */
+ dequeue_task(p, rq->active);
+ enqueue_task(p, rq->active);
+ }
+ goto out;
+ }
/*
- * The task cannot change CPUs because it's the current task.
+ * The task was running during this tick - update the
+ * time slice counter and the sleep average. Note: we
+ * do not update a process'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.
*/
- spin_lock_irqsave(&rq->lock, flags);
- if ((p->policy != SCHED_FIFO) && !--p->time_slice) {
- prio_array_t *array = rq->active;
- p->need_resched = 1;
+ if (p->sleep_avg)
+ p->sleep_avg--;
+ if (!--p->time_slice) {
dequeue_task(p, rq->active);
- if (!rt_task(p)) {
- if (++p->prio >= MAX_PRIO)
- p->prio = MAX_PRIO - 1;
- if (!TASK_INTERACTIVE(p))
- array = rq->expired;
- }
- enqueue_task(p, array);
+ p->need_resched = 1;
+ p->prio = effective_prio(p);
p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+ enqueue_task(p, TASK_INTERACTIVE(p) ? rq->active : rq->expired);
}
- spin_unlock_irqrestore(&rq->lock, flags);
+out:
+ if (!(now % BUSY_REBALANCE_TICK))
+ load_balance(rq, 0);
+ spin_unlock(&rq->lock);
}
void scheduling_functions_start_here(void) { }
@@ -454,18 +577,15 @@ void scheduling_functions_start_here(void) { }
*/
asmlinkage void schedule(void)
{
- task_t *prev, *next;
+ task_t *prev = current, *next;
+ runqueue_t *rq = this_rq();
prio_array_t *array;
- runqueue_t *rq;
list_t *queue;
int idx;
if (unlikely(in_interrupt()))
BUG();
-need_resched_back:
- prev = current;
release_kernel_lock(prev, smp_processor_id());
- rq = this_rq();
spin_lock_irq(&rq->lock);
switch (prev->state) {
@@ -480,7 +600,7 @@ need_resched_back:
}
pick_next_task:
if (unlikely(!rq->nr_running)) {
- load_balance(rq);
+ load_balance(rq, 1);
if (rq->nr_running)
goto pick_next_task;
next = rq->idle;
@@ -507,7 +627,6 @@ switch_tasks:
if (likely(prev != next)) {
rq->nr_switches++;
rq->curr = next;
- next->cpu = prev->cpu;
context_switch(prev, next);
/*
* The runqueue pointer might be from another CPU
@@ -520,8 +639,6 @@ switch_tasks:
spin_unlock_irq(&rq->lock);
reacquire_kernel_lock(current);
- if (unlikely(current->need_resched))
- goto need_resched_back;
return;
}
@@ -674,47 +791,23 @@ long sleep_on_timeout(wait_queue_head_t *q, long timeout)
*/
void set_cpus_allowed(task_t *p, unsigned long new_mask)
{
- runqueue_t *this_rq = this_rq(), *target_rq;
- unsigned long this_mask = 1UL << smp_processor_id();
- int target_cpu;
-
new_mask &= cpu_online_map;
if (!new_mask)
BUG();
+
p->cpus_allowed = new_mask;
/*
* Can the task run on the current CPU? If not then
* migrate the process off to a proper CPU.
*/
- if (new_mask & this_mask)
+ if (new_mask & (1UL << smp_processor_id()))
return;
- target_cpu = ffz(~new_mask);
- target_rq = cpu_rq(target_cpu);
- if (target_cpu < smp_processor_id()) {
- spin_lock_irq(&target_rq->lock);
- spin_lock(&this_rq->lock);
- } else {
- spin_lock_irq(&this_rq->lock);
- spin_lock(&target_rq->lock);
- }
- dequeue_task(p, p->array);
- this_rq->nr_running--;
- target_rq->nr_running++;
- enqueue_task(p, target_rq->active);
- target_rq->curr->need_resched = 1;
- spin_unlock(&target_rq->lock);
+#if CONFIG_SMP
+ smp_migrate_task(ffz(~new_mask), current);
- /*
- * The easiest solution is to context switch into
- * the idle thread - which will pick the best task
- * afterwards:
- */
- this_rq->nr_switches++;
- this_rq->curr = this_rq->idle;
- this_rq->idle->need_resched = 1;
- context_switch(current, this_rq->idle);
- barrier();
- spin_unlock_irq(&this_rq()->lock);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule();
+#endif
}
void scheduling_functions_end_here(void) { }
@@ -731,7 +824,7 @@ void set_user_nice(task_t *p, long nice)
* We have to be careful, if called from sys_setpriority(),
* the task might be in the middle of scheduling on another CPU.
*/
- lock_task_rq(rq, p, flags);
+ rq = lock_task_rq(p, &flags);
if (rt_task(p)) {
p->__nice = nice;
goto out_unlock;
@@ -745,7 +838,7 @@ void set_user_nice(task_t *p, long nice)
if (array) {
enqueue_task(p, array);
/*
- * If the task is runnable and lowered its priority,
+ * If the task is running and lowered its priority,
* or increased its priority then reschedule its CPU:
*/
if ((nice < p->__nice) ||
@@ -753,7 +846,7 @@ void set_user_nice(task_t *p, long nice)
resched_task(rq->curr);
}
out_unlock:
- unlock_task_rq(rq, p, flags);
+ unlock_task_rq(rq, p, &flags);
}
#ifndef __alpha__
@@ -830,7 +923,7 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param)
* To be able to change p->policy safely, the apropriate
* runqueue lock must be held.
*/
- lock_task_rq(rq,p,flags);
+ rq = lock_task_rq(p, &flags);
if (policy < 0)
policy = p->policy;
@@ -873,7 +966,7 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param)
activate_task(p, task_rq(p));
out_unlock:
- unlock_task_rq(rq,p,flags);
+ unlock_task_rq(rq, p, &flags);
out_unlock_tasklist:
read_unlock_irq(&tasklist_lock);
@@ -1015,7 +1108,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
p = find_process_by_pid(pid);
if (p)
jiffies_to_timespec(p->policy & SCHED_FIFO ?
- 0 : NICE_TO_TIMESLICE(p->__nice), &t);
+ 0 : NICE_TO_TIMESLICE(p->prio), &t);
read_unlock(&tasklist_lock);
if (p)
retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1116,14 +1209,12 @@ void show_state(void)
read_unlock(&tasklist_lock);
}
-extern unsigned long wait_init_idle;
-
static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
{
if (rq1 == rq2)
spin_lock(&rq1->lock);
else {
- if (rq1->cpu < rq2->cpu) {
+ if (rq1 < rq2) {
spin_lock(&rq1->lock);
spin_lock(&rq2->lock);
} else {
@@ -1154,14 +1245,9 @@ void __init init_idle(void)
current->array = NULL;
current->prio = MAX_PRIO;
current->state = TASK_RUNNING;
- clear_bit(smp_processor_id(), &wait_init_idle);
double_rq_unlock(this_rq, rq);
- while (wait_init_idle) {
- cpu_relax();
- barrier();
- }
current->need_resched = 1;
- __sti();
+ __restore_flags(flags);
}
extern void init_timervecs(void);
@@ -1181,7 +1267,6 @@ void __init sched_init(void)
rq->active = rq->arrays + 0;
rq->expired = rq->arrays + 1;
spin_lock_init(&rq->lock);
- rq->cpu = i;
for (j = 0; j < 2; j++) {
array = rq->arrays + j;
@@ -1201,12 +1286,9 @@ void __init sched_init(void)
*/
rq = this_rq();
rq->curr = current;
- rq->idle = NULL;
+ rq->idle = current;
wake_up_process(current);
- for (i = 0; i < PIDHASH_SZ; i++)
- pidhash[i] = NULL;
-
init_timervecs();
init_bh(TIMER_BH, timer_bh);
init_bh(TQUEUE_BH, tqueue_bh);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 4d8bb7b97..5b665bd72 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -387,8 +387,7 @@ static int ksoftirqd(void * __bind_cpu)
while (softirq_pending(cpu)) {
do_softirq();
- if (current->need_resched)
- schedule();
+ cond_resched();
}
__set_current_state(TASK_INTERRUPTIBLE);
diff --git a/kernel/timer.c b/kernel/timer.c
index ce3945cda..da17ae4ac 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -585,17 +585,16 @@ void update_process_times(int user_tick)
update_one_process(p, user_tick, system, cpu);
if (p->pid) {
- expire_task(p);
if (p->__nice > 0)
kstat.per_cpu_nice[cpu] += user_tick;
else
kstat.per_cpu_user[cpu] += user_tick;
kstat.per_cpu_system[cpu] += system;
} else {
- idle_tick();
if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
kstat.per_cpu_system[cpu] += system;
}
+ scheduler_tick(p);
}
/*
diff --git a/mm/filemap.c b/mm/filemap.c
index 89968606f..7fdfbdf97 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -290,7 +290,7 @@ static int truncate_list_pages(struct list_head *head, unsigned long start, unsi
page_cache_release(page);
- if (current->need_resched) {
+ if (need_resched()) {
__set_current_state(TASK_RUNNING);
schedule();
}
@@ -400,7 +400,7 @@ static int invalidate_list_pages2(struct list_head *head)
}
page_cache_release(page);
- if (current->need_resched) {
+ if (need_resched()) {
__set_current_state(TASK_RUNNING);
schedule();
}
diff --git a/mm/highmem.c b/mm/highmem.c
index 672500e52..3abe1c093 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -367,12 +367,6 @@ void create_bounce(unsigned long pfn, int gfp, struct bio **bio_orig)
if (pfn >= blk_max_pfn)
return;
-#ifndef CONFIG_HIGHMEM
- /*
- * should not hit for non-highmem case
- */
- BUG();
-#endif
bio_gfp = GFP_NOHIGHIO;
pool = page_pool;
} else {
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 1996d935c..8c476d491 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -110,8 +110,7 @@ static int badness(struct task_struct *p)
/*
* Simple selection loop. We chose the process with the highest
- * number of 'points'. We need the locks to make sure that the
- * list of task structs doesn't change while we look the other way.
+ * number of 'points'. We expect the caller will lock the tasklist.
*
* (not docbooked, we don't want this one cluttering up the manual)
*/
@@ -121,7 +120,6 @@ static struct task_struct * select_bad_process(void)
struct task_struct *p = NULL;
struct task_struct *chosen = NULL;
- read_lock(&tasklist_lock);
for_each_task(p) {
if (p->pid) {
int points = badness(p);
@@ -131,7 +129,6 @@ static struct task_struct * select_bad_process(void)
}
}
}
- read_unlock(&tasklist_lock);
return chosen;
}
@@ -170,14 +167,16 @@ void oom_kill_task(struct task_struct *p)
*/
static void oom_kill(void)
{
- struct task_struct *p = select_bad_process(), *q;
+ struct task_struct *p, *q;
+
+ read_lock(&tasklist_lock);
+ p = select_bad_process();
/* Found nothing?!?! Either we hang forever, or we panic. */
if (p == NULL)
panic("Out of memory and no killable processes...\n");
/* kill all processes that share the ->mm (i.e. all threads) */
- read_lock(&tasklist_lock);
for_each_task(q) {
if(q->mm == p->mm) oom_kill_task(q);
}
@@ -197,7 +196,7 @@ static void oom_kill(void)
*/
void out_of_memory(void)
{
- static unsigned long first, last, count;
+ static unsigned long first, last, count, lastkill;
unsigned long now, since;
/*
@@ -234,8 +233,18 @@ void out_of_memory(void)
return;
/*
+ * If we just killed a process, wait a while
+ * to give that task a chance to exit. This
+ * avoids killing multiple processes needlessly.
+ */
+ since = now - lastkill;
+ if (since < HZ*5)
+ return;
+
+ /*
* Ok, really out of memory. Kill something.
*/
+ lastkill = now;
oom_kill();
reset:
diff --git a/mm/shmem.c b/mm/shmem.c
index ddcac7a48..a32676791 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -26,6 +26,7 @@
#include <linux/pagemap.h>
#include <linux/string.h>
#include <linux/locks.h>
+#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -385,7 +386,7 @@ static int shmem_unuse_inode (struct shmem_inode_info *info, swp_entry_t entry,
return 0;
found:
delete_from_swap_cache(page);
- add_to_page_cache(page, info->inode->i_mapping, offset + idx);
+ add_to_page_cache(page, info->vfs_inode.i_mapping, offset + idx);
SetPageDirty(page);
SetPageUptodate(page);
info->swapped--;
@@ -685,9 +686,13 @@ struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
inode->i_mapping->a_ops = &shmem_aops;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
info = SHMEM_I(inode);
- info->inode = inode;
spin_lock_init (&info->lock);
sema_init (&info->sem, 1);
+ info->next_index = 0;
+ memset (info->i_direct, 0, sizeof(info->i_direct));
+ info->i_indirect = NULL;
+ info->swapped = 0;
+ info->locked = 0;
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
@@ -1308,7 +1313,48 @@ static struct super_block *shmem_read_super(struct super_block * sb, void * data
return sb;
}
+static kmem_cache_t * shmem_inode_cachep;
+static struct inode *shmem_alloc_inode(struct super_block *sb)
+{
+ struct shmem_inode_info *p;
+ p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, SLAB_KERNEL);
+ if (!p)
+ return NULL;
+ return &p->vfs_inode;
+}
+
+static void shmem_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct shmem_inode_info *p = (struct shmem_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ inode_init_once(&p->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
+ sizeof(struct shmem_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (shmem_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(shmem_inode_cachep))
+ printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n");
+}
static struct address_space_operations shmem_aops = {
writepage: shmem_writepage,
@@ -1350,6 +1396,8 @@ static struct inode_operations shmem_dir_inode_operations = {
};
static struct super_operations shmem_ops = {
+ alloc_inode: shmem_alloc_inode,
+ destroy_inode: shmem_destroy_inode,
#ifdef CONFIG_TMPFS
statfs: shmem_statfs,
remount_fs: shmem_remount_fs,
@@ -1376,30 +1424,45 @@ static int __init init_shmem_fs(void)
int error;
struct vfsmount * res;
- if ((error = register_filesystem(&tmpfs_fs_type))) {
+ error = init_inodecache();
+ if (error)
+ goto out3;
+
+ error = register_filesystem(&tmpfs_fs_type);
+ if (error) {
printk (KERN_ERR "Could not register tmpfs\n");
- return error;
+ goto out2;
}
#ifdef CONFIG_TMPFS
- if ((error = register_filesystem(&shmem_fs_type))) {
+ error = register_filesystem(&shmem_fs_type);
+ if (error) {
printk (KERN_ERR "Could not register shm fs\n");
- return error;
+ goto out1;
}
devfs_mk_dir (NULL, "shm", NULL);
#endif
res = kern_mount(&tmpfs_fs_type);
if (IS_ERR (res)) {
+ error = PTR_ERR(res);
printk (KERN_ERR "could not kern_mount tmpfs\n");
- unregister_filesystem(&tmpfs_fs_type);
- return PTR_ERR(res);
+ goto out;
}
shm_mnt = res;
/* The internal instance should not do size checking */
- if ((error = shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX)))
- printk (KERN_ERR "could not set limits on internal tmpfs\n");
-
+ shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX);
return 0;
+
+out:
+#ifdef CONFIG_TMPFS
+ unregister_filesystem(&shmem_fs_type);
+out1:
+#endif
+ unregister_filesystem(&tmpfs_fs_type);
+out2:
+ destroy_inodecache();
+out3:
+ return error;
}
static void __exit exit_shmem_fs(void)
@@ -1409,6 +1472,7 @@ static void __exit exit_shmem_fs(void)
#endif
unregister_filesystem(&tmpfs_fs_type);
mntput(shm_mnt);
+ destroy_inodecache();
}
module_init(init_shmem_fs)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index ede841b15..925286b4f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -344,7 +344,7 @@ void free_swap_and_cache(swp_entry_t entry)
if (page) {
page_cache_get(page);
/* Only cache user (+us), or swap space full? Free it! */
- if (page_count(page) == 2 || vm_swap_full()) {
+ if (page_count(page) - !!page->buffers == 2 || vm_swap_full()) {
delete_from_swap_cache(page);
SetPageDirty(page);
}
@@ -696,7 +696,7 @@ static int try_to_unuse(unsigned int type)
* interactive performance. Interruptible check on
* signal_pending() would be nice, but changes the spec?
*/
- if (current->need_resched)
+ if (need_resched())
schedule();
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 8d6d9ffa1..fb6d468d3 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -300,7 +300,7 @@ static int swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * class
counter = mmlist_nr;
do {
- if (unlikely(current->need_resched)) {
+ if (need_resched()) {
__set_current_state(TASK_RUNNING);
schedule();
}
@@ -345,7 +345,7 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask,
while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
struct page * page;
- if (unlikely(current->need_resched)) {
+ if (need_resched()) {
spin_unlock(&pagemap_lru_lock);
__set_current_state(TASK_RUNNING);
schedule();
@@ -625,8 +625,7 @@ static int kswapd_balance_pgdat(pg_data_t * pgdat)
for (i = pgdat->nr_zones-1; i >= 0; i--) {
zone = pgdat->node_zones + i;
- if (unlikely(current->need_resched))
- schedule();
+ cond_resched();
if (!zone->need_balance)
continue;
if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
diff --git a/net/core/Makefile b/net/core/Makefile
index 65c973f26..5dacce00c 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o
obj-$(CONFIG_NETFILTER) += netfilter.o
obj-$(CONFIG_NET_DIVERT) += dv.o
obj-$(CONFIG_NET_PROFILE) += profile.o
+obj-$(CONFIG_NET_RADIO) += wireless.o
+# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
+obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
include $(TOPDIR)/Rules.make
diff --git a/net/core/dev.c b/net/core/dev.c
index 6eb1c6d03..d7f8cad31 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -102,6 +102,7 @@
#include <linux/module.h>
#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
+#include <net/iw_handler.h>
#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
#ifdef CONFIG_PLIP
extern int plip_init(void);
@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, char **start, off_t offset,
#endif /* CONFIG_PROC_FS */
-#ifdef WIRELESS_EXT
-#ifdef CONFIG_PROC_FS
-
-/*
- * Print one entry of /proc/net/wireless
- * This is a clone of /proc/net/dev (just above)
- */
-static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
-{
- /* Get stats from the driver */
- struct iw_statistics *stats = (dev->get_wireless_stats ?
- dev->get_wireless_stats(dev) :
- (struct iw_statistics *) NULL);
- int size;
-
- if (stats != (struct iw_statistics *) NULL) {
- size = sprintf(buffer,
- "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n",
- dev->name,
- stats->status,
- stats->qual.qual,
- stats->qual.updated & 1 ? '.' : ' ',
- stats->qual.level,
- stats->qual.updated & 2 ? '.' : ' ',
- stats->qual.noise,
- stats->qual.updated & 4 ? '.' : ' ',
- stats->discard.nwid,
- stats->discard.code,
- stats->discard.fragment,
- stats->discard.retries,
- stats->discard.misc,
- stats->miss.beacon);
- stats->qual.updated = 0;
- }
- else
- size = 0;
-
- return size;
-}
-
-/*
- * Print info for /proc/net/wireless (print all entries)
- * This is a clone of /proc/net/dev (just above)
- */
-static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
- int length)
-{
- int len = 0;
- off_t begin = 0;
- off_t pos = 0;
- int size;
-
- struct net_device * dev;
-
- size = sprintf(buffer,
- "Inter-| sta-| Quality | Discarded packets | Missed\n"
- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n"
- );
-
- pos += size;
- len += size;
-
- read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
- size = sprintf_wireless_stats(buffer + len, dev);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- break;
- }
- read_unlock(&dev_base_lock);
-
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- if (len < 0)
- len = 0;
-
- return len;
-}
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Allow programatic access to /proc/net/wireless even if /proc
- * doesn't exist... Also more efficient...
- */
-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
-{
- /* Get stats from the driver */
- struct iw_statistics *stats = (dev->get_wireless_stats ?
- dev->get_wireless_stats(dev) :
- (struct iw_statistics *) NULL);
-
- if (stats != (struct iw_statistics *) NULL) {
- struct iwreq * wrq = (struct iwreq *)ifr;
-
- /* Copy statistics to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, stats,
- sizeof(struct iw_statistics)))
- return -EFAULT;
-
- /* Check if we need to clear the update flag */
- if(wrq->u.data.flags != 0)
- stats->qual.updated = 0;
- return(0);
- } else
- return -EOPNOTSUPP;
-}
-#endif /* WIRELESS_EXT */
-
/**
* netdev_set_master - set up master/slave pair
* @slave: slave device
@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
return 0;
-#ifdef WIRELESS_EXT
- case SIOCGIWSTATS:
- return dev_iwstats(dev, ifr);
-#endif /* WIRELESS_EXT */
-
/*
* Unknown or private ioctl
*/
@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
return -EOPNOTSUPP;
}
-#ifdef WIRELESS_EXT
- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
- if (dev->do_ioctl) {
- if (!netif_device_present(dev))
- return -ENODEV;
- return dev->do_ioctl(dev, ifr, cmd);
- }
- return -EOPNOTSUPP;
- }
-#endif /* WIRELESS_EXT */
-
}
return -EINVAL;
}
@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *arg)
}
dev_load(ifr.ifr_name);
rtnl_lock();
- ret = dev_ifsioc(&ifr, cmd);
+ /* Follow me in net/core/wireless.c */
+ ret = wireless_process_ioctl(&ifr, cmd);
rtnl_unlock();
if (!ret && IW_IS_GET(cmd) &&
copy_to_user(arg, &ifr, sizeof(struct ifreq)))
@@ -2856,6 +2726,7 @@ int __init net_dev_init(void)
proc_net_create("dev", 0, dev_get_info);
create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
#ifdef WIRELESS_EXT
+ /* Available in net/core/wireless.c */
proc_net_create("wireless", 0, dev_get_wireless_info);
#endif /* WIRELESS_EXT */
#endif /* CONFIG_PROC_FS */
diff --git a/net/core/wireless.c b/net/core/wireless.c
new file mode 100644
index 000000000..5d57ccc72
--- /dev/null
+++ b/net/core/wireless.c
@@ -0,0 +1,733 @@
+/*
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/************************** DOCUMENTATION **************************/
+/*
+ * API definition :
+ * --------------
+ * See <linux/wireless.h> for details of the APIs and the rest.
+ *
+ * History :
+ * -------
+ *
+ * v1 - 5.12.01 - Jean II
+ * o Created this file.
+ *
+ * v2 - 13.12.01 - Jean II
+ * o Move /proc/net/wireless stuff from net/core/dev.c to here
+ * o Make Wireless Extension IOCTLs go through here
+ * o Added iw_handler handling ;-)
+ * o Added standard ioctl description
+ * o Initial dumb commit strategy based on orinoco.c
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <asm/uaccess.h> /* copy_to_user() */
+#include <linux/config.h> /* Not needed ??? */
+#include <linux/types.h> /* off_t */
+#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
+
+#include <linux/wireless.h> /* Pretty obvious */
+#include <net/iw_handler.h> /* New driver API */
+
+/**************************** CONSTANTS ****************************/
+
+/* This will be turned on later on... */
+#undef WE_STRICT_WRITE /* Check write buffer size */
+
+/* Debuging stuff */
+#undef WE_IOCTL_DEBUG /* Debug IOCTL API */
+
+/************************* GLOBAL VARIABLES *************************/
+/*
+ * You should not use global variables, because or re-entrancy.
+ * On our case, it's only const, so it's OK...
+ */
+static const struct iw_ioctl_description standard_ioctl[] = {
+ /* SIOCSIWCOMMIT (internal) */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCGIWNAME */
+ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWNWID */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+ /* SIOCGIWNWID */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWFREQ */
+ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+ /* SIOCGIWFREQ */
+ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWMODE */
+ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+ /* SIOCGIWMODE */
+ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWSENS */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWSENS */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCSIWRANGE */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCGIWRANGE */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWPRIV */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCGIWPRIV (handled directly by us) */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCSIWSTATS */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCGIWSTATS (handled directly by us) */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWSPY */
+ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+ /* SIOCGIWSPY */
+ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCSIWAP */
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ /* SIOCGIWAP */
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCGIWAPLIST */
+ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCSIWESSID */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
+ /* SIOCGIWESSID */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
+ /* SIOCSIWNICKN */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+ /* SIOCGIWNICKN */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* -- hole -- */
+ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ /* SIOCSIWRATE */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWRATE */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCSIWRTS */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWRTS */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCSIWFRAG */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWFRAG */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCSIWTXPOW */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWTXPOW */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCSIWRETRY */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWRETRY */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCSIWENCODE */
+ { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+ /* SIOCGIWENCODE */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+ /* SIOCSIWPOWER */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWPOWER */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+};
+
+/* Size (in bytes) of the various private data types */
+char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+
+/************************ COMMON SUBROUTINES ************************/
+/*
+ * Stuff that may be used in various place or doesn't fit in one
+ * of the section below.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the driver handler associated with a specific Wireless Extension.
+ * Called from various place, so make sure it remains efficient.
+ */
+static inline iw_handler get_handler(struct net_device *dev,
+ unsigned int cmd)
+{
+ unsigned int index; /* MUST be unsigned */
+
+ /* Check if we have some wireless handlers defined */
+ if(dev->wireless_handlers == NULL)
+ return NULL;
+
+ /* Try as a standard command */
+ index = cmd - SIOCIWFIRST;
+ if(index < dev->wireless_handlers->num_standard)
+ return dev->wireless_handlers->standard[index];
+
+ /* Try as a private command */
+ index = cmd - SIOCIWFIRSTPRIV;
+ if(index < dev->wireless_handlers->num_private)
+ return dev->wireless_handlers->private[index];
+
+ /* Not found */
+ return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Get statistics out of the driver
+ */
+static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
+{
+ return (dev->get_wireless_stats ?
+ dev->get_wireless_stats(dev) :
+ (struct iw_statistics *) NULL);
+ /* In the future, get_wireless_stats may move from 'struct net_device'
+ * to 'struct iw_handler_def', to de-bloat struct net_device.
+ * Definitely worse a thought... */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
+ *
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
+ */
+static inline int call_commit_handler(struct net_device * dev)
+{
+ if((netif_running(dev)) &&
+ (dev->wireless_handlers->standard[0] != NULL)) {
+ /* Call the commit handler on the driver */
+ return dev->wireless_handlers->standard[0](dev, NULL,
+ NULL, NULL);
+ } else
+ return 0; /* Command completed successfully */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Number of private arguments
+ */
+static inline int get_priv_size(__u16 args)
+{
+ int num = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ return num * priv_type_size[type];
+}
+
+
+/******************** /proc/net/wireless SUPPORT ********************/
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print one entry (line) of /proc/net/wireless
+ */
+static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
+{
+ /* Get stats from the driver */
+ struct iw_statistics *stats;
+ int size;
+
+ stats = get_wireless_stats(dev);
+ if (stats != (struct iw_statistics *) NULL) {
+ size = sprintf(buffer,
+ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n",
+ dev->name,
+ stats->status,
+ stats->qual.qual,
+ stats->qual.updated & 1 ? '.' : ' ',
+ stats->qual.level,
+ stats->qual.updated & 2 ? '.' : ' ',
+ stats->qual.noise,
+ stats->qual.updated & 4 ? '.' : ' ',
+ stats->discard.nwid,
+ stats->discard.code,
+ stats->discard.fragment,
+ stats->discard.retries,
+ stats->discard.misc,
+ stats->miss.beacon);
+ stats->qual.updated = 0;
+ }
+ else
+ size = 0;
+
+ return size;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+ int length)
+{
+ int len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+ int size;
+
+ struct net_device * dev;
+
+ size = sprintf(buffer,
+ "Inter-| sta-| Quality | Discarded packets | Missed\n"
+ " face | tus | link level noise | nwid crypt frag retry misc | beacon\n"
+ );
+
+ pos += size;
+ len += size;
+
+ read_lock(&dev_base_lock);
+ for (dev = dev_base; dev != NULL; dev = dev->next) {
+ size = sprintf_wireless_stats(buffer + len, dev);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ break;
+ }
+ read_unlock(&dev_base_lock);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+/************************** IOCTL SUPPORT **************************/
+/*
+ * The original user space API to configure all those Wireless Extensions
+ * is through IOCTLs.
+ * In there, we check if we need to call the new driver API (iw_handler)
+ * or just call the driver ioctl handler.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Allow programatic access to /proc/net/wireless even if /proc
+ * doesn't exist... Also more efficient...
+ */
+static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+{
+ /* Get stats from the driver */
+ struct iw_statistics *stats;
+
+ stats = get_wireless_stats(dev);
+ if (stats != (struct iw_statistics *) NULL) {
+ struct iwreq * wrq = (struct iwreq *)ifr;
+
+ /* Copy statistics to the user buffer */
+ if(copy_to_user(wrq->u.data.pointer, stats,
+ sizeof(struct iw_statistics)))
+ return -EFAULT;
+
+ /* Check if we need to clear the update flag */
+ if(wrq->u.data.flags != 0)
+ stats->qual.updated = 0;
+ return 0;
+ } else
+ return -EOPNOTSUPP;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Export the driver private handler definition
+ * They will be picked up by tools like iwpriv...
+ */
+static inline int ioctl_export_private(struct net_device * dev,
+ struct ifreq * ifr)
+{
+ struct iwreq * iwr = (struct iwreq *) ifr;
+
+ /* Check if the driver has something to export */
+ if((dev->wireless_handlers->num_private_args == 0) ||
+ (dev->wireless_handlers->private_args == NULL))
+ return -EOPNOTSUPP;
+
+ /* Check NULL pointer */
+ if(iwr->u.data.pointer == NULL)
+ return -EFAULT;
+#ifdef WE_STRICT_WRITE
+ /* Check if there is enough buffer up there */
+ if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+ return -E2BIG;
+#endif /* WE_STRICT_WRITE */
+
+ /* Set the number of available ioctls. */
+ iwr->u.data.length = dev->wireless_handlers->num_private_args;
+
+ /* Copy structure to the user buffer. */
+ if (copy_to_user(iwr->u.data.pointer,
+ dev->wireless_handlers->private_args,
+ sizeof(struct iw_priv_args) * iwr->u.data.length))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static inline int ioctl_standard_call(struct net_device * dev,
+ struct ifreq * ifr,
+ unsigned int cmd,
+ iw_handler handler)
+{
+ struct iwreq * iwr = (struct iwreq *) ifr;
+ const struct iw_ioctl_description * descr;
+ struct iw_request_info info;
+ int ret = -EINVAL;
+
+ /* Get the description of the IOCTL */
+ descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
+ ifr->ifr_name, cmd);
+ printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+#endif /* WE_IOCTL_DEBUG */
+
+ /* Prepare the call */
+ info.cmd = cmd;
+ info.flags = 0;
+
+ /* Check if we have a pointer to user space data or not */
+ if(descr->header_type != IW_HEADER_TYPE_POINT) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, &info, &(iwr->u), NULL);
+ } else {
+ char * extra;
+ int err;
+
+ /* Check what user space is giving us */
+ if(IW_IS_SET(cmd)) {
+ /* Check NULL pointer */
+ if((iwr->u.data.pointer == NULL) &&
+ (iwr->u.data.length != 0))
+ return -EFAULT;
+ /* Check if number of token fits within bounds */
+ if(iwr->u.data.length > descr->max_tokens)
+ return -E2BIG;
+ if(iwr->u.data.length < descr->min_tokens)
+ return -EINVAL;
+ } else {
+ /* Check NULL pointer */
+ if(iwr->u.data.pointer == NULL)
+ return -EFAULT;
+#ifdef WE_STRICT_WRITE
+ /* Check if there is enough buffer up there */
+ if(iwr->u.data.length < descr->max_tokens)
+ return -E2BIG;
+#endif /* WE_STRICT_WRITE */
+ }
+
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "Malloc %d bytes\n",
+ descr->max_tokens * descr->token_size);
+#endif /* WE_IOCTL_DEBUG */
+
+ /* Always allocate for max space. Easier, and won't last
+ * long... */
+ extra = kmalloc(descr->max_tokens * descr->token_size,
+ GFP_KERNEL);
+ if (extra == NULL) {
+ return -ENOMEM;
+ }
+
+ /* If it is a SET, get all the extra data in here */
+ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+ err = copy_from_user(extra, iwr->u.data.pointer,
+ iwr->u.data.length *
+ descr->token_size);
+ if (err) {
+ kfree(extra);
+ return -EFAULT;
+ }
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "Got %d bytes\n",
+ iwr->u.data.length * descr->token_size);
+#endif /* WE_IOCTL_DEBUG */
+ }
+
+ /* Call the handler */
+ ret = handler(dev, &info, &(iwr->u), extra);
+
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
+ err = copy_to_user(iwr->u.data.pointer, extra,
+ iwr->u.data.length *
+ descr->token_size);
+ if (err)
+ ret = -EFAULT;
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "Wrote %d bytes\n",
+ iwr->u.data.length * descr->token_size);
+#endif /* WE_IOCTL_DEBUG */
+ }
+
+ /* Cleanup - I told you it wasn't that long ;-) */
+ kfree(extra);
+ }
+
+ /* Call commit handler if needed and defined */
+ if(ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ /* Here, we will generate the appropriate event if needed */
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static inline int ioctl_private_call(struct net_device * dev,
+ struct ifreq * ifr,
+ unsigned int cmd,
+ iw_handler handler)
+{
+ struct iwreq * iwr = (struct iwreq *) ifr;
+ struct iw_priv_args * descr = NULL;
+ struct iw_request_info info;
+ int extra_size = 0;
+ int i;
+ int ret = -EINVAL;
+
+ /* Get the description of the IOCTL */
+ for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
+ if(cmd == dev->wireless_handlers->private_args[i].cmd) {
+ descr = &(dev->wireless_handlers->private_args[i]);
+ break;
+ }
+
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
+ ifr->ifr_name, cmd);
+ if(descr) {
+ printk(KERN_DEBUG "Name %s, set %X, get %X\n",
+ descr->name, descr->set_args, descr->get_args);
+ }
+#endif /* WE_IOCTL_DEBUG */
+
+ /* Compute the size of the set/get arguments */
+ if(descr != NULL) {
+ if(IW_IS_SET(cmd)) {
+ /* Size of set arguments */
+ extra_size = get_priv_size(descr->set_args);
+
+ /* Does it fits in iwr ? */
+ if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+ (extra_size < IFNAMSIZ))
+ extra_size = 0;
+ } else {
+ /* Size of set arguments */
+ extra_size = get_priv_size(descr->get_args);
+
+ /* Does it fits in iwr ? */
+ if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+ (extra_size < IFNAMSIZ))
+ extra_size = 0;
+ }
+ }
+
+ /* Prepare the call */
+ info.cmd = cmd;
+ info.flags = 0;
+
+ /* Check if we have a pointer to user space data or not. */
+ if(extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ char * extra;
+ int err;
+
+ /* Check what user space is giving us */
+ if(IW_IS_SET(cmd)) {
+ /* Check NULL pointer */
+ if((iwr->u.data.pointer == NULL) &&
+ (iwr->u.data.length != 0))
+ return -EFAULT;
+
+ /* Does it fits within bounds ? */
+ if(iwr->u.data.length > (descr->set_args &
+ IW_PRIV_SIZE_MASK))
+ return -E2BIG;
+ } else {
+ /* Check NULL pointer */
+ if(iwr->u.data.pointer == NULL)
+ return -EFAULT;
+ }
+
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
+#endif /* WE_IOCTL_DEBUG */
+
+ /* Always allocate for max space. Easier, and won't last
+ * long... */
+ extra = kmalloc(extra_size, GFP_KERNEL);
+ if (extra == NULL) {
+ return -ENOMEM;
+ }
+
+ /* If it is a SET, get all the extra data in here */
+ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+ err = copy_from_user(extra, iwr->u.data.pointer,
+ extra_size);
+ if (err) {
+ kfree(extra);
+ return -EFAULT;
+ }
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
+#endif /* WE_IOCTL_DEBUG */
+ }
+
+ /* Call the handler */
+ ret = handler(dev, &info, &(iwr->u), extra);
+
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
+ err = copy_to_user(iwr->u.data.pointer, extra,
+ extra_size);
+ if (err)
+ ret = -EFAULT;
+#ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "Wrote %d elem\n",
+ iwr->u.data.length);
+#endif /* WE_IOCTL_DEBUG */
+ }
+
+ /* Cleanup - I told you it wasn't that long ;-) */
+ kfree(extra);
+ }
+
+
+ /* Call commit handler if needed and defined */
+ if(ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main IOCTl dispatcher. Called from the main networking code
+ * (dev_ioctl() in net/core/dev.c).
+ * Check the type of IOCTL and call the appropriate wrapper...
+ */
+int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+ struct net_device *dev;
+ iw_handler handler;
+
+ /* Permissions are already checked in dev_ioctl() before calling us.
+ * The copy_to/from_user() of ifr is also dealt with in there */
+
+ /* Make sure the device exist */
+ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+ return -ENODEV;
+
+ /* A bunch of special cases, then the generic case...
+ * Note that 'cmd' is already filtered in dev_ioctl() with
+ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
+ switch(cmd)
+ {
+ case SIOCGIWSTATS:
+ /* Get Wireless Stats */
+ return dev_iwstats(dev, ifr);
+
+ case SIOCGIWPRIV:
+ /* Check if we have some wireless handlers defined */
+ if(dev->wireless_handlers != NULL) {
+ /* We export to user space the definition of
+ * the private handler ourselves */
+ return ioctl_export_private(dev, ifr);
+ }
+ // ## Fall-through for old API ##
+ default:
+ /* Generic IOCTL */
+ /* Basic check */
+ if (!netif_device_present(dev))
+ return -ENODEV;
+ /* New driver API : try to find the handler */
+ handler = get_handler(dev, cmd);
+ if(handler != NULL) {
+ /* Standard and private are not the same */
+ if(cmd < SIOCIWFIRSTPRIV)
+ return ioctl_standard_call(dev,
+ ifr,
+ cmd,
+ handler);
+ else
+ return ioctl_private_call(dev,
+ ifr,
+ cmd,
+ handler);
+ }
+ /* Old driver API : call driver ioctl handler */
+ if (dev->do_ioctl) {
+ return dev->do_ioctl(dev, ifr, cmd);
+ }
+ return -EOPNOTSUPP;
+ }
+ /* Not reached */
+ return -EINVAL;
+}
diff --git a/net/khttpd/main.c b/net/khttpd/main.c
index c0b4da163..4065e8f8f 100644
--- a/net/khttpd/main.c
+++ b/net/khttpd/main.c
@@ -390,3 +390,5 @@ void khttpd_cleanup(void)
module_init(khttpd_init)
module_exit(khttpd_cleanup)
+
+MODULE_LICENSE("GPL");
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index f9f40f245..6805ea3db 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -994,3 +994,5 @@ static void __exit netlink_proto_exit(void)
module_init(netlink_proto_init);
module_exit(netlink_proto_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/net/socket.c b/net/socket.c
index 58ac533d0..0be746b10 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -278,16 +278,17 @@ static struct super_operations sockfs_ops = {
static struct super_block * sockfs_read_super(struct super_block *sb, void *data, int silent)
{
- struct inode *root = new_inode(sb);
+ struct inode *root;
+ sb->s_blocksize = 1024;
+ sb->s_blocksize_bits = 10;
+ sb->s_magic = SOCKFS_MAGIC;
+ sb->s_op = &sockfs_ops;
+ root = new_inode(sb);
if (!root)
return NULL;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
- sb->s_blocksize = 1024;
- sb->s_blocksize_bits = 10;
- sb->s_magic = SOCKFS_MAGIC;
- sb->s_op = &sockfs_ops;
sb->s_root = d_alloc(NULL, &(const struct qstr) { "socket:", 7, 0 });
if (!sb->s_root) {
iput(root);
@@ -437,11 +438,11 @@ struct socket *sock_alloc(void)
struct inode * inode;
struct socket * sock;
- inode = get_empty_inode();
+ inode = new_inode(sock_mnt->mnt_sb);
if (!inode)
return NULL;
- inode->i_sb = sock_mnt->mnt_sb;
+ inode->i_dev = NODEV;
sock = socki_lookup(inode);
inode->i_mode = S_IFSOCK|S_IRWXUGO;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 7ca2e8d46..804b66208 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -721,7 +721,7 @@ __rpc_schedule(void)
__rpc_execute(task);
- if (++count >= 200 || current->need_resched) {
+ if (++count >= 200 || need_resched()) {
count = 0;
schedule();
}