diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Fri Jul 26 19:58:50 2002 +++ b/CREDITS Fri Jul 26 19:58:50 2002 @@ -1670,6 +1670,7 @@ D: USB Bluetooth driver, USB Skeleton driver D: bits and pieces of USB core code. D: PCI Hotplug core, PCI Hotplug Compaq driver modifications +D: portions of the Linux Security Module (LSM) framework N: Russell Kroll E: rkroll@exploits.org @@ -2155,6 +2156,14 @@ E: tmolina@cox.net D: bug fixes, documentation, minor hackery +N: James Morris +E: jmorris@intercode.com.au +W: http://www.intercode.com.au/jmorris/ +D: Netfilter, Linux Security Modules (LSM). +S: PO Box 707 +S: Spit Junction NSW 2088 +S: Australia + N: David Mosberger-Tang E: davidm@hpl.hp.com if IA-64 related, else David.Mosberger@acm.org D: Linux/Alpha and Linux/ia64 @@ -2649,6 +2658,11 @@ S: 8006 Zuerich S: Switzerland +N: Wayne Salamon +E: wsalamon@tislabs.com +E: wsalamon@nai.com +D: portions of the Linux Security Module (LSM) framework and security modules + N: Robert Sanders E: gt8134b@prism.gatech.edu D: Dosemu @@ -2775,6 +2789,11 @@ S: Minto, NSW, 2566 S: Australia +N: Stephen Smalley +E: sds@tislabs.com +E: ssmalley@nai.com +D: portions of the Linux Security Module (LSM) framework and security modules + N: Chris Smith E: csmith@convex.com D: Read only HPFS filesystem @@ -3041,6 +3060,11 @@ S: B-3128 Baal S: Belgium +N: Chris Vance +E: cvance@tislabs.com +E: cvance@nai.com +D: portions of the Linux Security Module (LSM) framework and security modules + N: Petr Vandrovec E: vandrove@vc.cvut.cz D: Small contributions to ncpfs @@ -3272,6 +3296,14 @@ S: 60 Clifton Road S: Cambridge. CB1 7EG S: England + +N: Chris Wright +E: chris@wirex.com +D: hacking on LSM framework and security modules. +S: c/o WireX +S: 920 SW 3rd, Ste. 100 +S: Portland, OR 97204 +S: USA N: Frank Xia E: qx@math.columbia.edu diff -Nru a/Documentation/00-INDEX b/Documentation/00-INDEX --- a/Documentation/00-INDEX Fri Jul 26 19:58:51 2002 +++ b/Documentation/00-INDEX Fri Jul 26 19:58:51 2002 @@ -118,6 +118,8 @@ - summary listing of command line / boot prompt args for the kernel. kmod.txt - info on the kernel module loader/unloader (kerneld replacement). +ldm.txt + - a brief description of LDM (Windows Dynamic Disks). locks.txt - info on file locking implementations, flock() vs. fcntl(), etc. logo.gif diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile --- a/Documentation/DocBook/Makefile Fri Jul 26 19:58:51 2002 +++ b/Documentation/DocBook/Makefile Fri Jul 26 19:58:51 2002 @@ -1,169 +1,161 @@ -BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ - kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ - kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ - deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \ - writing_usb_driver.sgml scsidrivers.sgml - -PS := $(patsubst %.sgml, %.ps, $(BOOKS)) -PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) -HTML := $(patsubst %.sgml, %, $(BOOKS)) -IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig -EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook)) -PNG-parportbook := $(patsubst %.fig, %.png, $(IMG-parportbook)) -C-procfs-example = procfs_example.sgml - -$(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \ -$(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc: doc-progs ; - -dochelp: - @echo ' Linux kernel internal documentation in different formats:' - @echo ' sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF), htmldocs (HTML)' - -.PHONY: doc-progs -doc-progs: - @$(MAKE) -C $(TOPDIR)/scripts doc-progs - -$(BOOKS): $(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \ - $(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc +### +# This makefile is used to generate the kernel documentation, +# primarily based on in-line comments in various source files. +# See Documentation/kernel-doc-nano-HOWTO.txt for instruction in how +# to ducument the SRC - and how to read it. +# To add a new book the only step required is to add the book to the +# list of DOCBOOKS. + +DOCBOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ + parportbook.sgml kernel-hacking.sgml \ + kernel-locking.sgml via-audio.sgml mousedrivers.sgml \ + deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \ + writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \ + kernel-api.sgml + +### +# The build process is as follows (targets): +# (sgmldocs) +# file.tmpl --> file.sgml +--> file.ps (psdocs) +# +--> file.pdf (pdfdocs) +# +--> DIR=file (htmldocs) +### +# The targets that may be used. .PHONY: sgmldocs psdocs pdfdocs htmldocs clean mrproper +BOOKS := $(addprefix Documentation/DocBook/,$(DOCBOOKS)) sgmldocs: $(BOOKS) +PS := $(patsubst %.sgml, %.ps, $(BOOKS)) psdocs: $(PS) +PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) pdfdocs: $(PDF) +HTML := $(patsubst %.sgml, %.html, $(BOOKS)) htmldocs: $(HTML) +### +#External programs used +KERNELDOC=$(objtree)/scripts/kernel-doc +DOCPROC=$(objtree)/scripts/docproc + +### +# DOCPROC is used for two purposes: +# 1) To generate a dependency list for a .tmpl file +# 2) To preprocess a .tmpl file and call kernel-doc with +# appropriate parameters. +# The following rules are used to generate the .sgml documentation +# required to generate the final targets. (ps, pdf, html). +quiet_cmd_docproc = DOCPROC $@ +cmd_docproc = $(DOCPROC) doc $< >$@ +define rule_docproc + set -e + $(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))';) + $(cmd_$(1)); \ + ( \ + echo 'cmd_$@ := $(cmd_$(1))'; \ + echo $@: `$(DOCPROC) depend $<`; \ + ) > $(dir $@).$(notdir $@).cmd +endef + +%.sgml: %.tmpl FORCE + $(call if_changed_rule,docproc) + +### +#Read in all saved dependency files +cmd_files := $(wildcard $(foreach f,$(BOOKS),$(dir $(f)).$(notdir $(f)).cmd)) + +ifneq ($(cmd_files),) + include $(cmd_files) +endif + +### +# Changes in kernel-doc force a rebuild of all documentation +$(BOOKS): $(KERNELDOC) + +### +# procfs guide uses a .c file as example code. +# This requires an explicit dependency +C-procfs-example = Documentation/DocBook/procfs_example.sgml +Documentation/DocBook/procfs-guide.sgml: $(C-procfs-example) + +### +# The parportbook includes a few images. +# Force them to be build before the books +IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig +IMG-parportbook2 := $(addprefix Documentation/DocBook/,$(IMG-parportbook)) +EPS-parportbook := $(patsubst %.fig,%.eps, $(IMG-parportbook2)) +PNG-parportbook := $(patsubst %.fig,%.png, $(IMG-parportbook2)) +Documentation/DocBook/parportbook.ps: $(EPS-parportbook) +Documentation/DocBook/parportbook.html Documentation/DocBook/parportbook.pdf:\ + $(PNG-parportbook) + +### +# Rules to generate postscript, PDF and HTML +# db2html creates a directory. Generate a html file used for timestamp +%.ps : %.sgml + @(which db2ps > /dev/null 2>&1) || \ + (echo "*** You need to install DocBook stylesheets ***"; \ + exit 1) + @echo ' DB2PS $@' + @db2ps -o $(dir $@) $< + +%.pdf : %.sgml + @(which db2pdf > /dev/null 2>&1) || \ + (echo "*** You need to install DocBook stylesheets ***"; \ + exit 1) + @echo ' DB2PDF $@' + @db2pdf -o $(dir $@) $< + +%.html: %.sgml + @(which db2html > /dev/null 2>&1) || \ + (echo "*** You need to install DocBook stylesheets ***"; \ + exit 1) + @rm -rf $@ $(patsubst %.html,%,$@) + @echo ' DB2HTML $@' + @db2html -o $(patsubst %.html,%,$@) $< && \ + echo '\ + Goto $(patsubst %.html,%,$(notdir $@))

' > $@ + @if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \ + cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi + +### +# Rules to generate postscripts and PNG imgages from .fig format files %.eps: %.fig - fig2dev -Leps $< $@ + @echo ' FIG2DEV -Leps $@' + @fig2dev -Leps $< $@ %.png: %.fig + @echo ' FIG2DEV -Lpng $@' fig2dev -Lpng $< $@ +### +# Rule to convert a .c file to inline SGML documentation %.sgml: %.c - echo "" > $@ - expand --tabs=8 < $< | \ + @echo ' Generating $@' + @echo "" > $@ + @expand --tabs=8 < $< | \ sed -e "s/&/\\&/g" \ - -e "s//\\>/g" >> $@ - echo "" >> $@ - - -mousedrivers.sgml: mousedrivers.tmpl - $(TOPDIR)/scripts/docgen <$< >$@ - -kernel-hacking.sgml: kernel-hacking.tmpl - $(TOPDIR)/scripts/docgen <$< >$@ - -kernel-locking.sgml: kernel-locking.tmpl - $(TOPDIR)/scripts/docgen <$< >$@ - -wanbook.sgml: wanbook.tmpl $(TOPDIR)/drivers/net/wan/syncppp.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/syncppp.c \ - wanbook.sgml - -z8530book.sgml: z8530book.tmpl $(TOPDIR)/drivers/net/wan/z85230.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/z85230.c \ - z8530book.sgml - -via-audio.sgml: via-audio.tmpl $(TOPDIR)/sound/oss/via82cxxx_audio.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/sound/oss/via82cxxx_audio.c \ - via-audio.sgml - -tulip-user.sgml: tulip-user.tmpl - $(TOPDIR)/scripts/docgen <$< >$@ - -writing_usb_driver.sgml: writing_usb_driver.tmpl - $(TOPDIR)/scripts/docgen <$< >$@ - -scsidrivers.sgml : scsidrivers.tmpl - $(TOPDIR)/scripts/docgen <$< >$@ - -sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \ - sis900.sgml - -deviceiobook.sgml: deviceiobook.tmpl - $(TOPDIR)/scripts/docgen deviceiobook.sgml - -mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ - mcabook.sgml - -videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \ - videobook.sgml - -procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml - $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@ - -APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \ - $(TOPDIR)/arch/i386/kernel/irq.c \ - $(TOPDIR)/arch/i386/kernel/mca.c \ - $(TOPDIR)/arch/i386/kernel/mtrr.c \ - $(TOPDIR)/drivers/char/misc.c \ - $(TOPDIR)/kernel/printk.c \ - $(TOPDIR)/drivers/net/net_init.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)/sound/sound_core.c \ - $(TOPDIR)/sound/sound_firmware.c \ - $(TOPDIR)/drivers/net/wan/syncppp.c \ - $(TOPDIR)/drivers/net/wan/z85230.c \ - $(TOPDIR)/drivers/usb/core/hcd.c \ - $(TOPDIR)/drivers/usb/core/urb.c \ - $(TOPDIR)/drivers/usb/core/message.c \ - $(TOPDIR)/drivers/usb/core/config.c \ - $(TOPDIR)/drivers/usb/core/file.c \ - $(TOPDIR)/drivers/usb/core/usb.c \ - $(TOPDIR)/drivers/video/fbmem.c \ - $(TOPDIR)/drivers/video/fbcmap.c \ - $(TOPDIR)/drivers/video/fbcon.c \ - $(TOPDIR)/drivers/video/fbgen.c \ - $(TOPDIR)/drivers/video/fonts.c \ - $(TOPDIR)/drivers/video/macmodes.c \ - $(TOPDIR)/drivers/video/modedb.c \ - $(TOPDIR)/fs/devfs/base.c \ - $(TOPDIR)/fs/locks.c \ - $(TOPDIR)/fs/bio.c \ - $(TOPDIR)/include/asm-i386/bitops.h \ - $(TOPDIR)/include/linux/usb.h \ - $(TOPDIR)/kernel/pm.c \ - $(TOPDIR)/kernel/ksyms.c \ - $(TOPDIR)/kernel/kmod.c \ - $(TOPDIR)/kernel/module.c \ - $(TOPDIR)/kernel/printk.c \ - $(TOPDIR)/kernel/sched.c \ - $(TOPDIR)/kernel/sysctl.c \ - $(TOPDIR)/lib/string.c \ - $(TOPDIR)/lib/vsprintf.c \ - $(TOPDIR)/net/netsyms.c - -kernel-api.sgml: kernel-api.tmpl $(APISOURCES) - $(TOPDIR)/scripts/docgen $(APISOURCES) \ - kernel-api.sgml - -kernel-api-man: $(APISOURCES) - @rm -rf $(TOPDIR)/Documentation/man - $(TOPDIR)/scripts/kernel-doc -man $^ | \ - $(PERL) $(TOPDIR)/scripts/split-man $(TOPDIR)/Documentation/man - -parportbook parportbook.pdf: $(PNG-parportbook) -parportbook.ps: $(EPS-parportbook) -parportbook.sgml: parportbook.tmpl $(TOPDIR)/drivers/parport/init.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/parport/init.c <$< >$@ - -DVI := $(patsubst %.sgml, %.dvi, $(BOOKS)) -AUX := $(patsubst %.sgml, %.aux, $(BOOKS)) -TEX := $(patsubst %.sgml, %.tex, $(BOOKS)) -LOG := $(patsubst %.sgml, %.log, $(BOOKS)) -OUT := $(patsubst %.sgml, %.out, $(BOOKS)) + -e "s//\\>/g" >> $@ + @echo "" >> $@ + +### +# Help targets as used by the top-level makefile +dochelp: + @echo ' Linux kernel internal documentation in different formats:' + @echo ' sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF), htmldocs (HTML)' + +### +# clean and mrproper as used by the top-level makefile +# Temporary files left by various tools +DVI := $(patsubst %.sgml, %.dvi, $(BOOKS)) +AUX := $(patsubst %.sgml, %.aux, $(BOOKS)) +TEX := $(patsubst %.sgml, %.tex, $(BOOKS)) +LOG := $(patsubst %.sgml, %.log, $(BOOKS)) +OUT := $(patsubst %.sgml, %.out, $(BOOKS)) clean: @echo 'Cleaning up (DocBook)' @@ -176,37 +168,7 @@ mrproper: @echo 'Making mrproper (DocBook)' @rm -f $(PS) $(PDF) - @rm -f -r $(HTML) - @rm -f .depend - @rm -f $(TOPDIR)/scripts/mkdep-docbook - @rm -rf DBTOHTML_OUTPUT* - -%.ps : %.sgml - @(which db2ps > /dev/null 2>&1) || \ - (echo "*** You need to install DocBook stylesheets ***"; \ - exit 1) - db2ps $< - -%.pdf : %.sgml - @(which db2pdf > /dev/null 2>&1) || \ - (echo "*** You need to install DocBook stylesheets ***"; \ - exit 1) - db2pdf $< - -%: %.sgml - @(which db2html > /dev/null 2>&1) || \ - (echo "*** You need to install DocBook stylesheets ***"; \ - exit 1) - rm -rf $@ - db2html $< - if [ ! -z "$(PNG-$@)" ]; then cp $(PNG-$@) $@; fi - -# -# we could have our own dependency generator -# -# -# .depend: $(TOPDIR)/scripts/mkdep-docbook -# $(TOPDIR)/scripts/mkdep-docbook $(wildcard *.tmpl) > .depend + @rm -f -r $(HTML) $(patsubst %.html,%,$(HTML)) include $(TOPDIR)/Rules.make diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl --- a/Documentation/DocBook/kernel-api.tmpl Fri Jul 26 19:58:50 2002 +++ b/Documentation/DocBook/kernel-api.tmpl Fri Jul 26 19:58:50 2002 @@ -50,7 +50,7 @@ kernel/sched.c has no docs, which stuffs up the sgml. Comment out until somebody adds docs. KAO Delaying, scheduling, and timer routines -!Ekernel/sched.c +X!Ekernel/sched.c KAO --> @@ -305,7 +305,8 @@ 16x50 UART Driver -!Edrivers/char/serial.c +!Edrivers/serial/core.c +!Edrivers/serial/8250.c @@ -366,7 +367,7 @@ drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment out until somebody adds docs. KAO Frame Buffer Generic Functions -!Idrivers/video/fbgen.c +X!Idrivers/video/fbgen.c KAO --> Frame Buffer Video Mode Database @@ -380,5 +381,9 @@ !Idrivers/video/fonts.c - + diff -Nru a/Documentation/DocBook/parportbook.tmpl b/Documentation/DocBook/parportbook.tmpl --- a/Documentation/DocBook/parportbook.tmpl Fri Jul 26 19:58:50 2002 +++ b/Documentation/DocBook/parportbook.tmpl Fri Jul 26 19:58:50 2002 @@ -2729,7 +2729,9 @@ - + diff -Nru a/Documentation/cli-sti-removal.txt b/Documentation/cli-sti-removal.txt --- a/Documentation/cli-sti-removal.txt Fri Jul 26 19:58:51 2002 +++ b/Documentation/cli-sti-removal.txt Fri Jul 26 19:58:51 2002 @@ -96,8 +96,8 @@ drivers that want to disable local interrupts (interrupts on the current CPU), can use the following five macros: - local_irq_disable(), local_irq_enable(), local_irq_save(flags), - local_irq_save_off(flags), local_irq_restore(flags) + local_irq_disable(), local_irq_enable(), local_save_flags(flags), + local_irq_save(flags), local_irq_restore(flags) but beware, their meaning and semantics are much simpler, far from that of the old cli(), sti(), save_flags(flags) and restore_flags(flags) @@ -107,11 +107,11 @@ local_irq_enable() => turn local IRQs on - local_irq_save(flags) => save the current IRQ state into flags. The + local_save_flags(flags) => save the current IRQ state into flags. The state can be on or off. (on some architectures there's even more bits in it.) - local_irq_save_off(flags) => save the current IRQ state into flags and + local_irq_save(flags) => save the current IRQ state into flags and disable interrupts. local_irq_restore(flags) => restore the IRQ state from flags. diff -Nru a/Documentation/input/input-programming.txt b/Documentation/input/input-programming.txt --- a/Documentation/input/input-programming.txt Fri Jul 26 19:58:50 2002 +++ b/Documentation/input/input-programming.txt Fri Jul 26 19:58:50 2002 @@ -23,6 +23,7 @@ static void button_interrupt(int irq, void *dummy, struct pt_regs *fp) { input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1); + input_sync(&button_dev); } static int __init button_init(void) @@ -86,12 +87,21 @@ which upon every interrupt from the button checks its state and reports it via the - input_report_btn() + input_report_key() call to the input system. There is no need to check whether the interrupt routine isn't reporting two same value events (press, press for example) to the input system, because the input_report_* functions check that themselves. + +Then there is the + + input_sync() + +call to tell those who receive the events that we've sent a complete report. +This doesn't seem important in the one button case, but is quite important +for for example mouse movement, where you don't want the X and Y values +to be interpreted separately, because that'd result in a different movement. 1.2 dev->open() and dev->close() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -Nru a/Documentation/input/input.txt b/Documentation/input/input.txt --- a/Documentation/input/input.txt Fri Jul 26 19:58:51 2002 +++ b/Documentation/input/input.txt Fri Jul 26 19:58:51 2002 @@ -207,7 +207,7 @@ these. You'll need ImPS/2 if you want to make use of a wheel on a USB mouse and ExplorerPS/2 if you want to use extra (up to 5) buttons. -3.2.3 joydev.c +3.2.3 joydev.o ~~~~~~~~~~~~~~ Joydev implements v0.x and v1.x Linux joystick api, much like drivers/char/joystick/joystick.c used to in earlier versions. See diff -Nru a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt --- a/Documentation/input/xpad.txt Fri Jul 26 19:58:52 2002 +++ b/Documentation/input/xpad.txt Fri Jul 26 19:58:52 2002 @@ -1,8 +1,11 @@ -usb-xpad - Linux USB driver for XBOX HID gamecontrollers +xpad - Linux USB driver for X-Box gamepads -This is the very first release of a driver for XBOX gamecontrollers. +This is the very first release of a driver for X-Box gamepads. Basically, this was hacked away in just a few hours, so don't expect miracles. +In particular, there is currently NO support for the rumble pack. +You won't find many ff-aware linux applications anyway. + 0. Status --------- @@ -14,31 +17,38 @@ 8 axes and 10 buttons. Alls 8 axes work, though they all have the same range (-32768..32767) -and the zero-setting is not correct for the triggers. -9 of the 10 buttons work (my black button does not work, though I can -see no reason for it not to), all of them are in digital mode, though -(the six buttons on the right side are "analog" ones). +and the zero-setting is not correct for the triggers (I don't know if that +is some limitation of jstest, since the input device setup should be fine. I +didn't have a look at jstest itself yet). + +All of the 10 buttons work (in digital mode). The six buttons on the +right side (A, B, X, Y, black, white) are said to be "analog" and +report their values as 8 bit unsigned, not sure what this is good for. + +I tested the controller with quake3, and configuration and +in game functionality were OK. However, I find it rather difficult to +play first person shooters with a pad. Your mileage may vary. 1. USB adapter -------------- Before you can actually use the driver, you need to get yourself an -adapter cable to connect the XBOX-controller to your Linux-Box. +adapter cable to connect the X-Box controller to your Linux-Box. -Such a cable is pretty easy to build. The Controller itself is a USB device -(a hub with three ports; two expansion slots and the controller device) -with the only differnce in a nonstandard connector (5 pins vs. 4 on +Such a cable is pretty easy to build. The Controller itself is a USB compound +device (a hub with three ports for two expansion slots and the controller +device) with the only difference in a nonstandard connector (5 pins vs. 4 on standard USB connector). -You just need to solder an USB connector onto the cable and keep the +You just need to solder a USB connector onto the cable and keep the yellow wire unconnected. The other pins have the same order on both -connectors so there no magic to it. Detailed info on these matters can be found -on the net. +connectors so there is no magic to it. Detailed info on these matters +can be found on the net ([1], [2], [3]). Thanks to the trip splitter found on the cable you don't even need to cut the -original cable, you can buy an extension cable and cut that instead. That way, -you can still use the controller with your XBOX, if you have one ;) +original one. You can buy an extension cable and cut that instead. That way, +you can still use the controller with your X-Box, if you have one ;) 2. driver installation @@ -46,22 +56,26 @@ Once you have the adapter cable and the controller is connected, you need to load your USB subsystem and should cat /proc/bus/usb/devices. -There should be an entry like the one in InterAct_german.dump. +There should be an entry like the one at the end [4]. -Don't worry if the vendor and/or product ID don't match, those are easy to -add to the driver. You could do it yourself, just add the appropriate line -into the list after the line - '} xpad_device[] = {' -, but before the line that says - '{ 0x0000, 0x0000, "unknown...." }'. +Currently (as of version 0.0.4), the following three devices are included: + original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 + original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285 + InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a + +If you have another controller that is not listed above and is not recognized +by the driver, please drop me a line with the appropriate info (that is, include +the name, vendor and product ID, as well as the country where you bought it; +sending the whole dump out of /proc/bus/usb/devices along would be even better). In theory, the driver should work with other controllers than mine -(InterAct PowerPad pro, bought in Germany) just fine, but see for yourself. +(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this +for I only have this one controller. If you compiled and installed the driver, test the functionality: -> modprobe usb-xpad +> modprobe xpad > modprobe joydev -> jstest /dev/input/js0 +> jstest /dev/js0 There should be a single line showing 18 inputs (8 axes, 10 buttons), and it's values should change if you move the sticks and push the buttons. @@ -76,9 +90,27 @@ http://euc.jp/periphs/xbox-controller.ja.html. His useful info and both the usb-skeleton as well as the iforce input driver -helped a lot in rapid prototyping the basic functionality. +(Greg Kroah-Hartmann; Vojtech Pavlik) helped a lot in rapid prototyping +the basic functionality. + + +4. References +------------- +1. http://euc.jp/periphs/xbox-controller.ja.html (ITO Takayuki) +2. http://xpad.xbox-scene.com/ +3. http://www.xboxhackz.com/Hackz-Reference.htm + +4. /proc/bus/usb/devices - dump from InterAct PowerPad Pro (Germany): + +T: Bus=01 Lev=03 Prnt=04 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 +D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=32 #Cfgs= 1 +P: Vendor=05fd ProdID=107a Rev= 1.00 +C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none) +E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms +E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms -- Marko Friedemann -2002-07-02 +2002-07-16 diff -Nru a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt --- a/Documentation/kernel-doc-nano-HOWTO.txt Fri Jul 26 19:58:51 2002 +++ b/Documentation/kernel-doc-nano-HOWTO.txt Fri Jul 26 19:58:51 2002 @@ -20,18 +20,14 @@ - scripts/docproc.c This is a program for converting SGML template files into SGML - files. It invokes kernel-doc, giving it the list of functions that + files. When a file is referenced it is searched for symbols + exported (EXPORT_SYMBOL), to be able to distingush between internal + and external functions. + It invokes kernel-doc, giving it the list of functions that are to be documented. - -- scripts/gen-all-syms - - This is a script that lists the EXPORT_SYMBOL symbols in a list of C - files. - -- scripts/docgen - - This script invokes docproc, telling it which functions are to be - documented (this list comes from gen-all-syms). + Additionally it is used to scan the SGML template files to locate + all the files referenced herein. This is used to generate dependency + information as used by make. - Makefile @@ -141,6 +137,10 @@ !I is replaced by the documentation for functions that are _not_ exported using EXPORT_SYMBOL. + +!D is used to name additional files to search for functions +exported using EXPORT_SYMBOL. For example many symbols are only exported +in kernel/ksyms.c, therefore kernel-api.sgml include this file with !D. !F is replaced by the documentation, in , for the functions listed. diff -Nru a/Documentation/ldm.txt b/Documentation/ldm.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/ldm.txt Fri Jul 26 19:58:52 2002 @@ -0,0 +1,102 @@ + + LDM - Logical Disk Manager (Dynamic Disks) + ------------------------------------------ + +Overview +-------- + +Windows 2000 and XP use a new partitioning scheme. It is a complete +replacement for the MSDOS style partitions. It stores its information in a +1MiB journalled database at the end of the physical disk. The size of +partitions is limited only by disk space. The maximum number of partitions is +nearly 2000. + +Any partitions created under the LDM are called "Dynamic Disks". There are no +longer any primary or extended partitions. Normal MSDOS style partitions are +now known as Basic Disks. + +If you wish to use Spanned, Striped, Mirrored or RAID 5 Volumes, you must use +Dynamic Disks. The journalling allows Windows to make changes to these +partitions and filesystems without the need to reboot. + +Once the LDM driver has divided up the disk, you can use the MD driver to +assemble any multi-partition volumes, e.g. Stripes, RAID5. + +To prevent legacy applications from repartitioning the disk, the LDM creates a +dummy MSDOS partition containing one disk-sized partition. + + +Example +------- + +Below we have a 50MiB disk, divided into seven partitions. +N.B. The missing 1MiB at the end of the disk is where the LDM database is + stored. + + Device | Offset Bytes Sectors MiB | Size Bytes Sectors MiB + -------+----------------------------+--------------------------- + hda | 0 0 0 | 52428800 102400 50 + hda1 | 51380224 100352 49 | 1048576 2048 1 + hda2 | 16384 32 0 | 6979584 13632 6 + hda3 | 6995968 13664 6 | 10485760 20480 10 + hda4 | 17481728 34144 16 | 4194304 8192 4 + hda5 | 21676032 42336 20 | 5242880 10240 5 + hda6 | 26918912 52576 25 | 10485760 20480 10 + hda7 | 37404672 73056 35 | 13959168 27264 13 + +The LDM Database may not store the partitions in the order that they appear on +disk, but the driver will sort them. + +When Linux boots, you will see something like: + + hda: 102400 sectors w/32KiB Cache, CHS=50/64/32 + hda: [LDM] hda1 hda2 hda3 hda4 hda5 hda6 hda7 + + +Compiling LDM Support +--------------------- + +To enable LDM, choose the following two options: + + "Advanced partition selection" CONFIG_PARTITION_ADVANCED + "Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION + +If you believe the driver isn't working as it should, you can enable the extra +debugging code. This will produce a LOT of output. The option is: + + "Windows LDM extra logging" CONFIG_LDM_DEBUG + +N.B. The partition code cannot be compiled as a module. + +As with all the partition code, if the driver doesn't see signs of its type of +partition, it will pass control to another driver, so there is no harm in +enabling it. + +If you have Dynamic Disks but don't enable the driver, then all you will see +is a dummy MSDOS partition filling the whole disk. You won't be able to mount +any of the volumes on the disk. + + +Booting +------- + +If you enable LDM support, then lilo is capable of booting from any of the +discovered partitions. However, grub does not understand the LDM partitioning +and cannot boot from a Dynamic Disk. + + +More Documentation +------------------ + +There is an Overview of the LDM online together with complete Technical +Documentation. It can also be downloaded in html. + + http://linux-ntfs.sourceforge.net/ldm/index.html + http://linux-ntfs.sourceforge.net/downloads.html + +If you have any LDM questions that aren't answered on the website, email me. + +Cheers, + FlatCap - Richard Russon + ldm@flatcap.org + diff -Nru a/Documentation/serial/driver b/Documentation/serial/driver --- a/Documentation/serial/driver Fri Jul 26 19:58:50 2002 +++ b/Documentation/serial/driver Fri Jul 26 19:58:50 2002 @@ -120,7 +120,7 @@ TTY stop to the driver (equiv to rs_stop). Locking: port->lock taken. - Interrupts: caller dependent. + Interrupts: locally disabled. This call must not sleep start_tx(port,tty_start) diff -Nru a/Makefile b/Makefile --- a/Makefile Fri Jul 26 19:58:50 2002 +++ b/Makefile Fri Jul 26 19:58:50 2002 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 28 +SUBLEVEL = 29 EXTRAVERSION = # *DOCUMENTATION* @@ -166,6 +166,15 @@ help tags TAGS sgmldocs psdocs pdfdocs htmldocs \ checkconfig checkhelp checkincludes +# Helpers built in scripts/ +# --------------------------------------------------------------------------- + +scripts/docproc scripts/fixdep scripts/split-include : scripts ; + +.PHONY: scripts +scripts: + @$(MAKE) -C scripts + ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),) # Here goes the main Makefile @@ -212,7 +221,7 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) -CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -g \ +CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ -fomit-frame-pointer -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) @@ -357,15 +366,6 @@ ) > $@.tmp @$(update-if-changed) -# Helpers built in scripts/ -# --------------------------------------------------------------------------- - -scripts/fixdep scripts/split-include : scripts ; - -.PHONY: scripts -scripts: - @$(MAKE) -C scripts - # Generate module versions # --------------------------------------------------------------------------- @@ -650,7 +650,7 @@ -name .\*.tmp -o -name .\*.d \) -type f -print \ | grep -v lxdialog/ | xargs rm -f @rm -f $(CLEAN_FILES) - @$(MAKE) -C Documentation/DocBook clean + @$(MAKE) -f Documentation/DocBook/Makefile clean mrproper: clean archmrproper @echo 'Making mrproper' @@ -659,7 +659,7 @@ -type f -print | xargs rm -f @rm -f $(MRPROPER_FILES) @rm -rf $(MRPROPER_DIRS) - @$(MAKE) -C Documentation/DocBook mrproper + @$(MAKE) -f Documentation/DocBook/Makefile mrproper distclean: mrproper @echo 'Making distclean' @@ -732,10 +732,8 @@ # Documentation targets # --------------------------------------------------------------------------- - -sgmldocs psdocs pdfdocs htmldocs: - @$(MAKE) -C Documentation/DocBook $@ - +sgmldocs psdocs pdfdocs htmldocs: scripts + @$(MAKE) -f Documentation/DocBook/Makefile $@ # Scripts to check various things for consistency # --------------------------------------------------------------------------- diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in --- a/arch/alpha/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/alpha/config.in Fri Jul 26 19:58:51 2002 @@ -283,9 +283,9 @@ fi mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -393,4 +393,5 @@ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/arm/config.in b/arch/arm/config.in --- a/arch/arm/config.in Fri Jul 26 19:58:50 2002 +++ b/arch/arm/config.in Fri Jul 26 19:58:50 2002 @@ -529,9 +529,9 @@ fi mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -658,4 +658,5 @@ dep_bool ' Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/cris/config.in b/arch/cris/config.in --- a/arch/cris/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/cris/config.in Fri Jul 26 19:58:51 2002 @@ -228,5 +228,7 @@ int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi -source lib/Config.in endmenu + +source security/Config.in +source lib/Config.in diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/i386/config.in Fri Jul 26 19:58:51 2002 @@ -298,18 +298,10 @@ source drivers/block/Config.in -source drivers/md/Config.in - -if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in -fi - -source drivers/telephony/Config.in - mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL device support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL device support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -319,15 +311,32 @@ endmenu mainmenu_option next_comment -comment 'SCSI support' +comment 'SCSI device support' -tristate 'SCSI support' CONFIG_SCSI +tristate 'SCSI device support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi endmenu +mainmenu_option next_comment +comment 'Old non-SCSI/ATAPI CD-ROM drives' + +bool 'Support non-SCSI/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in +fi +endmenu + +source drivers/md/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +source drivers/telephony/Config.in + source drivers/message/fusion/Config.in source drivers/ieee1394/Config.in @@ -353,15 +362,6 @@ source net/irda/Config.in source drivers/isdn/Config.in - -mainmenu_option next_comment -comment 'Old CD-ROM drivers (not SCSI, not IDE)' - -bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI -if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then - source drivers/cdrom/Config.in -fi -endmenu # # input before char - char/joystick depends on it. As does USB. diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c Fri Jul 26 19:58:51 2002 +++ b/arch/i386/kernel/apic.c Fri Jul 26 19:58:51 2002 @@ -796,9 +796,9 @@ apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); } -void setup_APIC_timer(void * data) +static void setup_APIC_timer(unsigned int clocks) { - unsigned int clocks = (unsigned int) data, slice, t0, t1; + unsigned int slice, t0, t1; unsigned long flags; int delta; @@ -924,7 +924,7 @@ int dont_use_local_apic_timer __initdata = 0; -void __init setup_APIC_clocks (void) +void __init setup_boot_APIC_clock(void) { /* Disabled by DMI scan or kernel option? */ if (dont_use_local_apic_timer) @@ -939,12 +939,16 @@ /* * Now set up the timer for real. */ - setup_APIC_timer((void *)calibration_result); + setup_APIC_timer(calibration_result); local_irq_enable(); +} - /* and update all other cpus */ - smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1); +void __init setup_secondary_APIC_clock(void) +{ + local_irq_disable(); /* FIXME: Do we need this? --RR */ + setup_APIC_timer(calibration_result); + local_irq_enable(); } void __init disable_APIC_timer(void) @@ -1177,7 +1181,7 @@ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); #endif - setup_APIC_clocks(); + setup_boot_APIC_clock(); return 0; } diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c --- a/arch/i386/kernel/apm.c Fri Jul 26 19:58:50 2002 +++ b/arch/i386/kernel/apm.c Fri Jul 26 19:58:50 2002 @@ -1589,7 +1589,7 @@ p = buf; - if ((num_online_cpus() == 1) && + if ((num_possible_cpus() == 1) && !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; @@ -1720,7 +1720,7 @@ } } - if (debug && (num_online_cpus() == 1)) { + if (debug && (num_possible_cpus() == 1)) { error = apm_get_power_status(&bx, &cx, &dx); if (error) printk(KERN_INFO "apm: power status not available\n"); @@ -1764,7 +1764,7 @@ pm_power_off = apm_power_off; register_sysrq_key('o', &sysrq_poweroff_op); - if (num_online_cpus() == 1) { + if (num_possible_cpus() == 1) { #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) console_blank_hook = apm_console_blank; #endif @@ -1907,9 +1907,7 @@ printk(KERN_NOTICE "apm: disabled on user request.\n"); return -ENODEV; } - /* FIXME: When boot code changes, this will need to be - deactivated when/if a CPU comes up --RR */ - if ((num_online_cpus() > 1) && !power_off) { + if ((num_possible_cpus() > 1) && !power_off) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); return -ENODEV; } @@ -1924,35 +1922,38 @@ * that extends up to the end of page zero (that we have reserved). * This is for buggy BIOS's that refer to (real mode) segment 0x40 * even though they are called in protected mode. + * + * NOTE: on SMP we call into the APM BIOS only on CPU#0, so it's + * enough to modify CPU#0's GDT. */ - set_base(gdt[APM_40 >> 3], + set_base(cpu_gdt_table[0][APM_40 >> 3], __va((unsigned long)0x40 << 4)); - _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); + _set_limit((char *)&cpu_gdt_table[0][APM_40 >> 3], 4095 - (0x40 << 4)); apm_bios_entry.offset = apm_info.bios.offset; apm_bios_entry.segment = APM_CS; - set_base(gdt[APM_CS >> 3], + set_base(cpu_gdt_table[0][APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); - set_base(gdt[APM_CS_16 >> 3], + set_base(cpu_gdt_table[0][APM_CS_16 >> 3], __va((unsigned long)apm_info.bios.cseg_16 << 4)); - set_base(gdt[APM_DS >> 3], + set_base(cpu_gdt_table[0][APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ - _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1); + _set_limit((char *)&cpu_gdt_table[0][APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ - _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1); + _set_limit((char *)&cpu_gdt_table[0][APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ - _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1); + _set_limit((char *)&cpu_gdt_table[0][APM_DS >> 3], 64 * 1024 - 1); #ifndef APM_RELAX_SEGMENTS } else { - _set_limit((char *)&gdt[APM_CS >> 3], + _set_limit((char *)&cpu_gdt_table[0][APM_CS >> 3], (apm_info.bios.cseg_len - 1) & 0xffff); - _set_limit((char *)&gdt[APM_CS_16 >> 3], + _set_limit((char *)&cpu_gdt_table[0][APM_CS_16 >> 3], (apm_info.bios.cseg_16_len - 1) & 0xffff); - _set_limit((char *)&gdt[APM_DS >> 3], + _set_limit((char *)&cpu_gdt_table[0][APM_DS >> 3], (apm_info.bios.dseg_len - 1) & 0xffff); } #endif @@ -1963,9 +1964,7 @@ kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); - /* FIXME: When boot code changes, this will need to be - deactivated when/if a CPU comes up --RR */ - if (num_online_cpus() > 1) { + if (num_possible_cpus() > 1) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe (power off active).\n"); return 0; diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c --- a/arch/i386/kernel/cpu/common.c Fri Jul 26 19:58:50 2002 +++ b/arch/i386/kernel/cpu/common.c Fri Jul 26 19:58:50 2002 @@ -421,14 +421,14 @@ */ void __init cpu_init (void) { - int nr = smp_processor_id(); - struct tss_struct * t = &init_tss[nr]; + int cpu = smp_processor_id(); + struct tss_struct * t = init_tss + cpu; - if (test_and_set_bit(nr, &cpu_initialized)) { - printk(KERN_WARNING "CPU#%d already initialized!\n", nr); + if (test_and_set_bit(cpu, &cpu_initialized)) { + printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); for (;;) local_irq_enable(); } - printk(KERN_INFO "Initializing CPU#%d\n", nr); + printk(KERN_INFO "Initializing CPU#%d\n", cpu); if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); @@ -441,7 +441,17 @@ } #endif - __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); + /* + * Initialize the per-CPU GDT with the boot GDT, + * and set up the GDT descriptor: + */ + if (cpu) { + memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE); + cpu_gdt_descr[cpu].size = GDT_SIZE; + cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu]; + } + + __asm__ __volatile__("lgdt %0": "=m" (cpu_gdt_descr[cpu])); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); /* @@ -450,18 +460,18 @@ __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); /* - * set up and load the per-CPU TSS and LDT + * Set up and load the per-CPU TSS and LDT */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; if(current->mm) BUG(); - enter_lazy_tlb(&init_mm, current, nr); + enter_lazy_tlb(&init_mm, current, cpu); t->esp0 = current->thread.esp0; - set_tss_desc(nr,t); - gdt_table[__TSS(nr)].b &= 0xfffffdff; - load_TR(nr); + set_tss_desc(cpu,t); + cpu_gdt_table[cpu][TSS_ENTRY].b &= 0xfffffdff; + load_TR_desc(); load_LDT(&init_mm.context); /* Clear %fs and %gs. */ diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Fri Jul 26 19:58:51 2002 +++ b/arch/i386/kernel/entry.S Fri Jul 26 19:58:51 2002 @@ -417,7 +417,6 @@ ENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL - GET_THREAD_INFO(%ebx) movl %cr0, %eax testl $0x4, %eax # EM (math emulation bit) jne device_not_available_emulate @@ -753,6 +752,7 @@ .long sys_futex /* 240 */ .long sys_sched_setaffinity .long sys_sched_getaffinity + .long sys_set_thread_area .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S --- a/arch/i386/kernel/head.S Fri Jul 26 19:58:50 2002 +++ b/arch/i386/kernel/head.S Fri Jul 26 19:58:50 2002 @@ -231,7 +231,7 @@ call check_x87 incb ready - lgdt gdt_descr + lgdt cpu_gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers @@ -338,29 +338,28 @@ iret /* - * The interrupt descriptor table has room for 256 idt's, - * the global descriptor table is dependent on the number - * of tasks we can have.. + * The IDT and GDT 'descriptors' are a strange 48-bit object + * only used by the lidt and lgdt instructions. They are not + * like usual segment descriptors - they consist of a 16-bit + * segment size, and 32-bit linear address value: */ -#define IDT_ENTRIES 256 -#define GDT_ENTRIES (__TSS(NR_CPUS)) - -.globl idt -.globl gdt +.globl idt_descr +.globl cpu_gdt_descr ALIGN - .word 0 + .word 0 # 32-bit align idt_desc.address idt_descr: .word IDT_ENTRIES*8-1 # idt contains 256 entries -idt: .long idt_table - .word 0 -gdt_descr: +# boot GDT descriptor (later on used by CPU#0): + +cpu_gdt_descr: .word GDT_ENTRIES*8-1 -gdt: - .long gdt_table + .long cpu_gdt_table + + .fill NR_CPUS-1,6,0 # space for the other GDT descriptors /* * This is initialized to create an identity-mapping at 0-8M (for bootup @@ -413,20 +412,17 @@ ALIGN /* - * This contains typically 140 quadwords, depending on NR_CPUS. - * - * NOTE! Make sure the gdt descriptor in head.S matches this if you - * change anything. + * The Global Descriptor Table contains 20 quadwords, per-CPU. */ -ENTRY(gdt_table) +ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ - .quad 0x0000000000000000 /* not used */ + .quad 0x0000000000000000 /* TLS descriptor */ .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ - .quad 0x0000000000000000 /* not used */ - .quad 0x0000000000000000 /* not used */ + .quad 0x0000000000000000 /* TSS descriptor */ + .quad 0x0000000000000000 /* LDT descriptor */ /* * The APM segments have byte granularity and their bases * and limits are set at run time. @@ -444,5 +440,8 @@ .quad 0x0000000000000000 /* 0x88 not used */ .quad 0x0000000000000000 /* 0x90 not used */ .quad 0x0000000000000000 /* 0x98 not used */ - /* Per CPU segments */ - .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ + +#if CONFIG_SMP + .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ +#endif + diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Fri Jul 26 19:58:51 2002 +++ b/arch/i386/kernel/i386_ksyms.c Fri Jul 26 19:58:51 2002 @@ -74,7 +74,6 @@ EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(apm_info); -EXPORT_SYMBOL(gdt); #ifdef CONFIG_DEBUG_IOVIRT EXPORT_SYMBOL(__io_virt_debug); diff -Nru a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c --- a/arch/i386/kernel/mtrr.c Fri Jul 26 19:58:50 2002 +++ b/arch/i386/kernel/mtrr.c Fri Jul 26 19:58:50 2002 @@ -1055,7 +1055,7 @@ wait_barrier_cache_disable = TRUE; wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; - atomic_set (&undone_count, num_online_cpus() - 1); + atomic_set (&undone_count, num_booting_cpus() - 1); /* Start the ball rolling on other CPUs */ if (smp_call_function (ipi_handler, &data, 1, 0) != 0) panic ("mtrr: timed out waiting for other CPUs\n"); @@ -1064,14 +1064,14 @@ /* Wait for all other CPUs to flush and disable their caches */ while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, num_online_cpus() - 1); + atomic_set (&undone_count, num_booting_cpus() - 1); wait_barrier_cache_disable = FALSE; set_mtrr_cache_disable (&ctxt); /* Wait for all other CPUs to flush and disable their caches */ while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, num_online_cpus() - 1); + atomic_set (&undone_count, num_booting_cpus() - 1); wait_barrier_execute = FALSE; (*set_mtrr_up) (reg, base, size, type, FALSE); /* Now wait for other CPUs to complete the function */ diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c --- a/arch/i386/kernel/nmi.c Fri Jul 26 19:58:51 2002 +++ b/arch/i386/kernel/nmi.c Fri Jul 26 19:58:51 2002 @@ -72,19 +72,22 @@ int __init check_nmi_watchdog (void) { - irq_cpustat_t tmp[NR_CPUS]; + unsigned int prev_nmi_count[NR_CPUS]; int cpu; printk(KERN_INFO "testing NMI watchdog ... "); - memcpy(tmp, irq_stat, sizeof(tmp)); + for (cpu = 0; cpu < NR_CPUS; cpu++) + prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count; local_irq_enable(); mdelay((10*1000)/nmi_hz); // wait 10 ticks + /* FIXME: Only boot CPU is online at this stage. Check CPUs + as they come up. */ for (cpu = 0; cpu < NR_CPUS; cpu++) { if (!cpu_online(cpu)) continue; - if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) { + if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck!\n", cpu); return -1; } diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c Fri Jul 26 19:58:49 2002 +++ b/arch/i386/kernel/process.c Fri Jul 26 19:58:50 2002 @@ -662,7 +662,8 @@ { struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; - struct tss_struct *tss = init_tss + smp_processor_id(); + int cpu = smp_processor_id(); + struct tss_struct *tss = init_tss + cpu; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -689,6 +690,14 @@ } /* + * Load the per-thread Thread-Local Storage descriptor. + * + * NOTE: it's faster to do the two stores unconditionally + * than to branch away. + */ + load_TLS_desc(next, cpu); + + /* * Now maybe reload the debug registers */ if (unlikely(next->debugreg[7])) { @@ -818,3 +827,58 @@ } #undef last_sched #undef first_sched + +/* + * Set the Thread-Local Storage area: + */ +asmlinkage int sys_set_thread_area(unsigned int base, unsigned int limit, unsigned int flags) +{ + struct thread_struct *t = ¤t->thread; + int limit_in_pages = 0, writable = 0; + int cpu; + + /* do not allow unused flags */ + if (flags & ~TLS_FLAGS_MASK) + return -EINVAL; + + /* check limit */ + if (limit & 0xfff00000) + return -EINVAL; + + /* + * Clear the TLS? + */ + if (flags & TLS_FLAG_CLEAR) { + cpu = get_cpu(); + t->tls_base = t->tls_limit = t->tls_flags = 0; + t->tls_desc.a = t->tls_desc.b = 0; + load_TLS_desc(t, cpu); + put_cpu(); + return 0; + } + + if (flags & TLS_FLAG_LIMIT_IN_PAGES) + limit_in_pages = 1; + if (flags & TLS_FLAG_WRITABLE) + writable = 1; + + /* + * We must not get preempted while modifying the TLS. + */ + cpu = get_cpu(); + t->tls_base = base; + t->tls_limit = limit; + t->tls_flags = flags; + + t->tls_desc.a = ((base & 0x0000ffff) << 16) | (limit & 0x0ffff); + + t->tls_desc.b = (base & 0xff000000) | ((base & 0x00ff0000) >> 16) | + (limit & 0xf0000) | (writable << 9) | (1 << 15) | + (1 << 22) | (limit_in_pages << 23) | 0x7000; + + load_TLS_desc(t, cpu); + put_cpu(); + + return TLS_ENTRY*8 + 3; +} + diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c --- a/arch/i386/kernel/smp.c Fri Jul 26 19:58:50 2002 +++ b/arch/i386/kernel/smp.c Fri Jul 26 19:58:50 2002 @@ -646,7 +646,10 @@ /* * At this point the info structure may be out of scope unless wait==1 */ + irq_enter(); (*func)(info); + irq_exit(); + if (wait) { mb(); atomic_inc(&call_data->finished); diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Fri Jul 26 19:58:51 2002 +++ b/arch/i386/kernel/smpboot.c Fri Jul 26 19:58:51 2002 @@ -31,7 +31,7 @@ * Maciej W. Rozycki : Bits for genuine 82489DX APICs * Martin J. Bligh : Added support for multi-quad systems * Dave Jones : Report invalid combinations of Athlon CPUs. - */ +* Rusty Russell : Hacked into shape for new "hotplug" boot process. */ #include #include @@ -53,9 +53,6 @@ /* Set if we find a B stepping CPU */ static int __initdata smp_b_stepping; -/* Setup configured maximum number of CPUs to activate */ -static int __initdata max_cpus = NR_CPUS; - /* Number of siblings per CPU package */ int smp_num_siblings = 1; int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ @@ -64,7 +61,8 @@ unsigned long cpu_online_map; static volatile unsigned long cpu_callin_map; -static volatile unsigned long cpu_callout_map; +volatile unsigned long cpu_callout_map; +static unsigned long smp_commenced_mask; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; @@ -73,33 +71,6 @@ int smp_threads_ready; /* - * Setup routine for controlling SMP activation - * - * Command-line option of "nosmp" or "maxcpus=0" will disable SMP - * activation entirely (the MPS table probe still happens, though). - * - * Command-line option of "maxcpus=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . - */ - -static int __init nosmp(char *str) -{ - max_cpus = 0; - return 1; -} - -__setup("nosmp", nosmp); - -static int __init maxcpus(char *str) -{ - get_option(&str, &max_cpus); - return 1; -} - -__setup("maxcpus=", maxcpus); - -/* * Trampoline 80x86 program as an array. */ @@ -139,7 +110,7 @@ * a given CPU */ -void __init smp_store_cpu_info(int id) +static void __init smp_store_cpu_info(int id) { struct cpuinfo_x86 *c = cpu_data + id; @@ -193,29 +164,6 @@ } /* - * Architecture specific routine called by the kernel just before init is - * fired off. This allows the BP to have everything in order [we hope]. - * At the end of this all the APs will hit the system scheduling and off - * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over - * and give them jobs to do. smp_callin is a standard routine - * we use to track CPUs as they power up. - */ - -static atomic_t smp_commenced = ATOMIC_INIT(0); - -void __init smp_commence(void) -{ - /* - * Lets the callins below out of their loop. - */ - Dprintk("Setting commenced=1, go go go\n"); - - wmb(); - atomic_set(&smp_commenced,1); -} - -/* * TSC synchronization. * * We first check wether all CPUs have their TSC's synchronized, @@ -268,7 +216,7 @@ unsigned long one_usec; int buggy = 0; - printk("checking TSC synchronization across CPUs: "); + printk("checking TSC synchronization across %u CPUs: ", num_booting_cpus()); one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2); @@ -289,7 +237,7 @@ /* * all APs synchronize but they loop on '== num_cpus' */ - while (atomic_read(&tsc_count_start) != num_online_cpus()-1) + while (atomic_read(&tsc_count_start) != num_booting_cpus()-1) mb(); atomic_set(&tsc_count_stop, 0); wmb(); @@ -308,7 +256,7 @@ /* * Wait for all APs to leave the synchronization point: */ - while (atomic_read(&tsc_count_stop) != num_online_cpus()-1) + while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1) mb(); atomic_set(&tsc_count_start, 0); wmb(); @@ -317,16 +265,16 @@ sum = 0; for (i = 0; i < NR_CPUS; i++) { - if (cpu_online(i)) { + if (test_bit(i, &cpu_callout_map)) { t0 = tsc_values[i]; sum += t0; } } - avg = div64(sum, num_online_cpus()); + avg = div64(sum, num_booting_cpus()); sum = 0; for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) + if (!test_bit(i, &cpu_callout_map)) continue; delta = tsc_values[i] - avg; if (delta < 0) @@ -359,7 +307,7 @@ int i; /* - * num_online_cpus is not necessarily known at the time + * Not every cpu is online at the time * this gets called, so we first wait for the BP to * finish SMP initialization: */ @@ -367,7 +315,7 @@ for (i = 0; i < NR_LOOPS; i++) { atomic_inc(&tsc_count_start); - while (atomic_read(&tsc_count_start) != num_online_cpus()) + while (atomic_read(&tsc_count_start) != num_booting_cpus()) mb(); rdtscll(tsc_values[smp_processor_id()]); @@ -375,7 +323,7 @@ write_tsc(0, 0); atomic_inc(&tsc_count_stop); - while (atomic_read(&tsc_count_stop) != num_online_cpus()) mb(); + while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb(); } } #undef NR_LOOPS @@ -403,7 +351,7 @@ */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); cpuid = smp_processor_id(); - if (test_and_set_bit(cpuid, &cpu_online_map)) { + if (test_bit(cpuid, &cpu_callin_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", phys_id, cpuid); BUG(); @@ -501,15 +449,17 @@ */ cpu_init(); smp_callin(); - while (!atomic_read(&smp_commenced)) + while (!test_bit(smp_processor_id(), &smp_commenced_mask)) rep_nop(); + setup_secondary_APIC_clock(); enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. */ local_flush_tlb(); - + set_bit(smp_processor_id(), &cpu_online_map); + wmb(); return cpu_idle(); } @@ -943,7 +893,6 @@ unmap_cpu_to_boot_apicid(cpu, apicid); clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */ clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */ - clear_bit(cpu, &cpu_online_map); /* was set in smp_callin() */ cpucount--; } @@ -1015,7 +964,7 @@ int cpu_sibling_map[NR_CPUS] __cacheline_aligned; -void __init smp_boot_cpus(void) +static void __init smp_boot_cpus(unsigned int max_cpus) { int apicid, cpu, bit; @@ -1057,6 +1006,7 @@ * We have the boot CPU online for sure. */ set_bit(0, &cpu_online_map); + set_bit(0, &cpu_callout_map); boot_cpu_logical_apicid = logical_smp_processor_id(); map_cpu_to_boot_apicid(0, boot_cpu_apicid); @@ -1072,11 +1022,11 @@ #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = 1; if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." " Using dummy APIC emulation.\n"); - goto smp_done; + return; } /* @@ -1101,8 +1051,8 @@ #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif - cpu_online_map = phys_cpu_present_map = 1; - goto smp_done; + phys_cpu_present_map = 1; + return; } verify_local_APIC(); @@ -1116,8 +1066,8 @@ #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif - cpu_online_map = phys_cpu_present_map = 1; - goto smp_done; + phys_cpu_present_map = 1; + return; } connect_bsp_APIC(); @@ -1189,7 +1139,7 @@ } else { unsigned long bogosum = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) - if (cpu_online_map & (1<mm->context); /* This does lldt */ /* diff -Nru a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S --- a/arch/i386/kernel/trampoline.S Fri Jul 26 19:58:51 2002 +++ b/arch/i386/kernel/trampoline.S Fri Jul 26 19:58:51 2002 @@ -63,9 +63,14 @@ .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L +# +# NOTE: here we actually use CPU#0's GDT - but that is OK, we reload +# the proper GDT shortly after booting up the secondary CPUs. +# + gdt_48: .word 0x0800 # gdt limit = 2048, 256 GDT entries - .long gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) + .long cpu_gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) .globl trampoline_end trampoline_end: diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Fri Jul 26 19:58:50 2002 +++ b/arch/i386/kernel/traps.c Fri Jul 26 19:58:50 2002 @@ -784,11 +784,10 @@ __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); /* - * "idt" is magic - it overlaps the idt_descr - * variable so that updating idt will automatically - * update the idt descriptor.. + * Update the IDT descriptor and reload the IDT so that + * it uses the read-only mapped virtual address. */ - idt = (struct desc_struct *) fix_to_virt(FIX_F00F_IDT); + idt_descr.address = fix_to_virt(FIX_F00F_IDT); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); } #endif @@ -831,37 +830,6 @@ static void __init set_call_gate(void *a, void *addr) { _set_gate(a,12,3,addr); -} - -#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ - *((gate_addr)+1) = ((base) & 0xff000000) | \ - (((base) & 0x00ff0000)>>16) | \ - ((limit) & 0xf0000) | \ - ((dpl)<<13) | \ - (0x00408000) | \ - ((type)<<8); \ - *(gate_addr) = (((base) & 0x0000ffff)<<16) | \ - ((limit) & 0x0ffff); } - -#define _set_tssldt_desc(n,addr,limit,type) \ -__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ - "movw %%ax,2(%2)\n\t" \ - "rorl $16,%%eax\n\t" \ - "movb %%al,4(%2)\n\t" \ - "movb %4,5(%2)\n\t" \ - "movb $0,6(%2)\n\t" \ - "movb %%ah,7(%2)\n\t" \ - "rorl $16,%%eax" \ - : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) - -void set_tss_desc(unsigned int n, void *addr) -{ - _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89); -} - -void set_ldt_desc(unsigned int n, void *addr, unsigned int size) -{ - _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); } #ifdef CONFIG_X86_VISWS_APIC diff -Nru a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile --- a/arch/i386/mm/Makefile Fri Jul 26 19:58:51 2002 +++ b/arch/i386/mm/Makefile Fri Jul 26 19:58:51 2002 @@ -9,7 +9,7 @@ O_TARGET := mm.o -obj-y := init.o fault.o ioremap.o extable.o pageattr.o +obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o export-objs := pageattr.o include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c Fri Jul 26 19:58:50 2002 +++ b/arch/i386/mm/fault.c Fri Jul 26 19:58:50 2002 @@ -24,6 +24,7 @@ #include #include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -129,7 +130,6 @@ } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); -extern unsigned long idt; /* * This routine handles page faults. It determines the address, @@ -293,7 +293,7 @@ if (boot_cpu_data.f00f_bug) { unsigned long nr; - nr = (address - idt) >> 3; + nr = (address - idt_descr.address) >> 3; if (nr == 6) { do_invalid_op(regs, 0); diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Fri Jul 26 19:58:51 2002 +++ b/arch/i386/mm/init.c Fri Jul 26 19:58:51 2002 @@ -38,15 +38,146 @@ #include #include #include +#include mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; /* - * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the - * physical space so we can cache the place of the first one and move - * around without checking the pgd every time. + * Creates a middle page table and puts a pointer to it in the + * given global directory entry. This only returns the gd entry + * in non-PAE compilation mode, since the middle layer is folded. */ +static pmd_t * __init one_md_table_init(pgd_t *pgd) +{ + pmd_t *pmd_table; + +#if CONFIG_X86_PAE + pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pgd(pgd, __pgd(__pa(md_table) | _PAGE_PRESENT)); + if (pmd_table != pmd_offset(pgd, 0)) + BUG(); +#else + pmd_table = pmd_offset(pgd, 0); +#endif + + return pmd_table; +} + +/* + * Create a page table and place a pointer to it in a middle page + * directory entry. + */ +static pte_t * __init one_page_table_init(pmd_t *pmd) +{ + pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(__pa(page_table) | _KERNPG_TABLE)); + if (page_table != pte_offset_kernel(pmd, 0)) + BUG(); + + return page_table; +} + +/* + * This function initializes a certain range of kernel virtual memory + * with new bootmem page tables, everywhere page tables are missing in + * the given range. + */ + +/* + * NOTE: The pagetables are allocated contiguous on the physical space + * so we can cache the place of the first one and move around without + * checking the pgd every time. + */ +static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) +{ + pgd_t *pgd; + pmd_t *pmd; + int pgd_ofs, pmd_ofs; + unsigned long vaddr; + + vaddr = start; + pgd_ofs = __pgd_offset(vaddr); + pmd_ofs = __pmd_offset(vaddr); + pgd = pgd_base + pgd_ofs; + + for ( ; (pgd_ofs < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_ofs++) { + if (pgd_none(*pgd)) + one_md_table_init(pgd); + + pmd = pmd_offset(pgd, vaddr); + for (; (pmd_ofs < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_ofs++) { + if (pmd_none(*pmd)) + one_page_table_init(pmd); + + vaddr += PMD_SIZE; + } + pmd_ofs = 0; + } +} + +/* + * This maps the physical memory to kernel virtual address space, a total + * of max_low_pfn pages, by creating page tables starting from address + * PAGE_OFFSET. + */ +static void __init kernel_physical_mapping_init(pgd_t *pgd_base) +{ + unsigned long pfn; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int pgd_ofs, pmd_ofs, pte_ofs; + + pgd_ofs = __pgd_offset(PAGE_OFFSET); + pgd = pgd_base + pgd_ofs; + pfn = 0; + + for (; pgd_ofs < PTRS_PER_PGD && pfn < max_low_pfn; pgd++, pgd_ofs++) { + pmd = one_md_table_init(pgd); + for (pmd_ofs = 0; pmd_ofs < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_ofs++) { + /* Map with big pages if possible, otherwise create normal page tables. */ + if (cpu_has_pse) { + set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); + pfn += PTRS_PER_PTE; + } else { + pte = one_page_table_init(pmd); + + for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); + } + } + } +} + +static inline int page_kills_ppro(unsigned long pagenr) +{ + if (pagenr >= 0x70000 && pagenr <= 0x7003F) + return 1; + return 0; +} + +static inline int page_is_ram(unsigned long pagenr) +{ + int i; + + for (i = 0; i < e820.nr_map; i++) { + unsigned long addr, end; + + if (e820.map[i].type != E820_RAM) /* not usable memory */ + continue; + /* + * !!!FIXME!!! Some BIOSen report areas as RAM that + * are not. Notably the 640->1Mb area. We need a sanity + * check here. + */ + addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; + end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; + if ((pagenr >= addr) && (pagenr < end)) + return 1; + } + return 0; +} #if CONFIG_HIGHMEM pte_t *kmap_pte; @@ -65,186 +196,88 @@ kmap_prot = PAGE_KERNEL; } -#endif /* CONFIG_HIGHMEM */ -void show_mem(void) -{ - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; - int highmem = 0; - - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - while (i-- > 0) { - total++; - if (PageHighMem(mem_map+i)) - highmem++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (page_count(mem_map+i)) - shared += page_count(mem_map+i) - 1; - } - printk("%d pages of RAM\n", total); - printk("%d pages of HIGHMEM\n",highmem); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); -} - -/* References to section boundaries */ - -extern char _text, _etext, _edata, __bss_start, _end; -extern char __init_begin, __init_end; - -static inline void set_pte_phys (unsigned long vaddr, - unsigned long phys, pgprot_t flags) +void __init permanent_kmaps_init(pgd_t *pgd_base) { pgd_t *pgd; pmd_t *pmd; pte_t *pte; + unsigned long vaddr; + + vaddr = PKMAP_BASE; + page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); pgd = swapper_pg_dir + __pgd_offset(vaddr); - if (pgd_none(*pgd)) { - printk("PAE BUG #00!\n"); - return; - } pmd = pmd_offset(pgd, vaddr); - if (pmd_none(*pmd)) { - printk("PAE BUG #01!\n"); - return; - } pte = pte_offset_kernel(pmd, vaddr); - /* stored as-is, to permit clearing entries */ - set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); - - /* - * It's enough to flush this one mapping. - * (PGE mappings get flushed as well) - */ - __flush_tlb_one(vaddr); + pkmap_page_table = pte; } -void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) +void __init set_highmem_pages_init(int bad_ppro) { - unsigned long address = __fix_to_virt(idx); - - if (idx >= __end_of_fixed_addresses) { - printk("Invalid __set_fixmap\n"); - return; - } - set_pte_phys(address, phys, flags); -} + int pfn; + for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) { + struct page *page = mem_map + pfn; -static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int i, j; - unsigned long vaddr; - - vaddr = start; - i = __pgd_offset(vaddr); - j = __pmd_offset(vaddr); - pgd = pgd_base + i; - - for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { -#if CONFIG_X86_PAE - if (pgd_none(*pgd)) { - pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); - if (pmd != pmd_offset(pgd, 0)) - printk("PAE BUG #02!\n"); + if (!page_is_ram(pfn)) { + SetPageReserved(page); + continue; } - pmd = pmd_offset(pgd, vaddr); -#else - pmd = (pmd_t *)pgd; -#endif - for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { - if (pmd_none(*pmd)) { - pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); - if (pte != pte_offset_kernel(pmd, 0)) - BUG(); - } - vaddr += PMD_SIZE; + if (bad_ppro && page_kills_ppro(pfn)) + { + SetPageReserved(page); + continue; } - j = 0; + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; } + totalram_pages += totalhigh_pages; } +#else +#define kmap_init() do { } while (0) +#define permanent_kmaps_init(pgd_base) do { } while (0) +#define set_highmem_pages_init(bad_ppro) do { } while (0) +#endif /* CONFIG_HIGHMEM */ + unsigned long __PAGE_KERNEL = _PAGE_KERNEL; static void __init pagetable_init (void) { - unsigned long vaddr, pfn; - pgd_t *pgd, *pgd_base; - int i, j, k; - pmd_t *pmd; - pte_t *pte, *pte_base; + unsigned long vaddr; + pgd_t *pgd_base = swapper_pg_dir; - pgd_base = swapper_pg_dir; #if CONFIG_X86_PAE + int i; + /* Init entries of the first-level page table to the zero page */ for (i = 0; i < PTRS_PER_PGD; i++) set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #endif + + /* Enable PSE if available */ if (cpu_has_pse) { set_in_cr4(X86_CR4_PSE); } + + /* Enable PGE if available */ if (cpu_has_pge) { set_in_cr4(X86_CR4_PGE); __PAGE_KERNEL |= _PAGE_GLOBAL; } - i = __pgd_offset(PAGE_OFFSET); - pfn = 0; - pgd = pgd_base + i; - - for (; i < PTRS_PER_PGD && pfn < max_low_pfn; pgd++, i++) { -#if CONFIG_X86_PAE - pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd) | _PAGE_PRESENT)); -#else - pmd = (pmd_t *) pgd; -#endif - for (j = 0; j < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, j++) { - if (cpu_has_pse) { - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; - } else { - pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - - for (k = 0; k < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, k++) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); - - set_pmd(pmd, __pmd(__pa(pte_base) | _KERNPG_TABLE)); - } - } - } + kernel_physical_mapping_init(pgd_base); /* * Fixed mappings, only the page table structure has to be * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - fixrange_init(vaddr, 0, pgd_base); + page_table_range_init(vaddr, 0, pgd_base); -#if CONFIG_HIGHMEM - /* - * Permanent kmaps: - */ - vaddr = PKMAP_BASE; - fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + __pgd_offset(vaddr); - pmd = pmd_offset(pgd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; -#endif + permanent_kmaps_init(pgd_base); #if CONFIG_X86_PAE /* @@ -276,6 +309,27 @@ flush_tlb_all(); } +void __init zone_sizes_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned int max_dma, high, low; + + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = max_low_pfn; + high = highend_pfn; + + if (low < max_dma) + zones_size[ZONE_DMA] = low; + else { + zones_size[ZONE_DMA] = max_dma; + zones_size[ZONE_NORMAL] = low - max_dma; +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = high - low; +#endif + } + free_area_init(zones_size); +} + /* * paging_init() sets up the page tables - note that the first 8MB are * already mapped by head.S. @@ -297,32 +351,10 @@ if (cpu_has_pae) set_in_cr4(X86_CR4_PAE); #endif - __flush_tlb_all(); -#ifdef CONFIG_HIGHMEM kmap_init(); -#endif - { - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; - unsigned int max_dma, high, low; - - max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - low = max_low_pfn; - high = highend_pfn; - - if (low < max_dma) - zones_size[ZONE_DMA] = low; - else { - zones_size[ZONE_DMA] = max_dma; - zones_size[ZONE_NORMAL] = low - max_dma; -#ifdef CONFIG_HIGHMEM - zones_size[ZONE_HIGHMEM] = high - low; -#endif - } - free_area_init(zones_size); - } - return; + zone_sizes_init(); } /* @@ -373,35 +405,6 @@ printk("Ok.\n"); } } - -static inline int page_is_ram (unsigned long pagenr) -{ - int i; - - for (i = 0; i < e820.nr_map; i++) { - unsigned long addr, end; - - if (e820.map[i].type != E820_RAM) /* not usable memory */ - continue; - /* - * !!!FIXME!!! Some BIOSen report areas as RAM that - * are not. Notably the 640->1Mb area. We need a sanity - * check here. - */ - addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; - end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; - if ((pagenr >= addr) && (pagenr < end)) - return 1; - } - return 0; -} - -static inline int page_kills_ppro(unsigned long pagenr) -{ - if(pagenr >= 0x70000 && pagenr <= 0x7003F) - return 1; - return 0; -} void __init mem_init(void) { @@ -436,27 +439,9 @@ */ if (page_is_ram(tmp) && PageReserved(mem_map+tmp)) reservedpages++; -#ifdef CONFIG_HIGHMEM - for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { - struct page *page = mem_map + tmp; - if (!page_is_ram(tmp)) { - SetPageReserved(page); - continue; - } - if (bad_ppro && page_kills_ppro(tmp)) - { - SetPageReserved(page); - continue; - } - ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); - atomic_set(&page->count, 1); - __free_page(page); - totalhigh_pages++; - } - totalram_pages += totalhigh_pages; -#endif + set_highmem_pages_init(bad_ppro); + codesize = (unsigned long) &_etext - (unsigned long) &_text; datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; @@ -487,8 +472,22 @@ #ifndef CONFIG_SMP zap_low_mappings(); #endif +} + +#if CONFIG_X86_PAE +struct kmem_cache_s *pae_pgd_cachep; +void __init pgtable_cache_init(void) +{ + /* + * PAE pgds must be 16-byte aligned: + */ + pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); + if (!pae_pgd_cachep) + panic("init_pae(): Cannot alloc pae_pgd SLAB cache"); } +#endif /* Put this after the callers, so that it cannot be inlined */ static int do_test_wp_bit(unsigned long vaddr) @@ -541,110 +540,3 @@ } } #endif - -#if defined(CONFIG_X86_PAE) -static struct kmem_cache_s *pae_pgd_cachep; - -void __init pgtable_cache_init(void) -{ - /* - * PAE pgds must be 16-byte aligned: - */ - pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0, - SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); - if (!pae_pgd_cachep) - panic("init_pae(): Cannot alloc pae_pgd SLAB cache"); -} - -pgd_t *pgd_alloc(struct mm_struct *mm) -{ - int i; - pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL); - - if (pgd) { - for (i = 0; i < USER_PTRS_PER_PGD; i++) { - unsigned long pmd = __get_free_page(GFP_KERNEL); - if (!pmd) - goto out_oom; - clear_page(pmd); - set_pgd(pgd + i, __pgd(1 + __pa(pmd))); - } - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - } - return pgd; -out_oom: - for (i--; i >= 0; i--) - free_page((unsigned long)__va(pgd_val(pgd[i])-1)); - kmem_cache_free(pae_pgd_cachep, pgd); - return NULL; -} - -void pgd_free(pgd_t *pgd) -{ - int i; - - for (i = 0; i < USER_PTRS_PER_PGD; i++) - free_page((unsigned long)__va(pgd_val(pgd[i])-1)); - kmem_cache_free(pae_pgd_cachep, pgd); -} - -#else - -pgd_t *pgd_alloc(struct mm_struct *mm) -{ - pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); - - if (pgd) { - memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - } - return pgd; -} - -void pgd_free(pgd_t *pgd) -{ - free_page((unsigned long)pgd); -} -#endif /* CONFIG_X86_PAE */ - -pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) -{ - int count = 0; - pte_t *pte; - - do { - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pte) - clear_page(pte); - else { - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); - } - } while (!pte && (count++ < 10)); - return pte; -} - -struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) -{ - int count = 0; - struct page *pte; - - do { -#if CONFIG_HIGHPTE - pte = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0); -#else - pte = alloc_pages(GFP_KERNEL, 0); -#endif - if (pte) - clear_highpage(pte); - else { - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ); - } - } while (!pte && (count++ < 10)); - return pte; -} diff -Nru a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mm/pgtable.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,188 @@ +/* + * linux/arch/i386/mm/pgtable.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void show_mem(void) +{ + int i, total = 0, reserved = 0; + int shared = 0, cached = 0; + int highmem = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageHighMem(mem_map+i)) + highmem++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (page_count(mem_map+i)) + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n", total); + printk("%d pages of HIGHMEM\n",highmem); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); +} + +/* + * Associate a virtual page frame with a given physical page frame + * and protection flags for that frame. + */ +static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + if (pgd_none(*pgd)) { + BUG(); + return; + } + pmd = pmd_offset(pgd, vaddr); + if (pmd_none(*pmd)) { + BUG(); + return; + } + pte = pte_offset_kernel(pmd, vaddr); + /* stored as-is, to permit clearing entries */ + set_pte(pte, pfn_pte(pfn, flags)); + + /* + * It's enough to flush this one mapping. + * (PGE mappings get flushed as well) + */ + __flush_tlb_one(vaddr); +} + +void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) +{ + unsigned long address = __fix_to_virt(idx); + + if (idx >= __end_of_fixed_addresses) { + BUG(); + return; + } + set_pte_pfn(address, phys >> PAGE_SHIFT, flags); +} + +pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +{ + int count = 0; + pte_t *pte; + + do { + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + else { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + } while (!pte && (count++ < 10)); + return pte; +} + +struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + int count = 0; + struct page *pte; + + do { +#if CONFIG_HIGHPTE + pte = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0); +#else + pte = alloc_pages(GFP_KERNEL, 0); +#endif + if (pte) + clear_highpage(pte); + else { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + } while (!pte && (count++ < 10)); + return pte; +} + +#if CONFIG_X86_PAE + +pgd_t *pgd_alloc(struct mm_struct *mm) +{ + int i; + pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL); + + if (pgd) { + for (i = 0; i < USER_PTRS_PER_PGD; i++) { + unsigned long pmd = __get_free_page(GFP_KERNEL); + if (!pmd) + goto out_oom; + clear_page(pmd); + set_pgd(pgd + i, __pgd(1 + __pa(pmd))); + } + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + return pgd; +out_oom: + for (i--; i >= 0; i--) + free_page((unsigned long)__va(pgd_val(pgd[i])-1)); + kmem_cache_free(pae_pgd_cachep, pgd); + return NULL; +} + +void pgd_free(pgd_t *pgd) +{ + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i++) + free_page((unsigned long)__va(pgd_val(pgd[i])-1)); + kmem_cache_free(pae_pgd_cachep, pgd); +} + +#else + +pgd_t *pgd_alloc(struct mm_struct *mm) +{ + pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); + + if (pgd) { + memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + return pgd; +} + +void pgd_free(pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +#endif /* CONFIG_X86_PAE */ + diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in --- a/arch/ia64/config.in Fri Jul 26 19:58:52 2002 +++ b/arch/ia64/config.in Fri Jul 26 19:58:52 2002 @@ -133,9 +133,9 @@ source drivers/message/fusion/Config.in mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -263,3 +263,5 @@ fi endmenu + +source security/Config.in diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c Fri Jul 26 19:58:52 2002 +++ b/arch/ia64/kernel/ptrace.c Fri Jul 26 19:58:52 2002 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -1099,6 +1100,9 @@ if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) + goto out; + ret = security_ops->ptrace(current->parent, current); + if (ret) goto out; current->ptrace |= PT_PTRACED; ret = 0; diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in --- a/arch/m68k/config.in Fri Jul 26 19:58:52 2002 +++ b/arch/m68k/config.in Fri Jul 26 19:58:52 2002 @@ -160,9 +160,9 @@ fi mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL device support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL device support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -172,9 +172,9 @@ endmenu mainmenu_option next_comment -comment 'SCSI support' +comment 'SCSI device support' -tristate 'SCSI support' CONFIG_SCSI +tristate 'SCSI device support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then @@ -547,4 +547,5 @@ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/mips/config.in b/arch/mips/config.in --- a/arch/mips/config.in Fri Jul 26 19:58:52 2002 +++ b/arch/mips/config.in Fri Jul 26 19:58:52 2002 @@ -343,9 +343,9 @@ "$CONFIG_DECSTATION" != "y" ]; then mainmenu_option next_comment - comment 'ATA/IDE/MFM/RLL support' + comment 'ATA/ATAPI/MFM/RLL support' - tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE + tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -503,4 +503,5 @@ fi endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/mips64/config.in b/arch/mips64/config.in --- a/arch/mips64/config.in Fri Jul 26 19:58:50 2002 +++ b/arch/mips64/config.in Fri Jul 26 19:58:50 2002 @@ -138,9 +138,9 @@ source drivers/telephony/Config.in mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -248,4 +248,5 @@ fi endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/parisc/config.in b/arch/parisc/config.in --- a/arch/parisc/config.in Fri Jul 26 19:58:52 2002 +++ b/arch/parisc/config.in Fri Jul 26 19:58:52 2002 @@ -200,4 +200,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/ppc/4xx_io/Makefile b/arch/ppc/4xx_io/Makefile --- a/arch/ppc/4xx_io/Makefile Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/4xx_io/Makefile Fri Jul 26 19:58:51 2002 @@ -6,7 +6,6 @@ #obj-y := -obj-$(CONFIG_STB_KB) += stb_kb.o obj-$(CONFIG_SERIAL_SICC) += serial_sicc.o include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/4xx_io/stb_kb.c b/arch/ppc/4xx_io/stb_kb.c --- a/arch/ppc/4xx_io/stb_kb.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/4xx_io/stb_kb.c Fri Jul 26 19:58:51 2002 @@ -1,289 +0,0 @@ -/* - * arch/ppc/4xx_io/stb_kb.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* the following are borrowed from pc_keyb.c, thanks to those involved! */ -/* - * Translation of escaped scancodes to keycodes. - * This is now user-settable. - * The keycodes 1-88,96-111,119 are fairly standard, and - * should probably not be changed - changing might confuse X. - * X also interprets scancode 0x5d (KEY_Begin). - * - * For 1-88 keycode equals scancode. - */ - -#define E0_KPENTER 96 -#define E0_RCTRL 97 -#define E0_KPSLASH 98 -#define E0_PRSCR 99 -#define E0_RALT 100 -#define E0_BREAK 101 /* (control-pause) */ -#define E0_HOME 102 -#define E0_UP 103 -#define E0_PGUP 104 -#define E0_LEFT 105 -#define E0_RIGHT 106 -#define E0_END 107 -#define E0_DOWN 108 -#define E0_PGDN 109 -#define E0_INS 110 -#define E0_DEL 111 - -#define E1_PAUSE 119 - -/* - * The keycodes below are randomly located in 89-95,112-118,120-127. - * They could be thrown away (and all occurrences below replaced by 0), - * but that would force many users to use the `setkeycodes' utility, where - * they needed not before. It does not matter that there are duplicates, as - * long as no duplication occurs for any single keyboard. - */ -#define SC_LIM 89 - -#define FOCUS_PF1 85 /* actual code! */ -#define FOCUS_PF2 89 -#define FOCUS_PF3 90 -#define FOCUS_PF4 91 -#define FOCUS_PF5 92 -#define FOCUS_PF6 93 -#define FOCUS_PF7 94 -#define FOCUS_PF8 95 -#define FOCUS_PF9 120 -#define FOCUS_PF10 121 -#define FOCUS_PF11 122 -#define FOCUS_PF12 123 - -#define JAP_86 124 -/* tfj@olivia.ping.dk: - * The four keys are located over the numeric keypad, and are - * labelled A1-A4. It's an rc930 keyboard, from - * Regnecentralen/RC International, Now ICL. - * Scancodes: 59, 5a, 5b, 5c. - */ -#define RGN1 124 -#define RGN2 125 -#define RGN3 126 -#define RGN4 127 - -static unsigned char high_keys[128 - SC_LIM] = { - RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ - 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ - 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ - FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ - FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ -}; - -/* BTC */ -#define E0_MACRO 112 -/* LK450 */ -#define E0_F13 113 -#define E0_F14 114 -#define E0_HELP 115 -#define E0_DO 116 -#define E0_F17 117 -#define E0_KPMINPLUS 118 -/* - * My OmniKey generates e0 4c for the "OMNI" key and the - * right alt key does nada. [kkoller@nyx10.cs.du.edu] - */ -#define E0_OK 124 -/* - * New microsoft keyboard is rumoured to have - * e0 5b (left window button), e0 5c (right window button), - * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] - * [or: Windows_L, Windows_R, TaskMan] - */ -#define E0_MSLW 125 -#define E0_MSRW 126 -#define E0_MSTM 127 - -static unsigned char e0_keys[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ - 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ - 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ - E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ - E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ - E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ - E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ - 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ - 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ -}; - -void __init rawirkbd_init_hw(void) { - -} -/* -int rawirkbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - return -EINVAL; -} - -int rawirkbd_getkeycode(unsigned int scancode) -{ - return -EINVAL; -} -*/ - -int rawirkbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - if (scancode < SC_LIM || scancode > 255 || keycode > 127) - return -EINVAL; - if (scancode < 128) - high_keys[scancode - SC_LIM] = keycode; - else - e0_keys[scancode - 128] = keycode; - return 0; -} - -int rawirkbd_getkeycode(unsigned int scancode) -{ - return - (scancode < SC_LIM || scancode > 255) ? -EINVAL : - (scancode < 128) ? high_keys[scancode - SC_LIM] : - e0_keys[scancode - 128]; -} - -int rawirkbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ - static int prev_scancode = 0; - - /* special prefix scancodes.. */ - if (scancode == 0xe0 || scancode == 0xe1) { - prev_scancode = scancode; - return 0; - } - - /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ - if (scancode == 0x00 || scancode == 0xff) { - prev_scancode = 0; - return 0; - } - - scancode &= 0x7f; - - if (prev_scancode) { - /* - * usually it will be 0xe0, but a Pause key generates - * e1 1d 45 e1 9d c5 when pressed, and nothing when released - */ - if (prev_scancode != 0xe0) { - if (prev_scancode == 0xe1 && scancode == 0x1d) { - prev_scancode = 0x100; - return 0; - } else if (prev_scancode == 0x100 && scancode == 0x45) { - *keycode = E1_PAUSE; - prev_scancode = 0; - } else { -#ifdef KBD_REPORT_UNKN - if (!raw_mode) - printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); -#endif - prev_scancode = 0; - return 0; - } - } else { - prev_scancode = 0; - /* - * The keyboard maintains its own internal caps lock and - * num lock statuses. In caps lock mode E0 AA precedes make - * code and E0 2A follows break code. In num lock mode, - * E0 2A precedes make code and E0 AA follows break code. - * We do our own book-keeping, so we will just ignore these. - */ - /* - * For my keyboard there is no caps lock mode, but there are - * both Shift-L and Shift-R modes. The former mode generates - * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. - * So, we should also ignore the latter. - aeb@cwi.nl - */ - if (scancode == 0x2a || scancode == 0x36) - return 0; - - if (e0_keys[scancode]) - *keycode = e0_keys[scancode]; - else { -#ifdef KBD_REPORT_UNKN - if (!raw_mode) - printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", - scancode); -#endif - return 0; - } - } - } else if (scancode >= SC_LIM) { - /* This happens with the FOCUS 9000 keyboard - Its keys PF1..PF12 are reported to generate - 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f - Moreover, unless repeated, they do not generate - key-down events, so we have to zero up_flag below */ - /* Also, Japanese 86/106 keyboards are reported to - generate 0x73 and 0x7d for \ - and \ | respectively. */ - /* Also, some Brazilian keyboard is reported to produce - 0x73 and 0x7e for \ ? and KP-dot, respectively. */ - - *keycode = high_keys[scancode - SC_LIM]; - - if (!*keycode) { - if (!raw_mode) { -#ifdef KBD_REPORT_UNKN - printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" - " - ignored\n", scancode); -#endif - } - return 0; - } - } else - *keycode = scancode; - return 1; -} - -char rawirkbd_unexpected_up(unsigned char keycode) -{ - /* unexpected, but this can happen: maybe this was a key release for a - FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ - if (keycode >= SC_LIM || keycode == 85) - return 0; - else - return 0200; -} - -#include - -void redwood_irkb_init(void) -{ - extern struct machdep_calls ppc_md; - - ppc_md.kbd_translate = rawirkbd_translate; - ppc_md.kbd_unexpected_up = rawirkbd_unexpected_up; -} - diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c --- a/arch/ppc/8xx_io/uart.c Fri Jul 26 19:58:52 2002 +++ b/arch/ppc/8xx_io/uart.c Fri Jul 26 19:58:52 2002 @@ -3103,19 +3103,3 @@ return 0; } - -#ifdef CONFIG_INPUT_KEYBDEV - -void handle_scancode(unsigned char scancode, int down) -{ - printk("handle_scancode(scancode=0x%x, down=%d)\n", scancode, down); -} - -static void kbd_bh(unsigned long dummy) -{ -} - -DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -void (*kbd_ledfunc)(unsigned int led); - -#endif diff -Nru a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c --- a/arch/ppc/amiga/config.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/amiga/config.c Fri Jul 26 19:58:51 2002 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -76,9 +75,6 @@ extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); -/* amiga specific keyboard functions */ -extern int amiga_keyb_init(void); -extern int amiga_kbdrate (struct kbd_repeat *); /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -119,18 +115,6 @@ index: -1, }; -#ifdef CONFIG_MAGIC_SYSRQ -char amiga_sysrq_xlate[128] = - "\0001234567890-=\\\000\000" /* 0x00 - 0x0f */ - "qwertyuiop[]\000123" /* 0x10 - 0x1f */ - "asdfghjkl;'\000\000456" /* 0x20 - 0x2f */ - "\000zxcvbnm,./\000+789" /* 0x30 - 0x3f */ - " \177\t\r\r\000\177\000\000\000-\000\000\000\000\000" /* 0x40 - 0x4f */ - "\000\201\202\203\204\205\206\207\210\211()/*+\000" /* 0x50 - 0x5f */ - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */ - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ -#endif - extern void (*kd_mksound)(unsigned int, unsigned int); @@ -407,8 +391,6 @@ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; - mach_keyb_init = amiga_keyb_init; - mach_kbdrate = amiga_kbdrate; mach_init_IRQ = amiga_init_IRQ; #ifndef CONFIG_APUS mach_default_handler = &amiga_default_handler; diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in --- a/arch/ppc/config.in Fri Jul 26 19:58:50 2002 +++ b/arch/ppc/config.in Fri Jul 26 19:58:50 2002 @@ -575,7 +575,6 @@ mainmenu_option next_comment comment 'IBM 40x options' if [ "$CONFIG_STB03xxx" = "y" ]; then - bool 'STB IR Keyboard' CONFIG_STB_KB bool 'SICC Serial port' CONFIG_SERIAL_SICC if [ "$CONFIG_SERIAL_SICC" = "y" -a "$CONFIG_UART0_TTYS1" = "y" ]; then define_bool CONFIG_UART1_DFLT_CONSOLE y @@ -624,3 +623,6 @@ bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG fi endmenu + +source security/Config.in + diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c --- a/arch/ppc/kernel/open_pic.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/kernel/open_pic.c Fri Jul 26 19:58:51 2002 @@ -602,7 +602,7 @@ * -- Cort */ -void __init do_openpic_setup_cpu(void) +void __devinit do_openpic_setup_cpu(void) { int i; u32 msk = 1 << smp_hw_index[smp_processor_id()]; diff -Nru a/arch/ppc/kernel/ppc4xx_setup.c b/arch/ppc/kernel/ppc4xx_setup.c --- a/arch/ppc/kernel/ppc4xx_setup.c Fri Jul 26 19:58:50 2002 +++ b/arch/ppc/kernel/ppc4xx_setup.c Fri Jul 26 19:58:50 2002 @@ -345,12 +345,6 @@ ppc_md.progress = ppc4xx_progress; #endif -#if defined(CONFIG_VT) && defined(CONFIG_PC_KEYBOARD) -#if defined(CONFIG_REDWOOD_4) && defined(CONFIG_STB_KB) - redwood_irkb_init(); -#endif -#endif - /* ** m8xx_setup.c, prep_setup.c use ** defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c --- a/arch/ppc/kernel/smp.c Fri Jul 26 19:58:52 2002 +++ b/arch/ppc/kernel/smp.c Fri Jul 26 19:58:52 2002 @@ -48,15 +48,17 @@ atomic_t ipi_recv; atomic_t ipi_sent; spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; -unsigned long cache_decay_ticks; -static int max_cpus __initdata = NR_CPUS; -unsigned long cpu_online_map; +unsigned int prof_multiplier[NR_CPUS] = { [1 ... NR_CPUS-1] = 1 }; +unsigned int prof_counter[NR_CPUS] = { [1 ... NR_CPUS-1] = 1 }; +unsigned long cache_decay_ticks = HZ/100; +unsigned long cpu_online_map = 1UL; +unsigned long cpu_possible_map = 1UL; int smp_hw_index[NR_CPUS]; -static struct smp_ops_t *smp_ops; struct thread_info *secondary_ti; +/* SMP operations for this machine */ +static struct smp_ops_t *smp_ops; + /* all cpu mappings are 1-1 -- Cort */ volatile unsigned long cpu_callin_map[NR_CPUS]; @@ -70,10 +72,6 @@ static int __smp_call_function(void (*func) (void *info), void *info, int wait, int target); -#ifdef CONFIG_PPC_ISERIES -extern void smp_iSeries_space_timers( unsigned nr ); -#endif - /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. * * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up @@ -291,6 +289,7 @@ atomic_inc(&call_data->finished); } +#if 0 /* Old boot code. */ void __init smp_boot_cpus(void) { int i, cpu_nr; @@ -556,3 +555,156 @@ } __setup("maxcpus=", maxcpus); +#else /* New boot code */ +/* FIXME: Do this properly for all archs --RR */ +static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED; +static unsigned int timebase_upper = 0, timebase_lower = 0; + +void __devinit +smp_generic_give_timebase(void) +{ + spin_lock(&timebase_lock); + do { + timebase_upper = get_tbu(); + timebase_lower = get_tbl(); + } while (timebase_upper != get_tbu()); + spin_unlock(&timebase_lock); + + while (timebase_upper || timebase_lower) + rmb(); +} + +void __devinit +smp_generic_take_timebase(void) +{ + int done = 0; + + while (!done) { + spin_lock(&timebase_lock); + if (timebase_upper || timebase_lower) { + set_tb(timebase_upper, timebase_lower); + timebase_upper = 0; + timebase_lower = 0; + done = 1; + } + spin_unlock(&timebase_lock); + } +} + +static void __devinit smp_store_cpu_info(int id) +{ + struct cpuinfo_PPC *c = &cpu_data[id]; + + /* assume bogomips are same for everything */ + c->loops_per_jiffy = loops_per_jiffy; + c->pvr = mfspr(PVR); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + int num_cpus; + + /* Fixup boot cpu */ + smp_store_cpu_info(smp_processor_id()); + cpu_callin_map[smp_processor_id()] = 1; + + smp_ops = ppc_md.smp_ops; + if (smp_ops == NULL) { + printk("SMP not supported on this machine.\n"); + return; + } + + /* Probe platform for CPUs: always linear. */ + num_cpus = smp_ops->probe(); + cpu_possible_map = (1 << num_cpus)-1; + + if (smp_ops->space_timers) + smp_ops->space_timers(num_cpus); +} + +int __init setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + +/* Processor coming up starts here */ +int __devinit start_secondary(void *unused) +{ + int cpu; + + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + + cpu = smp_processor_id(); + smp_store_cpu_info(cpu); + set_dec(tb_ticks_per_jiffy); + cpu_callin_map[cpu] = 1; + + printk("CPU %i done callin...\n", cpu); + smp_ops->setup_cpu(cpu); + printk("CPU %i done setup...\n", cpu); + smp_ops->take_timebase(); + printk("CPU %i done timebase take...\n", cpu); + + return cpu_idle(NULL); +} + +int __cpu_up(unsigned int cpu) +{ + struct pt_regs regs; + struct task_struct *p; + char buf[32]; + int c; + + /* create a process for the processor */ + /* only regs.msr is actually used, and 0 is OK for it */ + memset(®s, 0, sizeof(struct pt_regs)); + p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0); + if (IS_ERR(p)) + panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); + + init_idle(p, cpu); + unhash_process(p); + + secondary_ti = p->thread_info; + p->thread_info->cpu = cpu; + + /* + * There was a cache flush loop here to flush the cache + * to memory for the first 8MB of RAM. The cache flush + * has been pushed into the kick_cpu function for those + * platforms that need it. + */ + + /* wake up cpu */ + smp_ops->kick_cpu(cpu); + + /* + * wait to see if the cpu made a callin (is actually up). + * use this value that I found through experimentation. + * -- Cort + */ + for (c = 1000; c && !cpu_callin_map[cpu]; c--) + udelay(100); + + if (!cpu_callin_map[cpu]) { + sprintf(buf, "didn't find cpu %u", cpu); + if (ppc_md.progress) ppc_md.progress(buf, 0x360+cpu); + printk("Processor %u is stuck.\n", cpu); + return -ENOENT; + } + + sprintf(buf, "found cpu %u", cpu); + if (ppc_md.progress) ppc_md.progress(buf, 0x350+cpu); + printk("Processor %d found.\n", cpu); + + smp_ops->give_timebase(); + set_bit(cpu, &cpu_online_map); + return 0; +} + +void smp_cpus_done(unsigned int max_cpus) +{ + smp_ops->setup_cpu(0); +} +#endif diff -Nru a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c --- a/arch/ppc/platforms/apus_setup.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/apus_setup.c Fri Jul 26 19:58:51 2002 @@ -34,7 +34,6 @@ #include #include #include -#include #include unsigned long m68k_machtype; @@ -42,16 +41,9 @@ extern void amiga_init_IRQ(void); -extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); -extern char amiga_sysrq_xlate[128]; - extern void apus_setup_pci_ptrs(void); void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; -/* machine dependent keyboard functions */ -int (*mach_keyb_init) (void) __initdata = NULL; -int (*mach_kbdrate) (struct kbd_repeat *) = NULL; -void (*mach_kbd_leds) (unsigned int) = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; @@ -562,32 +554,6 @@ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu); } -/****************************************************** keyboard */ -static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - return -EOPNOTSUPP; -} - -static int apus_kbd_getkeycode(unsigned int scancode) -{ - return scancode > 127 ? -EINVAL : scancode; -} - -static char apus_kbd_unexpected_up(unsigned char keycode) -{ - return 0200; -} - -static void apus_kbd_init_hw(void) -{ -#ifdef CONFIG_APUS - extern int amiga_keyb_init(void); - - amiga_keyb_init(); -#endif -} - - /****************************************************** debugging */ /* some serial hardware definitions */ @@ -851,9 +817,4 @@ ppc_md.find_end_of_memory = apus_find_end_of_memory; ppc_md.setup_io_mappings = apus_map_io; - - /* These should not be used for the APUS yet, since it uses - the M68K keyboard now. */ - ppc_md.kbd_translate = amiga_kbd_translate; - ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up; } diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c --- a/arch/ppc/platforms/chrp_setup.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/chrp_setup.c Fri Jul 26 19:58:51 2002 @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c --- a/arch/ppc/platforms/chrp_smp.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/chrp_smp.c Fri Jul 26 19:58:51 2002 @@ -50,59 +50,61 @@ return smp_chrp_cpu_nr; } -static void __init +static void __devinit smp_chrp_kick_cpu(int nr) { *(unsigned long *)KERNELBASE = nr; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); } -static void __init +static void __devinit smp_chrp_setup_cpu(int cpu_nr) { - static atomic_t ready = ATOMIC_INIT(1); - static volatile int frozen = 0; - - /* FIXME: Hotplug cpu breaks all this --RR */ - if (cpu_nr == 0) { - /* wait for all the others */ - while (atomic_read(&ready) < num_online_cpus()) - barrier(); - atomic_set(&ready, 1); - /* freeze the timebase */ - call_rtas("freeze-time-base", 0, 1, NULL); - mb(); - frozen = 1; - /* XXX assumes this is not a 601 */ - set_tb(0, 0); - last_jiffy_stamp(0) = 0; - while (atomic_read(&ready) < num_online_cpus()) - barrier(); - /* thaw the timebase again */ - call_rtas("thaw-time-base", 0, 1, NULL); - mb(); - frozen = 0; - smp_tb_synchronized = 1; - } else { - atomic_inc(&ready); - while (!frozen) - barrier(); - set_tb(0, 0); - last_jiffy_stamp(0) = 0; - mb(); - atomic_inc(&ready); - while (frozen) - barrier(); - } - if (OpenPIC_Addr) do_openpic_setup_cpu(); } +static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED; +static unsigned int timebase_upper = 0, timebase_lower = 0; + +void __devinit +smp_chrp_give_timebase(void) +{ + spin_lock(&timebase_lock); + call_rtas("freeze-time-base", 0, 1, NULL); + timebase_upper = get_tbu(); + timebase_lower = get_tbl(); + spin_unlock(&timebase_lock); + + while (timebase_upper || timebase_lower) + rmb(); + call_rtas("thaw-time-base", 0, 1, NULL); +} + +void __devinit +smp_chrp_take_timebase(void) +{ + int done = 0; + + while (!done) { + spin_lock(&timebase_lock); + if (timebase_upper || timebase_lower) { + set_tb(timebase_upper, timebase_lower); + timebase_upper = 0; + timebase_lower = 0; + done = 1; + } + spin_unlock(&timebase_lock); + } + printk("CPU %i taken timebase\n", smp_processor_id()); +} + /* CHRP with openpic */ struct smp_ops_t chrp_smp_ops __chrpdata = { - smp_openpic_message_pass, - smp_chrp_probe, - smp_chrp_kick_cpu, - smp_chrp_setup_cpu, + .message_pass = smp_openpic_message_pass, + .probe = smp_chrp_probe, + .kick_cpu = smp_chrp_kick_cpu, + .setup_cpu = smp_chrp_setup_cpu, + .give_timebase = smp_chrp_give_timebase, + .take_timebase = smp_chrp_take_timebase, }; diff -Nru a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c --- a/arch/ppc/platforms/gemini_setup.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/gemini_setup.c Fri Jul 26 19:58:51 2002 @@ -528,6 +528,8 @@ smp_gemini_probe, smp_gemini_kick_cpu, smp_gemini_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; #endif /* CONFIG_SMP */ diff -Nru a/arch/ppc/platforms/iSeries_smp.c b/arch/ppc/platforms/iSeries_smp.c --- a/arch/ppc/platforms/iSeries_smp.c Fri Jul 26 19:58:50 2002 +++ b/arch/ppc/platforms/iSeries_smp.c Fri Jul 26 19:58:50 2002 @@ -117,7 +117,7 @@ set_dec( xPaca[nr].default_decr ); } -void smp_iSeries_space_timers( unsigned nr ) +static void smp_iSeries_space_timers(unsigned nr) { unsigned offset,i; @@ -131,6 +131,9 @@ smp_iSeries_message_pass, smp_iSeries_probe, smp_iSeries_kick_cpu, - smp_iSeries_setup_cpu + smp_iSeries_setup_cpu, + smp_iSeries_space_timers, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c --- a/arch/ppc/platforms/pmac_smp.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/pmac_smp.c Fri Jul 26 19:58:51 2002 @@ -612,6 +612,8 @@ smp_psurge_probe, smp_psurge_kick_cpu, smp_psurge_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; /* Core99 Macs (dual G4s) */ @@ -620,4 +622,6 @@ smp_core99_probe, smp_core99_kick_cpu, smp_core99_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; diff -Nru a/arch/ppc/platforms/pplus_setup.c b/arch/ppc/platforms/pplus_setup.c --- a/arch/ppc/platforms/pplus_setup.c Fri Jul 26 19:58:52 2002 +++ b/arch/ppc/platforms/pplus_setup.c Fri Jul 26 19:58:52 2002 @@ -63,7 +63,6 @@ #include #include #include -#include #include #include @@ -310,6 +309,8 @@ smp_pplus_probe, smp_pplus_kick_cpu, smp_pplus_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; #endif /* CONFIG_SMP */ diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c --- a/arch/ppc/platforms/prep_setup.c Fri Jul 26 19:58:52 2002 +++ b/arch/ppc/platforms/prep_setup.c Fri Jul 26 19:58:52 2002 @@ -55,7 +55,6 @@ #include #include #include -#include #include #include #include @@ -757,6 +756,8 @@ smp_prep_probe, smp_prep_kick_cpu, smp_prep_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; #endif /* CONFIG_SMP */ diff -Nru a/arch/ppc/platforms/redwood.c b/arch/ppc/platforms/redwood.c --- a/arch/ppc/platforms/redwood.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/redwood.c Fri Jul 26 19:58:51 2002 @@ -45,22 +45,3 @@ board_init(void) { } - -/* hack; blame me dan. -brad */ -#ifdef CONFIG_INPUT_KEYBDEV - -void -handle_scancode(unsigned char scancode, int down) -{ - printk("handle_scancode(scancode=0x%x, down=%d)\n", scancode, down); -} - -static void -kbd_bh(unsigned long dummy) -{ -} - -DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -void (*kbd_ledfunc) (unsigned int led); - -#endif diff -Nru a/arch/ppc/platforms/sandpoint_setup.c b/arch/ppc/platforms/sandpoint_setup.c --- a/arch/ppc/platforms/sandpoint_setup.c Fri Jul 26 19:58:52 2002 +++ b/arch/ppc/platforms/sandpoint_setup.c Fri Jul 26 19:58:52 2002 @@ -83,7 +83,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h --- a/arch/ppc/platforms/spruce.h Fri Jul 26 19:58:50 2002 +++ b/arch/ppc/platforms/spruce.h Fri Jul 26 19:58:50 2002 @@ -58,16 +58,5 @@ #define SPRUCE_NVRAM_BASE_ADDR 0xff800000 #define SPRUCE_RTC_BASE_ADDR SPRUCE_NVRAM_BASE_ADDR -#define KEYBOARD_IRQ 22 -#define AUX_IRQ 21 - -unsigned char spruce_read_keyb_data(void); -unsigned char spruce_read_keyb_status(void); - -#define kbd_read_input spruce_read_keyb_data -#define kbd_read_status spruce_read_keyb_status -#define kbd_write_output(val) *((unsigned char *)0xff810000) = (char)val -#define kbd_write_command(val) *((unsigned char *)0xff810001) = (char)val - #endif /* __ASM_SPRUCE_H__ */ #endif /* __KERNEL__ */ diff -Nru a/arch/ppc/platforms/spruce_setup.c b/arch/ppc/platforms/spruce_setup.c --- a/arch/ppc/platforms/spruce_setup.c Fri Jul 26 19:58:50 2002 +++ b/arch/ppc/platforms/spruce_setup.c Fri Jul 26 19:58:50 2002 @@ -46,7 +46,6 @@ #include #include -#include #include #include #include @@ -199,49 +198,6 @@ { io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE, 0x08000000, _PAGE_IO); -} - -unsigned char spruce_read_keyb_status(void) -{ - unsigned long kbd_status; - - __raw_writel(0x00000088, 0xff500008); - eieio(); - - __raw_writel(0x03000000, 0xff50000c); - eieio(); - - asm volatile(" lis 7,0xff88 \n - ori 7,7,0x8 \n - lswi 6,7,0x8 \n - mr %0,6 \n" - : "=r" (kbd_status) :: "6", "7"); - - __raw_writel(0x00000000, 0xff50000c); - eieio(); - - return (unsigned char)(kbd_status >> 24); -} - -unsigned char spruce_read_keyb_data(void) -{ - unsigned long kbd_data; - - __raw_writel(0x00000088, 0xff500008); - eieio(); - - __raw_writel(0x03000000, 0xff50000c); - eieio(); - - asm volatile(" lis 7,0xff88 \n - lswi 6,7,0x8 \n - mr %0,6 \n" - : "=r" (kbd_data) :: "6", "7"); - - __raw_writel(0x00000000, 0xff50000c); - eieio(); - - return (unsigned char)(kbd_data >> 24); } void __init diff -Nru a/arch/ppc/platforms/walnut.c b/arch/ppc/platforms/walnut.c --- a/arch/ppc/platforms/walnut.c Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/walnut.c Fri Jul 26 19:58:51 2002 @@ -45,6 +45,8 @@ #include #endif +#include "walnut.h" + #undef DEBUG #ifdef DEBUG @@ -82,9 +84,6 @@ void __init board_setup_arch(void) { -#define WALNUT_PS2_BASE 0xF0100000 -#define WALNUT_FPGA_BASE 0xF0300000 - void *fpga_brdc; unsigned char fpga_brdc_data; void *fpga_enable; diff -Nru a/arch/ppc/platforms/walnut.h b/arch/ppc/platforms/walnut.h --- a/arch/ppc/platforms/walnut.h Fri Jul 26 19:58:51 2002 +++ b/arch/ppc/platforms/walnut.h Fri Jul 26 19:58:51 2002 @@ -73,14 +73,6 @@ #define WALNUT_PS2_BASE 0xF0100000 #define WALNUT_FPGA_BASE 0xF0300000 - -extern void *kb_cs; -extern void *kb_data; -#define kbd_read_input() readb(kb_data) -#define kbd_read_status() readb(kb_cs) -#define kbd_write_output(val) writeb(val, kb_data) -#define kbd_write_command(val) writeb(val, kb_cs) - #define PPC4xx_MACHINE_NAME "IBM Walnut" #endif /* !__ASSEMBLY__ */ diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in --- a/arch/ppc64/config.in Fri Jul 26 19:58:50 2002 +++ b/arch/ppc64/config.in Fri Jul 26 19:58:50 2002 @@ -92,9 +92,9 @@ fi mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -226,4 +226,5 @@ fi endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/s390/config.in b/arch/s390/config.in --- a/arch/s390/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/s390/config.in Fri Jul 26 19:58:51 2002 @@ -75,4 +75,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/s390x/config.in b/arch/s390x/config.in --- a/arch/s390x/config.in Fri Jul 26 19:58:50 2002 +++ b/arch/s390x/config.in Fri Jul 26 19:58:50 2002 @@ -78,4 +78,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/sh/config.in b/arch/sh/config.in --- a/arch/sh/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/sh/config.in Fri Jul 26 19:58:51 2002 @@ -211,9 +211,9 @@ fi mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -369,4 +369,5 @@ fi endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in --- a/arch/sparc/config.in Fri Jul 26 19:58:50 2002 +++ b/arch/sparc/config.in Fri Jul 26 19:58:50 2002 @@ -104,9 +104,9 @@ if [ "$CONFIG_PCI" = "y" ]; then mainmenu_option next_comment - comment 'ATA/IDE/MFM/RLL support' + comment 'ATA/ATAPI/MFM/RLL support' - tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE + tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -242,4 +242,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in --- a/arch/sparc64/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/sparc64/config.in Fri Jul 26 19:58:51 2002 @@ -105,9 +105,9 @@ fi mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL device support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL device support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -293,4 +293,5 @@ endmenu +source security/Config.in source lib/Config.in diff -Nru a/arch/x86_64/config.in b/arch/x86_64/config.in --- a/arch/x86_64/config.in Fri Jul 26 19:58:51 2002 +++ b/arch/x86_64/config.in Fri Jul 26 19:58:51 2002 @@ -126,9 +126,9 @@ source drivers/telephony/Config.in mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' +comment 'ATA/ATAPI/MFM/RLL support' -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in @@ -229,4 +229,5 @@ fi endmenu +source security/Config.in source lib/Config.in diff -Nru a/drivers/acpi/ac.c b/drivers/acpi/ac.c --- a/drivers/acpi/ac.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/ac.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 26 $) + * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 27 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -47,13 +47,13 @@ int acpi_ac_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_ac_driver = { - name: ACPI_AC_DRIVER_NAME, - class: ACPI_AC_CLASS, - ids: ACPI_AC_HID, - ops: { - add: acpi_ac_add, - remove: acpi_ac_remove, - }, + .name = ACPI_AC_DRIVER_NAME, + .class = ACPI_AC_CLASS, + .ids = ACPI_AC_HID, + .ops = { + .add = acpi_ac_add, + .remove = acpi_ac_remove, + }, }; struct acpi_ac { diff -Nru a/drivers/acpi/battery.c b/drivers/acpi/battery.c --- a/drivers/acpi/battery.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/battery.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_battery.c - ACPI Battery Driver ($Revision: 36 $) + * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -52,13 +52,13 @@ static int acpi_battery_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_battery_driver = { - name: ACPI_BATTERY_DRIVER_NAME, - class: ACPI_BATTERY_CLASS, - ids: ACPI_BATTERY_HID, - ops: { - add: acpi_battery_add, - remove: acpi_battery_remove, - }, + .name = ACPI_BATTERY_DRIVER_NAME, + .class = ACPI_BATTERY_CLASS, + .ids = ACPI_BATTERY_HID, + .ops = { + .add = acpi_battery_add, + .remove = acpi_battery_remove, + }, }; struct acpi_battery_status { diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c --- a/drivers/acpi/bus.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/bus.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_bus.c - ACPI Bus Driver ($Revision: 79 $) + * acpi_bus.c - ACPI Bus Driver ($Revision: 80 $) * * Copyright (C) 2001, 2002 Paul Diefenbaugh * @@ -97,10 +97,10 @@ static int acpi_device_resume(struct device *dev, u32 stage); static struct device_driver acpi_bus_driver = { - probe: acpi_device_probe, - remove: acpi_device_remove, - suspend: acpi_device_suspend, - resume: acpi_device_resume, + .probe = acpi_device_probe, + .remove = acpi_device_remove, + .suspend = acpi_device_suspend, + .resume = acpi_device_resume, }; diff -Nru a/drivers/acpi/button.c b/drivers/acpi/button.c --- a/drivers/acpi/button.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/button.c Fri Jul 26 19:58:50 2002 @@ -1,5 +1,5 @@ /* - * acpi_button.c - ACPI Button Driver ($Revision: 29 $) + * acpi_button.c - ACPI Button Driver ($Revision: 30 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -47,13 +47,13 @@ int acpi_button_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_button_driver = { - name: ACPI_BUTTON_DRIVER_NAME, - class: ACPI_BUTTON_CLASS, - ids: "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E", - ops: { - add: acpi_button_add, - remove: acpi_button_remove, - }, + .name = ACPI_BUTTON_DRIVER_NAME, + .class = ACPI_BUTTON_CLASS, + .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E", + .ops = { + .add = acpi_button_add, + .remove = acpi_button_remove, + }, }; struct acpi_button { diff -Nru a/drivers/acpi/debugger/dbcmds.c b/drivers/acpi/debugger/dbcmds.c --- a/drivers/acpi/debugger/dbcmds.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/debugger/dbcmds.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: dbcmds - debug commands and output routines - * $Revision: 84 $ + * $Revision: 85 $ * ******************************************************************************/ @@ -31,6 +31,7 @@ #include "acevents.h" #include "acdebug.h" #include "acresrc.h" +#include "acdisasm.h" #ifdef ENABLE_DEBUGGER @@ -342,7 +343,7 @@ num_statements = ACPI_STRTOUL (statements, NULL, 0); } - acpi_db_display_op (NULL, op, num_statements); + acpi_dm_disassemble (NULL, op, num_statements); } diff -Nru a/drivers/acpi/debugger/dbfileio.c b/drivers/acpi/debugger/dbfileio.c --- a/drivers/acpi/debugger/dbfileio.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/debugger/dbfileio.c Fri Jul 26 19:58:50 2002 @@ -2,7 +2,7 @@ * * Module Name: dbfileio - Debugger file I/O commands. These can't usually * be used when running the debugger in Ring 0 (Kernel mode) - * $Revision: 64 $ + * $Revision: 67 $ * ******************************************************************************/ @@ -30,7 +30,7 @@ #include "acnamesp.h" #include "actables.h" -#ifdef ENABLE_DEBUGGER +#if (defined ENABLE_DEBUGGER || defined ACPI_DISASSEMBLER) #define _COMPONENT ACPI_DEBUGGER ACPI_MODULE_NAME ("dbfileio") @@ -86,6 +86,7 @@ } +#ifdef ENABLE_DEBUGGER /******************************************************************************* * * FUNCTION: Acpi_db_close_debug_file @@ -148,6 +149,7 @@ #endif } +#endif #ifdef ACPI_APPLICATION @@ -190,7 +192,7 @@ status = acpi_tb_validate_table_header (&table_header); if ((ACPI_FAILURE (status)) || - (table_header.length > 524288)) /* 1/2 Mbyte should be enough */ { + (table_header.length > 0x800000)) /* 8 Mbyte should be enough */ { acpi_os_printf ("Table header is invalid!\n"); return (AE_ERROR); } @@ -296,7 +298,7 @@ } -#ifndef PARSER_ONLY +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node); if (ACPI_FAILURE (status)) { /* Uninstall table and free the buffer */ @@ -330,7 +332,7 @@ /* Get the entire file */ - acpi_os_printf ("Loading Acpi table from file %s\n", filename); + fprintf (stderr, "Loading Acpi table from file %s\n", filename); status = acpi_db_load_table (fp, &acpi_gbl_db_table_ptr, &table_length); fclose(fp); @@ -383,8 +385,8 @@ return (status); } - acpi_os_printf ("%4.4s at %p successfully installed and loaded\n", - acpi_gbl_db_table_ptr->signature, acpi_gbl_db_table_ptr); + fprintf (stderr, "Acpi table [%4.4s] successfully installed and loaded\n", + acpi_gbl_db_table_ptr->signature); acpi_gbl_acpi_hardware_present = FALSE; diff -Nru a/drivers/acpi/debugger/dbxface.c b/drivers/acpi/debugger/dbxface.c --- a/drivers/acpi/debugger/dbxface.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/debugger/dbxface.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: dbxface - AML Debugger external interfaces - * $Revision: 59 $ + * $Revision: 61 $ * ******************************************************************************/ @@ -27,6 +27,7 @@ #include "acpi.h" #include "amlcode.h" #include "acdebug.h" +#include "acdisasm.h" #ifdef ENABLE_DEBUGGER @@ -164,7 +165,7 @@ /* Now we can display it */ - acpi_db_display_op (walk_state, display_op, ACPI_UINT32_MAX); + acpi_dm_disassemble (walk_state, display_op, ACPI_UINT32_MAX); if ((op->common.aml_opcode == AML_IF_OP) || (op->common.aml_opcode == AML_WHILE_OP)) { @@ -351,7 +352,6 @@ } if (!acpi_gbl_db_opt_verbose) { - acpi_gbl_db_disasm_indent = " "; acpi_gbl_db_opt_disasm = TRUE; acpi_gbl_db_opt_stats = FALSE; } diff -Nru a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c --- a/drivers/acpi/dispatcher/dsobject.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/dispatcher/dsobject.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dsobject - Dispatcher object management routines - * $Revision: 104 $ + * $Revision: 105 $ * *****************************************************************************/ @@ -35,6 +35,7 @@ ACPI_MODULE_NAME ("dsobject") +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * * FUNCTION: Acpi_ds_init_one_object @@ -218,199 +219,6 @@ /***************************************************************************** * - * FUNCTION: Acpi_ds_init_object_from_op - * - * PARAMETERS: Walk_state - Current walk state - * Op - Parser op used to init the internal object - * Opcode - AML opcode associated with the object - * Ret_obj_desc - Namespace object to be initialized - * - * RETURN: Status - * - * DESCRIPTION: Initialize a namespace object from a parser Op and its - * associated arguments. The namespace object is a more compact - * representation of the Op and its arguments. - * - ****************************************************************************/ - -acpi_status -acpi_ds_init_object_from_op ( - acpi_walk_state *walk_state, - acpi_parse_object *op, - u16 opcode, - acpi_operand_object **ret_obj_desc) -{ - const acpi_opcode_info *op_info; - acpi_operand_object *obj_desc; - acpi_status status = AE_OK; - - - ACPI_FUNCTION_TRACE ("Ds_init_object_from_op"); - - - obj_desc = *ret_obj_desc; - op_info = acpi_ps_get_opcode_info (opcode); - if (op_info->class == AML_CLASS_UNKNOWN) { - /* Unknown opcode */ - - return_ACPI_STATUS (AE_TYPE); - } - - /* Perform per-object initialization */ - - switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { - case ACPI_TYPE_BUFFER: - - /* - * Defer evaluation of Buffer Term_arg operand - */ - obj_desc->buffer.node = (acpi_namespace_node *) walk_state->operands[0]; - obj_desc->buffer.aml_start = op->named.data; - obj_desc->buffer.aml_length = op->named.length; - break; - - - case ACPI_TYPE_PACKAGE: - - /* - * Defer evaluation of Package Term_arg operand - */ - obj_desc->package.node = (acpi_namespace_node *) walk_state->operands[0]; - obj_desc->package.aml_start = op->named.data; - obj_desc->package.aml_length = op->named.length; - break; - - - case ACPI_TYPE_INTEGER: - - switch (op_info->type) { - case AML_TYPE_CONSTANT: - /* - * Resolve AML Constants here - AND ONLY HERE! - * All constants are integers. - * We mark the integer with a flag that indicates that it started life - * as a constant -- so that stores to constants will perform as expected (noop). - * (Zero_op is used as a placeholder for optional target operands.) - */ - obj_desc->common.flags = AOPOBJ_AML_CONSTANT; - - switch (opcode) { - case AML_ZERO_OP: - - obj_desc->integer.value = 0; - break; - - case AML_ONE_OP: - - obj_desc->integer.value = 1; - break; - - case AML_ONES_OP: - - obj_desc->integer.value = ACPI_INTEGER_MAX; - - /* Truncate value if we are executing from a 32-bit ACPI table */ - - acpi_ex_truncate_for32bit_table (obj_desc); - break; - - case AML_REVISION_OP: - - obj_desc->integer.value = ACPI_CA_SUPPORT_LEVEL; - break; - - default: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode)); - status = AE_AML_OPERAND_TYPE; - break; - } - break; - - - case AML_TYPE_LITERAL: - - obj_desc->integer.value = op->common.value.integer; - break; - - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type)); - status = AE_AML_OPERAND_TYPE; - break; - } - break; - - - case ACPI_TYPE_STRING: - - obj_desc->string.pointer = op->common.value.string; - obj_desc->string.length = ACPI_STRLEN (op->common.value.string); - - /* - * The string is contained in the ACPI table, don't ever try - * to delete it - */ - obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; - break; - - - case ACPI_TYPE_METHOD: - break; - - - case INTERNAL_TYPE_REFERENCE: - - switch (op_info->type) { - case AML_TYPE_LOCAL_VARIABLE: - - /* Split the opcode into a base opcode + offset */ - - obj_desc->reference.opcode = AML_LOCAL_OP; - obj_desc->reference.offset = opcode - AML_LOCAL_OP; - acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, - walk_state, (acpi_namespace_node **) &obj_desc->reference.object); - break; - - - case AML_TYPE_METHOD_ARGUMENT: - - /* Split the opcode into a base opcode + offset */ - - obj_desc->reference.opcode = AML_ARG_OP; - obj_desc->reference.offset = opcode - AML_ARG_OP; - break; - - - default: /* Other literals, etc.. */ - - if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { - /* Node was saved in Op */ - - obj_desc->reference.node = op->common.node; - } - - obj_desc->reference.opcode = opcode; - break; - } - break; - - - default: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n", - ACPI_GET_OBJECT_TYPE (obj_desc))); - - status = AE_AML_OPERAND_TYPE; - break; - } - - return_ACPI_STATUS (status); -} - - -/***************************************************************************** - * * FUNCTION: Acpi_ds_build_internal_object * * PARAMETERS: Walk_state - Current walk state @@ -778,6 +586,204 @@ /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + +#endif /* ACPI_NO_METHOD_EXECUTION */ + + +/***************************************************************************** + * + * FUNCTION: Acpi_ds_init_object_from_op + * + * PARAMETERS: Walk_state - Current walk state + * Op - Parser op used to init the internal object + * Opcode - AML opcode associated with the object + * Ret_obj_desc - Namespace object to be initialized + * + * RETURN: Status + * + * DESCRIPTION: Initialize a namespace object from a parser Op and its + * associated arguments. The namespace object is a more compact + * representation of the Op and its arguments. + * + ****************************************************************************/ + +acpi_status +acpi_ds_init_object_from_op ( + acpi_walk_state *walk_state, + acpi_parse_object *op, + u16 opcode, + acpi_operand_object **ret_obj_desc) +{ + const acpi_opcode_info *op_info; + acpi_operand_object *obj_desc; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("Ds_init_object_from_op"); + + + obj_desc = *ret_obj_desc; + op_info = acpi_ps_get_opcode_info (opcode); + if (op_info->class == AML_CLASS_UNKNOWN) { + /* Unknown opcode */ + + return_ACPI_STATUS (AE_TYPE); + } + + /* Perform per-object initialization */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_BUFFER: + + /* + * Defer evaluation of Buffer Term_arg operand + */ + obj_desc->buffer.node = (acpi_namespace_node *) walk_state->operands[0]; + obj_desc->buffer.aml_start = op->named.data; + obj_desc->buffer.aml_length = op->named.length; + break; + + + case ACPI_TYPE_PACKAGE: + + /* + * Defer evaluation of Package Term_arg operand + */ + obj_desc->package.node = (acpi_namespace_node *) walk_state->operands[0]; + obj_desc->package.aml_start = op->named.data; + obj_desc->package.aml_length = op->named.length; + break; + + + case ACPI_TYPE_INTEGER: + + switch (op_info->type) { + case AML_TYPE_CONSTANT: + /* + * Resolve AML Constants here - AND ONLY HERE! + * All constants are integers. + * We mark the integer with a flag that indicates that it started life + * as a constant -- so that stores to constants will perform as expected (noop). + * (Zero_op is used as a placeholder for optional target operands.) + */ + obj_desc->common.flags = AOPOBJ_AML_CONSTANT; + + switch (opcode) { + case AML_ZERO_OP: + + obj_desc->integer.value = 0; + break; + + case AML_ONE_OP: + + obj_desc->integer.value = 1; + break; + + case AML_ONES_OP: + + obj_desc->integer.value = ACPI_INTEGER_MAX; + + /* Truncate value if we are executing from a 32-bit ACPI table */ + +#ifndef ACPI_NO_METHOD_EXECUTION + acpi_ex_truncate_for32bit_table (obj_desc); +#endif + break; + + case AML_REVISION_OP: + + obj_desc->integer.value = ACPI_CA_SUPPORT_LEVEL; + break; + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode)); + status = AE_AML_OPERAND_TYPE; + break; + } + break; + + + case AML_TYPE_LITERAL: + + obj_desc->integer.value = op->common.value.integer; + break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type)); + status = AE_AML_OPERAND_TYPE; + break; + } + break; + + + case ACPI_TYPE_STRING: + + obj_desc->string.pointer = op->common.value.string; + obj_desc->string.length = ACPI_STRLEN (op->common.value.string); + + /* + * The string is contained in the ACPI table, don't ever try + * to delete it + */ + obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; + break; + + + case ACPI_TYPE_METHOD: + break; + + + case INTERNAL_TYPE_REFERENCE: + + switch (op_info->type) { + case AML_TYPE_LOCAL_VARIABLE: + + /* Split the opcode into a base opcode + offset */ + + obj_desc->reference.opcode = AML_LOCAL_OP; + obj_desc->reference.offset = opcode - AML_LOCAL_OP; +#ifndef ACPI_NO_METHOD_EXECUTION + acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, + walk_state, (acpi_namespace_node **) &obj_desc->reference.object); +#endif + break; + + + case AML_TYPE_METHOD_ARGUMENT: + + /* Split the opcode into a base opcode + offset */ + + obj_desc->reference.opcode = AML_ARG_OP; + obj_desc->reference.offset = opcode - AML_ARG_OP; + break; + + default: /* Other literals, etc.. */ + + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { + /* Node was saved in Op */ + + obj_desc->reference.node = op->common.node; + } + + obj_desc->reference.opcode = opcode; + break; + } + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n", + ACPI_GET_OBJECT_TYPE (obj_desc))); + + status = AE_AML_OPERAND_TYPE; + break; + } + return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c --- a/drivers/acpi/dispatcher/dsutils.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/dispatcher/dsutils.c Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: dsutils - Dispatcher utilities - * $Revision: 93 $ + * $Revision: 94 $ * ******************************************************************************/ @@ -35,6 +35,7 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsutils") +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * @@ -237,6 +238,47 @@ /******************************************************************************* * + * FUNCTION: Acpi_ds_resolve_operands + * + * PARAMETERS: Walk_state - Current walk state with operands on stack + * + * RETURN: Status + * + * DESCRIPTION: Resolve all operands to their values. Used to prepare + * arguments to a control method invocation (a call from one + * method to another.) + * + ******************************************************************************/ + +acpi_status +acpi_ds_resolve_operands ( + acpi_walk_state *walk_state) +{ + u32 i; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("Ds_resolve_operands", walk_state); + + + /* + * Attempt to resolve each of the valid operands + * Method arguments are passed by value, not by reference + */ + for (i = 0; i < walk_state->num_operands; i++) { + status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state); + if (ACPI_FAILURE (status)) { + break; + } + } + + return_ACPI_STATUS (status); +} +#endif + + +/******************************************************************************* + * * FUNCTION: Acpi_ds_create_operand * * PARAMETERS: Walk_state @@ -514,43 +556,4 @@ return_ACPI_STATUS (status); } - -/******************************************************************************* - * - * FUNCTION: Acpi_ds_resolve_operands - * - * PARAMETERS: Walk_state - Current walk state with operands on stack - * - * RETURN: Status - * - * DESCRIPTION: Resolve all operands to their values. Used to prepare - * arguments to a control method invocation (a call from one - * method to another.) - * - ******************************************************************************/ - -acpi_status -acpi_ds_resolve_operands ( - acpi_walk_state *walk_state) -{ - u32 i; - acpi_status status = AE_OK; - - - ACPI_FUNCTION_TRACE_PTR ("Ds_resolve_operands", walk_state); - - - /* - * Attempt to resolve each of the valid operands - * Method arguments are passed by value, not by reference - */ - for (i = 0; i < walk_state->num_operands; i++) { - status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state); - if (ACPI_FAILURE (status)) { - break; - } - } - - return_ACPI_STATUS (status); -} diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c --- a/drivers/acpi/dispatcher/dswload.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/dispatcher/dswload.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dswload - Dispatcher namespace load callbacks - * $Revision: 67 $ + * $Revision: 69 $ * *****************************************************************************/ @@ -70,9 +70,11 @@ break; case 3: +#ifndef ACPI_NO_METHOD_EXECUTION walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_exec_begin_op; walk_state->ascending_callback = acpi_ds_exec_end_op; +#endif break; default: @@ -169,6 +171,11 @@ op->named.name = node->name.integer; +#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) + op->named.path = (u8 *) path; +#endif + + /* * Put the Node in the "op" object that the parser uses, so we * can get it again quickly when this scope is closed @@ -221,6 +228,7 @@ object_type = walk_state->op_info->object_type; +#ifndef ACPI_NO_METHOD_EXECUTION if (walk_state->op_info->flags & AML_FIELD) { if (walk_state->opcode == AML_FIELD_OP || walk_state->opcode == AML_BANK_FIELD_OP || @@ -238,6 +246,7 @@ return (status); } } +#endif if (op->common.aml_opcode == AML_NAME_OP) { /* For Name opcode, get the object type from the argument */ @@ -430,7 +439,9 @@ acpi_namespace_node *node; acpi_parse_object *arg; acpi_namespace_node *new_node; +#ifndef ACPI_NO_METHOD_EXECUTION u32 i; +#endif ACPI_FUNCTION_NAME ("Ds_load2_end_op"); @@ -478,6 +489,7 @@ } } + /* * Named operations are as follows: * @@ -515,6 +527,8 @@ arg = op->common.value.arg; switch (walk_state->op_info->type) { +#ifndef ACPI_NO_METHOD_EXECUTION + case AML_TYPE_CREATE_FIELD: /* @@ -604,7 +618,7 @@ } break; - +#endif /* ACPI_NO_METHOD_EXECUTION */ case AML_TYPE_NAMED_COMPLEX: @@ -629,6 +643,7 @@ break; +#ifndef ACPI_NO_METHOD_EXECUTION case AML_REGION_OP: /* * The Op_region is not fully parsed at this time. Only valid argument is the Space_id. @@ -656,6 +671,7 @@ status = acpi_ds_create_node (walk_state, node, op); break; +#endif /* ACPI_NO_METHOD_EXECUTION */ default: diff -Nru a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c --- a/drivers/acpi/dispatcher/dswstate.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/dispatcher/dswstate.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dswstate - Dispatcher parse tree walk management routines - * $Revision: 65 $ + * $Revision: 67 $ * *****************************************************************************/ @@ -837,7 +837,7 @@ /* Init the method args/local */ -#ifndef _ACPI_ASL_COMPILER +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) acpi_ds_method_data_init (walk_state); #endif @@ -858,7 +858,6 @@ } -#ifndef _ACPI_ASL_COMPILER /******************************************************************************* * * FUNCTION: Acpi_ds_init_aml_walk @@ -943,7 +942,6 @@ status = acpi_ds_init_callbacks (walk_state, pass_number); return_ACPI_STATUS (status); } -#endif /******************************************************************************* diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c --- a/drivers/acpi/ec.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/ec.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 35 $) + * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -62,15 +62,15 @@ static int acpi_ec_stop (struct acpi_device *device, int type); static struct acpi_driver acpi_ec_driver = { - name: ACPI_EC_DRIVER_NAME, - class: ACPI_EC_CLASS, - ids: ACPI_EC_HID, - ops: { - add: acpi_ec_add, - remove: acpi_ec_remove, - start: acpi_ec_start, - stop: acpi_ec_stop, - }, + .name = ACPI_EC_DRIVER_NAME, + .class = ACPI_EC_CLASS, + .ids = ACPI_EC_HID, + .ops = { + .add = acpi_ec_add, + .remove = acpi_ec_remove, + .start = acpi_ec_start, + .stop = acpi_ec_stop, + }, }; struct acpi_ec { @@ -134,7 +134,7 @@ acpi_ec_read ( struct acpi_ec *ec, u8 address, - u8 *data) + u32 *data) { acpi_status status = AE_OK; int result = 0; @@ -167,7 +167,7 @@ goto end; - acpi_hw_low_level_read(8, (u32*) data, &ec->data_addr, 0); + acpi_hw_low_level_read(8, data, &ec->data_addr, 0); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", *data, address)); @@ -237,7 +237,7 @@ static int acpi_ec_query ( struct acpi_ec *ec, - u8 *data) + u32 *data) { int result = 0; acpi_status status = AE_OK; @@ -269,7 +269,7 @@ if (result) goto end; - acpi_hw_low_level_read(8, (u32*) data, &ec->data_addr, 0); + acpi_hw_low_level_read(8, data, &ec->data_addr, 0); if (!*data) result = -ENODATA; @@ -328,7 +328,7 @@ { acpi_status status = AE_OK; struct acpi_ec *ec = (struct acpi_ec *) data; - u8 value = 0; + u32 value = 0; unsigned long flags = 0; struct acpi_ec_query_data *query_data = NULL; @@ -336,7 +336,7 @@ return; spin_lock_irqsave(&ec->lock, flags); - acpi_hw_low_level_read(8, (u32*) &value, &ec->command_addr, 0); + acpi_hw_low_level_read(8, &value, &ec->command_addr, 0); spin_unlock_irqrestore(&ec->lock, flags); /* TBD: Implement asynch events! @@ -398,6 +398,7 @@ { int result = 0; struct acpi_ec *ec = NULL; + u32 temp = 0; ACPI_FUNCTION_TRACE("acpi_ec_space_handler"); @@ -408,7 +409,8 @@ switch (function) { case ACPI_READ: - result = acpi_ec_read(ec, (u8) address, (u8*) value); + result = acpi_ec_read(ec, (u8) address, &temp); + *value = (acpi_integer) temp; break; case ACPI_WRITE: result = acpi_ec_write(ec, (u8) address, (u8) *value); diff -Nru a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c --- a/drivers/acpi/executer/excreate.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/executer/excreate.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: excreate - Named object creation - * $Revision: 92 $ + * $Revision: 93 $ * *****************************************************************************/ @@ -36,6 +36,7 @@ ACPI_MODULE_NAME ("excreate") +#ifndef ACPI_NO_METHOD_EXECUTION /***************************************************************************** * * FUNCTION: Acpi_ex_create_alias @@ -490,6 +491,7 @@ return_ACPI_STATUS (status); } +#endif /***************************************************************************** * diff -Nru a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c --- a/drivers/acpi/executer/exdump.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/executer/exdump.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exdump - Interpreter debug output routines - * $Revision: 156 $ + * $Revision: 157 $ * *****************************************************************************/ @@ -575,14 +575,14 @@ { if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { - return; + return_VOID; } } if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { acpi_os_printf ("Ex_dump_object_descriptor: %p is not a valid ACPI object\n", obj_desc); - return; + return_VOID; } /* Common Fields */ diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c --- a/drivers/acpi/executer/exoparg1.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/executer/exoparg1.c Fri Jul 26 19:58:52 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exoparg1 - AML execution - opcodes with 1 argument - * $Revision: 140 $ + * $Revision: 141 $ * *****************************************************************************/ @@ -804,16 +804,7 @@ switch (operand[0]->reference.target_type) { case ACPI_TYPE_BUFFER_FIELD: - /* Ensure that the Buffer arguments are evaluated */ - temp_desc = operand[0]->reference.object; -#if 0 - - status = acpi_ds_get_buffer_arguments (temp_desc); - if (ACPI_FAILURE (status)) { - goto cleanup; - } -#endif /* * Create a new object that contains one element of the @@ -841,14 +832,6 @@ case ACPI_TYPE_PACKAGE: -#if 0 - /* Ensure that the Package arguments are evaluated */ - - status = acpi_ds_get_package_arguments (operand[0]->reference.object); - if (ACPI_FAILURE (status)) { - goto cleanup; - } -#endif /* * Return the referenced element of the package. We must add * another reference to the referenced object, however. @@ -883,6 +866,11 @@ case AML_REF_OF_OP: return_desc = operand[0]->reference.object; + + if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == ACPI_DESC_TYPE_NAMED) { + + return_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) return_desc); + } /* Add another reference to the object! */ diff -Nru a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c --- a/drivers/acpi/executer/exutils.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/executer/exutils.c Fri Jul 26 19:58:50 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exutils - interpreter/scanner utilities - * $Revision: 100 $ + * $Revision: 102 $ * *****************************************************************************/ @@ -52,6 +52,34 @@ /******************************************************************************* * + * FUNCTION: Acpi_ex_validate_object_type + * + * PARAMETERS: Type Object type to validate + * + * DESCRIPTION: Determine if a type is a valid ACPI object type + * + ******************************************************************************/ + +u8 +acpi_ex_validate_object_type ( + acpi_object_type type) +{ + + ACPI_FUNCTION_ENTRY (); + + + if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) || + (type > INTERNAL_TYPE_MAX)) { + return (FALSE); + } + + return (TRUE); +} + +#ifndef ACPI_NO_METHOD_EXECUTION + +/******************************************************************************* + * * FUNCTION: Acpi_ex_enter_interpreter * * PARAMETERS: None @@ -118,33 +146,6 @@ /******************************************************************************* * - * FUNCTION: Acpi_ex_validate_object_type - * - * PARAMETERS: Type Object type to validate - * - * DESCRIPTION: Determine if a type is a valid ACPI object type - * - ******************************************************************************/ - -u8 -acpi_ex_validate_object_type ( - acpi_object_type type) -{ - - ACPI_FUNCTION_ENTRY (); - - - if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) || - (type > INTERNAL_TYPE_MAX)) { - return (FALSE); - } - - return (TRUE); -} - - -/******************************************************************************* - * * FUNCTION: Acpi_ex_truncate_for32bit_table * * PARAMETERS: Obj_desc - Object to be truncated @@ -263,6 +264,8 @@ ACPI_REPORT_ERROR (("Could not release ACPI Global Lock\n")); } } + + return_VOID; } @@ -378,4 +381,4 @@ } } - +#endif diff -Nru a/drivers/acpi/fan.c b/drivers/acpi/fan.c --- a/drivers/acpi/fan.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/fan.c Fri Jul 26 19:58:50 2002 @@ -1,5 +1,5 @@ /* - * acpi_fan.c - ACPI Fan Driver ($Revision: 28 $) + * acpi_fan.c - ACPI Fan Driver ($Revision: 29 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -47,13 +47,13 @@ int acpi_fan_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_fan_driver = { - name: ACPI_FAN_DRIVER_NAME, - class: ACPI_FAN_CLASS, - ids: ACPI_FAN_HID, - ops: { - add: acpi_fan_add, - remove: acpi_fan_remove, - }, + .name = ACPI_FAN_DRIVER_NAME, + .class = ACPI_FAN_CLASS, + .ids = ACPI_FAN_HID, + .ops = { + .add = acpi_fan_add, + .remove = acpi_fan_remove, + }, }; struct acpi_fan { diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h --- a/drivers/acpi/include/acconfig.h Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/include/acconfig.h Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 105 $ + * $Revision: 107 $ * *****************************************************************************/ @@ -54,7 +54,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20020702 +#define ACPI_CA_VERSION 0x20020725 /* Version of ACPI supported */ @@ -151,6 +151,15 @@ /* Maximum Space_ids for Operation Regions */ #define ACPI_MAX_ADDRESS_SPACE 255 + +/* Array sizes. Used for range checking also */ + +#define NUM_ACCESS_TYPES 6 +#define NUM_UPDATE_RULES 3 +#define NUM_LOCK_RULES 2 +#define NUM_MATCH_OPS 6 +#define NUM_OPCODES 256 +#define NUM_FIELD_NAMES 2 /* RSDP checksums */ diff -Nru a/drivers/acpi/include/acdebug.h b/drivers/acpi/include/acdebug.h --- a/drivers/acpi/include/acdebug.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/acdebug.h Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acdebug.h - ACPI/AML debugger - * $Revision: 62 $ + * $Revision: 63 $ * *****************************************************************************/ @@ -29,7 +29,6 @@ #define ACPI_DEBUG_BUFFER_SIZE 4196 - typedef struct command_info { NATIVE_CHAR *name; /* Command Name */ @@ -186,47 +185,6 @@ /* - * dbdisasm - AML disassembler - */ - -void -acpi_db_display_op ( - acpi_walk_state *walk_state, - acpi_parse_object *origin, - u32 num_opcodes); - -void -acpi_db_display_namestring ( - NATIVE_CHAR *name); - -void -acpi_db_display_path ( - acpi_parse_object *op); - -void -acpi_db_display_opcode ( - acpi_walk_state *walk_state, - acpi_parse_object *op); - -void -acpi_db_decode_internal_object ( - acpi_operand_object *obj_desc); - -void -acpi_db_decode_node ( - acpi_namespace_node *node); - -u32 -acpi_db_block_type ( - acpi_parse_object *op); - -acpi_status -acpi_ps_display_object_pathname ( - acpi_walk_state *walk_state, - acpi_parse_object *op); - - -/* * dbdisply - debug display commands */ @@ -281,6 +239,10 @@ void * acpi_db_get_pointer ( void *target); + +void +acpi_db_decode_internal_object ( + acpi_operand_object *obj_desc); /* diff -Nru a/drivers/acpi/include/acdisasm.h b/drivers/acpi/include/acdisasm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/include/acdisasm.h Fri Jul 26 19:58:52 2002 @@ -0,0 +1,362 @@ +/****************************************************************************** + * + * Name: acdisasm.h - AML disassembler + * $Revision: 2 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2002, R. Byron Moore + * + * 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 __ACDISASM_H__ +#define __ACDISASM_H__ + +#include "amlresrc.h" + + +#define BLOCK_NONE 0 +#define BLOCK_PAREN 1 +#define BLOCK_BRACE 2 +#define BLOCK_COMMA_LIST 4 + +extern const char *acpi_gbl_io_decode[2]; +extern const char *acpi_gbl_word_decode[4]; +extern const char *acpi_gbl_consume_decode[2]; +extern const char *acpi_gbl_min_decode[2]; +extern const char *acpi_gbl_max_decode[2]; +extern const char *acpi_gbl_DECdecode[2]; +extern const char *acpi_gbl_RNGdecode[4]; +extern const char *acpi_gbl_MEMdecode[4]; +extern const char *acpi_gbl_RWdecode[2]; +extern const char *acpi_gbl_irq_decode[2]; +extern const char *acpi_gbl_HEdecode[2]; +extern const char *acpi_gbl_LLdecode[2]; +extern const char *acpi_gbl_SHRdecode[2]; +extern const char *acpi_gbl_TYPdecode[4]; +extern const char *acpi_gbl_BMdecode[2]; +extern const char *acpi_gbl_SIZdecode[4]; +extern const NATIVE_CHAR *acpi_gbl_lock_rule[NUM_LOCK_RULES]; +extern const NATIVE_CHAR *acpi_gbl_access_types[NUM_ACCESS_TYPES]; +extern const NATIVE_CHAR *acpi_gbl_update_rules[NUM_UPDATE_RULES]; +extern const NATIVE_CHAR *acpi_gbl_match_ops[NUM_MATCH_OPS]; + + +typedef struct acpi_op_walk_info +{ + u32 level; + u32 bit_offset; + +} ACPI_OP_WALK_INFO; + +typedef +acpi_status (*ASL_WALK_CALLBACK) ( + acpi_parse_object *op, + u32 level, + void *context); + + +/* + * dmwalk + */ + +void +acpi_dm_walk_parse_tree ( + acpi_parse_object *op, + ASL_WALK_CALLBACK descending_callback, + ASL_WALK_CALLBACK ascending_callback, + void *context); + +acpi_status +acpi_dm_descending_op ( + acpi_parse_object *op, + u32 level, + void *context); + +acpi_status +acpi_dm_ascending_op ( + acpi_parse_object *op, + u32 level, + void *context); + + +/* + * dmopcode + */ + +void +acpi_dm_validate_name ( + char *name, + acpi_parse_object *op); + +u32 +acpi_dm_dump_name ( + char *name); + +void +acpi_dm_string ( + char *string); + +void +acpi_dm_unicode ( + acpi_parse_object *op); + +void +acpi_dm_disassemble ( + acpi_walk_state *walk_state, + acpi_parse_object *origin, + u32 num_opcodes); + +void +acpi_dm_namestring ( + NATIVE_CHAR *name); + +void +acpi_dm_display_path ( + acpi_parse_object *op); + +void +acpi_dm_disassemble_one_op ( + acpi_walk_state *walk_state, + ACPI_OP_WALK_INFO *info, + acpi_parse_object *op); + +void +acpi_dm_decode_internal_object ( + acpi_operand_object *obj_desc); + +void +acpi_dm_decode_node ( + acpi_namespace_node *node); + +u32 +acpi_dm_block_type ( + acpi_parse_object *op); + +u32 +acpi_dm_list_type ( + acpi_parse_object *op); + +acpi_status +acpi_ps_display_object_pathname ( + acpi_walk_state *walk_state, + acpi_parse_object *op); + +void +acpi_dm_method_flags ( + acpi_parse_object *op); + +void +acpi_dm_field_flags ( + acpi_parse_object *op); + +void +acpi_dm_address_space ( + u8 space_id); + +void +acpi_dm_region_flags ( + acpi_parse_object *op); + +void +acpi_dm_match_op ( + acpi_parse_object *op); + +void +acpi_dm_match_keyword ( + acpi_parse_object *op); + +u8 +acpi_dm_comma_if_list_member ( + acpi_parse_object *op); + +void +acpi_dm_comma_if_field_member ( + acpi_parse_object *op); + + +/* + * dmbuffer + */ + +void +acpi_is_eisa_id ( + acpi_parse_object *op); + +void +acpi_dm_eisa_id ( + u32 encoded_id); + +u8 +acpi_dm_is_unicode_buffer ( + acpi_parse_object *op); + +u8 +acpi_dm_is_string_buffer ( + acpi_parse_object *op); + + +/* + * dmresrc + */ + +void +acpi_dm_disasm_byte_list ( + u32 level, + u8 *byte_data, + u32 byte_count); + +void +acpi_dm_byte_list ( + ACPI_OP_WALK_INFO *info, + acpi_parse_object *op); + +void +acpi_dm_resource_descriptor ( + ACPI_OP_WALK_INFO *info, + u8 *byte_data, + u32 byte_count); + +u8 +acpi_dm_is_resource_descriptor ( + acpi_parse_object *op); + +void +acpi_dm_indent ( + u32 level); + +void +acpi_dm_bit_list ( + u16 mask); + + +/* + * dmresrcl + */ + +void +acpi_dm_io_flags ( + u8 flags); + +void +acpi_dm_memory_flags ( + u8 flags, + u8 specific_flags); + +void +acpi_dm_word_descriptor ( + ASL_WORD_ADDRESS_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_dword_descriptor ( + ASL_DWORD_ADDRESS_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_qword_descriptor ( + ASL_QWORD_ADDRESS_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_memory24_descriptor ( + ASL_MEMORY_24_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_memory32_descriptor ( + ASL_MEMORY_32_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_fixed_mem32_descriptor ( + ASL_FIXED_MEMORY_32_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_generic_register_descriptor ( + ASL_GENERAL_REGISTER_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_interrupt_descriptor ( + ASL_EXTENDED_XRUPT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_vendor_large_descriptor ( + ASL_LARGE_VENDOR_DESC *resource, + u32 length, + u32 level); + + +/* + * dmresrcs + */ + +void +acpi_dm_irq_descriptor ( + ASL_IRQ_FORMAT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_dma_descriptor ( + ASL_DMA_FORMAT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_io_descriptor ( + ASL_IO_PORT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_fixed_io_descriptor ( + ASL_FIXED_IO_PORT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_start_dependent_descriptor ( + ASL_START_DEPENDENT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_end_dependent_descriptor ( + ASL_START_DEPENDENT_DESC *resource, + u32 length, + u32 level); + +void +acpi_dm_vendor_small_descriptor ( + ASL_SMALL_VENDOR_DESC *resource, + u32 length, + u32 level); + + +#endif /* __ACDISASM_H__ */ diff -Nru a/drivers/acpi/include/acglobal.h b/drivers/acpi/include/acglobal.h --- a/drivers/acpi/include/acglobal.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/acglobal.h Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acglobal.h - Declarations for global variables - * $Revision: 126 $ + * $Revision: 128 $ * *****************************************************************************/ @@ -140,8 +140,9 @@ extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; extern const u8 acpi_gbl_decode_to8bit[8]; -extern const NATIVE_CHAR *acpi_gbl_db_sleep_states[ACPI_NUM_SLEEP_STATES]; +extern const NATIVE_CHAR *acpi_gbl_db_sleep_states[ACPI_NUM_SLEEP_STATES]; extern const acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; +extern const NATIVE_CHAR *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; /***************************************************************************** @@ -237,6 +238,12 @@ ACPI_EXTERN u8 acpi_gbl_db_output_flags; +#ifdef ACPI_DISASSEMBLER + +ACPI_EXTERN u8 acpi_gbl_db_opt_disasm; +ACPI_EXTERN u8 acpi_gbl_db_opt_verbose; +#endif + #ifdef ENABLE_DEBUGGER @@ -247,9 +254,7 @@ ACPI_EXTERN NATIVE_CHAR *optarg; ACPI_EXTERN u8 acpi_gbl_db_opt_tables; -ACPI_EXTERN u8 acpi_gbl_db_opt_disasm; ACPI_EXTERN u8 acpi_gbl_db_opt_stats; -ACPI_EXTERN u8 acpi_gbl_db_opt_verbose; ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; @@ -261,7 +266,6 @@ ACPI_EXTERN u8 acpi_gbl_db_output_to_file; ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_buffer; ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_filename; -ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_disasm_indent; ACPI_EXTERN u32 acpi_gbl_db_debug_level; ACPI_EXTERN u32 acpi_gbl_db_console_debug_level; ACPI_EXTERN acpi_table_header *acpi_gbl_db_table_ptr; diff -Nru a/drivers/acpi/include/aclocal.h b/drivers/acpi/include/aclocal.h --- a/drivers/acpi/include/aclocal.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/aclocal.h Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: aclocal.h - Internal data types used across the ACPI subsystem - * $Revision: 168 $ + * $Revision: 173 $ * *****************************************************************************/ @@ -567,8 +567,8 @@ */ typedef struct acpi_opcode_info { -#ifdef _OPCODE_NAMES - NATIVE_CHAR *name; /* Opcode name (debug only) */ +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG) + NATIVE_CHAR *name; /* Opcode name (disassembler/debug only) */ #endif u32 parse_args; /* Grammar/Parse time arguments */ u32 runtime_args; /* Interpret time arguments */ @@ -603,15 +603,23 @@ u32 aml_offset; /* offset of declaration in AML */\ union acpi_parse_obj *parent; /* parent op */\ union acpi_parse_obj *next; /* next op */\ - ACPI_DEBUG_ONLY_MEMBERS (\ + ACPI_DISASM_ONLY_MEMBERS (\ + u8 disasm_flags; /* Used during AML disassembly */\ + u8 disasm_opcode; /* Subtype used for disassembly */\ NATIVE_CHAR aml_op_name[16]) /* op name (debug only) */\ /* NON-DEBUG members below: */\ acpi_namespace_node *node; /* for use by interpreter */\ acpi_parse_value value; /* Value or args associated with the opcode */\ +#define ACPI_DASM_BUFFER 0x00 +#define ACPI_DASM_RESOURCE 0x01 +#define ACPI_DASM_STRING 0x02 +#define ACPI_DASM_UNICODE 0x03 +#define ACPI_DASM_EISAID 0x04 +#define ACPI_DASM_MATCHOP 0x05 /* - * generic operation (eg. If, While, Store) + * generic operation (for example: If, While, Store) */ typedef struct acpi_parseobj_common { @@ -626,6 +634,7 @@ typedef struct acpi_parseobj_named { ACPI_PARSE_COMMON + u8 *path; u8 *data; /* AML body or bytelist data */ u32 length; /* AML length */ u32 name; /* 4-byte name or zero if no name */ @@ -653,15 +662,15 @@ u32 logical_byte_offset; u32 end_line; u32 end_logical_line; - u16 parse_opcode; u32 acpi_btype; u32 aml_length; u32 aml_subtree_length; u32 final_aml_length; u32 final_aml_offset; + u16 parse_opcode; + u16 compile_flags; u8 aml_opcode_length; u8 aml_pkg_len_bytes; - u16 compile_flags; u8 extra; char parse_op_name[12]; @@ -704,6 +713,13 @@ #define ACPI_PARSEOP_DEFERRED 0x04 #define ACPI_PARSEOP_BYTELIST 0x08 #define ACPI_PARSEOP_IN_CACHE 0x80 + +/* Parse object Disasm_flags */ + +#define ACPI_PARSEOP_IGNORE 0x01 +#define ACPI_PARSEOP_PARAMLIST 0x02 +#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 +#define ACPI_PARSEOP_SPECIAL 0x10 /***************************************************************************** diff -Nru a/drivers/acpi/include/acmacros.h b/drivers/acpi/include/acmacros.h --- a/drivers/acpi/include/acmacros.h Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/include/acmacros.h Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acmacros.h - C macros for the entire subsystem. - * $Revision: 124 $ + * $Revision: 126 $ * *****************************************************************************/ @@ -287,12 +287,18 @@ /* * Macros for the master AML opcode table */ -#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) +#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG) #define ACPI_OP(name,Pargs,Iargs,obj_type,class,type,flags) {name,Pargs,Iargs,flags,obj_type,class,type} #else #define ACPI_OP(name,Pargs,Iargs,obj_type,class,type,flags) {Pargs,Iargs,flags,obj_type,class,type} #endif +#ifdef ACPI_DISASSEMBLER +#define ACPI_DISASM_ONLY_MEMBERS(a) a; +#else +#define ACPI_DISASM_ONLY_MEMBERS(a) +#endif + #define ARG_TYPE_WIDTH 5 #define ARG_1(x) ((u32)(x)) #define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH)) @@ -435,7 +441,6 @@ #define ACPI_DEBUG_DEFINE(a) a; #define ACPI_DEBUG_ONLY_MEMBERS(a) a; -#define _OPCODE_NAMES #define _VERBOSE_STRUCTURES @@ -514,10 +519,6 @@ #define return_ACPI_STATUS(s) return(s) #define return_VALUE(s) return(s) #define return_PTR(s) return(s) - -#ifdef ENABLE_DEBUGGER -#define _OPCODE_NAMES -#endif #endif diff -Nru a/drivers/acpi/include/acnamesp.h b/drivers/acpi/include/acnamesp.h --- a/drivers/acpi/include/acnamesp.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/acnamesp.h Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acnamesp.h - Namespace subcomponent prototypes and defines - * $Revision: 125 $ + * $Revision: 126 $ * *****************************************************************************/ @@ -43,7 +43,7 @@ /* Definitions of the predefined namespace names */ #define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */ -#define ACPI_ROOT_NAME (u32) 0x2F202020 /* Root name is "/ " */ +#define ACPI_ROOT_NAME (u32) 0x5F5F5F5C /* Root name is "\___" */ #define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */ #define ACPI_NS_ROOT_PATH "\\" diff -Nru a/drivers/acpi/include/acpiosxf.h b/drivers/acpi/include/acpiosxf.h --- a/drivers/acpi/include/acpiosxf.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/acpiosxf.h Fri Jul 26 19:58:50 2002 @@ -204,7 +204,6 @@ void *value, u32 width); - acpi_status acpi_os_write_port ( ACPI_IO_ADDRESS address, @@ -222,7 +221,6 @@ void *value, u32 width); - acpi_status acpi_os_write_memory ( ACPI_PHYSICAL_ADDRESS address, @@ -241,7 +239,6 @@ void *value, u32 width); - acpi_status acpi_os_write_pci_configuration ( acpi_pci_id *pci_id, @@ -259,7 +256,6 @@ void *pointer, u32 length); - u8 acpi_os_writable ( void *pointer, @@ -287,6 +283,10 @@ acpi_os_vprintf ( const NATIVE_CHAR *format, va_list args); + +void +acpi_os_redirect_output ( + void *destination); /* diff -Nru a/drivers/acpi/include/acutils.h b/drivers/acpi/include/acutils.h --- a/drivers/acpi/include/acutils.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/acutils.h Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures - * $Revision: 140 $ + * $Revision: 142 $ * *****************************************************************************/ @@ -224,6 +224,9 @@ #define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) #define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) #define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) +#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_SP | _ACPI_PU)) +#define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) +#define ACPI_IS_ASCII(c) ((c) < 0x80) #endif /* ACPI_USE_SYSTEM_CLIBRARY */ diff -Nru a/drivers/acpi/include/amlcode.h b/drivers/acpi/include/amlcode.h --- a/drivers/acpi/include/amlcode.h Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/include/amlcode.h Fri Jul 26 19:58:52 2002 @@ -3,7 +3,7 @@ * Name: amlcode.h - Definitions for AML, as included in "definition blocks" * Declarations and definitions contained herein are derived * directly from the ACPI specification. - * $Revision: 68 $ + * $Revision: 69 $ * *****************************************************************************/ @@ -472,15 +472,6 @@ #define METHOD_FLAGS_ARG_COUNT 0x07 #define METHOD_FLAGS_SERIALIZED 0x08 #define METHOD_FLAGS_SYNCH_LEVEL 0xF0 - - -/* Array sizes. Used for range checking also */ - -#define NUM_ACCESS_TYPES 6 -#define NUM_UPDATE_RULES 3 -#define NUM_MATCH_OPS 7 -#define NUM_OPCODES 256 -#define NUM_FIELD_NAMES 2 #endif /* __AMLCODE_H__ */ diff -Nru a/drivers/acpi/include/amlresrc.h b/drivers/acpi/include/amlresrc.h --- a/drivers/acpi/include/amlresrc.h Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/include/amlresrc.h Fri Jul 26 19:58:50 2002 @@ -1,8 +1,8 @@ /****************************************************************************** * - * Module Name: aslresource.h - ASL resource descriptors - * $Revision: 19 $ + * Module Name: amlresrc.h - AML resource descriptors + * $Revision: 20 $ * *****************************************************************************/ @@ -25,8 +25,8 @@ */ -#ifndef __ASLRESOURCE_H -#define __ASLRESOURCE_H +#ifndef __AMLRESRC_H +#define __AMLRESRC_H #define ASL_RESNAME_ADDRESS "_ADR" @@ -80,11 +80,13 @@ /* - * Resource descriptors defined in the ACPI specification + * Resource descriptors defined in the ACPI specification. + * + * Alignment must be BYTE because these descriptors + * are used to overlay the AML byte stream. */ - - #pragma pack(1) + typedef struct asl_irq_format_desc { u8 descriptor_type; @@ -94,7 +96,6 @@ } ASL_IRQ_FORMAT_DESC; -#pragma pack(1) typedef struct asl_irq_noflags_desc { u8 descriptor_type; @@ -103,7 +104,6 @@ } ASL_IRQ_NOFLAGS_DESC; -#pragma pack(1) typedef struct asl_dma_format_desc { u8 descriptor_type; @@ -113,7 +113,6 @@ } ASL_DMA_FORMAT_DESC; -#pragma pack(1) typedef struct asl_start_dependent_desc { u8 descriptor_type; @@ -122,7 +121,6 @@ } ASL_START_DEPENDENT_DESC; -#pragma pack(1) typedef struct asl_start_dependent_noprio_desc { u8 descriptor_type; @@ -130,7 +128,6 @@ } ASL_START_DEPENDENT_NOPRIO_DESC; -#pragma pack(1) typedef struct asl_end_dependent_desc { u8 descriptor_type; @@ -138,7 +135,6 @@ } ASL_END_DEPENDENT_DESC; -#pragma pack(1) typedef struct asl_io_port_desc { u8 descriptor_type; @@ -151,7 +147,6 @@ } ASL_IO_PORT_DESC; -#pragma pack(1) typedef struct asl_fixed_io_port_desc { u8 descriptor_type; @@ -161,7 +156,6 @@ } ASL_FIXED_IO_PORT_DESC; -#pragma pack(1) typedef struct asl_small_vendor_desc { u8 descriptor_type; @@ -170,7 +164,6 @@ } ASL_SMALL_VENDOR_DESC; -#pragma pack(1) typedef struct asl_end_tag_desc { u8 descriptor_type; @@ -181,7 +174,6 @@ /* LARGE descriptors */ -#pragma pack(1) typedef struct asl_memory_24_desc { u8 descriptor_type; @@ -195,7 +187,6 @@ } ASL_MEMORY_24_DESC; -#pragma pack(1) typedef struct asl_large_vendor_desc { u8 descriptor_type; @@ -205,7 +196,6 @@ } ASL_LARGE_VENDOR_DESC; -#pragma pack(1) typedef struct asl_memory_32_desc { u8 descriptor_type; @@ -219,7 +209,6 @@ } ASL_MEMORY_32_DESC; -#pragma pack(1) typedef struct asl_fixed_memory_32_desc { u8 descriptor_type; @@ -231,7 +220,6 @@ } ASL_FIXED_MEMORY_32_DESC; -#pragma pack(1) typedef struct asl_qword_address_desc { u8 descriptor_type; @@ -249,7 +237,6 @@ } ASL_QWORD_ADDRESS_DESC; -#pragma pack(1) typedef struct asl_dword_address_desc { u8 descriptor_type; @@ -267,7 +254,6 @@ } ASL_DWORD_ADDRESS_DESC; -#pragma pack(1) typedef struct asl_word_address_desc { u8 descriptor_type; @@ -285,7 +271,6 @@ } ASL_WORD_ADDRESS_DESC; -#pragma pack(1) typedef struct asl_extended_xrupt_desc { u8 descriptor_type; @@ -298,7 +283,6 @@ } ASL_EXTENDED_XRUPT_DESC; -#pragma pack(1) typedef struct asl_general_register_desc { u8 descriptor_type; @@ -311,6 +295,9 @@ } ASL_GENERAL_REGISTER_DESC; +/* restore default alignment */ + +#pragma pack() /* Union of all resource descriptors, sow we can allocate the worst case */ diff -Nru a/drivers/acpi/include/platform/acenv.h b/drivers/acpi/include/platform/acenv.h --- a/drivers/acpi/include/platform/acenv.h Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/include/platform/acenv.h Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acenv.h - Generation environment specific items - * $Revision: 95 $ + * $Revision: 99 $ * *****************************************************************************/ @@ -32,11 +32,13 @@ */ #ifdef _ACPI_DUMP_APP +#ifndef MSDOS #define ACPI_DEBUG +#endif #define ACPI_APPLICATION -#define ENABLE_DEBUGGER +#define ACPI_DISASSEMBLER +#define ACPI_NO_METHOD_EXECUTION #define ACPI_USE_SYSTEM_CLIBRARY -#define PARSER_ONLY #endif #ifdef _ACPI_EXEC_APP @@ -45,13 +47,15 @@ #define ACPI_DEBUG #define ACPI_APPLICATION #define ENABLE_DEBUGGER +#define ACPI_DISASSEMBLER #define ACPI_USE_SYSTEM_CLIBRARY #endif #ifdef _ACPI_ASL_COMPILER #define ACPI_DEBUG #define ACPI_APPLICATION -/* #define ENABLE_DEBUGGER */ +#define ACPI_DISASSEMBLER +#define ACPI_CONSTANT_EVAL_ONLY #define ACPI_USE_SYSTEM_CLIBRARY #endif @@ -183,7 +187,6 @@ /* * Use the standard C library headers. * We want to keep these to a minimum. - * */ #ifdef ACPI_USE_STANDARD_HEADERS @@ -213,12 +216,16 @@ #define ACPI_STRTOUL(d,s,n) strtoul((d), (s), (ACPI_SIZE)(n)) #define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (ACPI_SIZE)(n)) #define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (ACPI_SIZE)(n)) + #define ACPI_TOUPPER toupper #define ACPI_TOLOWER tolower #define ACPI_IS_XDIGIT isxdigit #define ACPI_IS_DIGIT isdigit #define ACPI_IS_SPACE isspace #define ACPI_IS_UPPER isupper +#define ACPI_IS_PRINT isprint +#define ACPI_IS_ALPHA isalpha +#define ACPI_IS_ASCII isascii /****************************************************************************** * diff -Nru a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c --- a/drivers/acpi/namespace/nsdump.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/namespace/nsdump.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: nsdump - table dumping routines for debug - * $Revision: 136 $ + * $Revision: 137 $ * *****************************************************************************/ @@ -618,93 +618,6 @@ (void *) &info, NULL); } - -#ifndef _ACPI_ASL_COMPILER -/******************************************************************************* - * - * FUNCTION: Acpi_ns_dump_one_device - * - * PARAMETERS: Handle - Node to be dumped - * Level - Nesting level of the handle - * Context - Passed into Walk_namespace - * - * DESCRIPTION: Dump a single Node that represents a device - * This procedure is a User_function called by Acpi_ns_walk_namespace. - * - ******************************************************************************/ - -acpi_status -acpi_ns_dump_one_device ( - acpi_handle obj_handle, - u32 level, - void *context, - void **return_value) -{ - acpi_device_info info; - acpi_status status; - u32 i; - - - ACPI_FUNCTION_NAME ("Ns_dump_one_device"); - - - status = acpi_ns_dump_one_object (obj_handle, level, context, return_value); - - status = acpi_get_object_info (obj_handle, &info); - if (ACPI_SUCCESS (status)) { - for (i = 0; i < level; i++) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ")); - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", - info.hardware_id, - ACPI_HIDWORD (info.address), ACPI_LODWORD (info.address), - info.current_status)); - } - - return (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ns_dump_root_devices - * - * PARAMETERS: None - * - * DESCRIPTION: Dump all objects of type "device" - * - ******************************************************************************/ - -void -acpi_ns_dump_root_devices (void) -{ - acpi_handle sys_bus_handle; - acpi_status status; - - - ACPI_FUNCTION_NAME ("Ns_dump_root_devices"); - - - /* Only dump the table if tracing is enabled */ - - if (!(ACPI_LV_TABLES & acpi_dbg_level)) { - return; - } - - status = acpi_get_handle (0, ACPI_NS_SYSTEM_BUS, &sys_bus_handle); - if (ACPI_FAILURE (status)) { - return; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Display of all devices in the namespace:\n")); - - status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, sys_bus_handle, - ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, - acpi_ns_dump_one_device, NULL, NULL); -} - -#endif /******************************************************************************* * diff -Nru a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/namespace/nsdumpdv.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Module Name: nsdump - table dumping routines for debug + * $Revision: 1 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2002, R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acnamesp.h" +#include "acparser.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsdumpdv") + + +#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_dump_one_device + * + * PARAMETERS: Handle - Node to be dumped + * Level - Nesting level of the handle + * Context - Passed into Walk_namespace + * + * DESCRIPTION: Dump a single Node that represents a device + * This procedure is a User_function called by Acpi_ns_walk_namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ns_dump_one_device ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value) +{ + acpi_device_info info; + acpi_status status; + u32 i; + + + ACPI_FUNCTION_NAME ("Ns_dump_one_device"); + + + status = acpi_ns_dump_one_object (obj_handle, level, context, return_value); + + status = acpi_get_object_info (obj_handle, &info); + if (ACPI_SUCCESS (status)) { + for (i = 0; i < level; i++) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", + info.hardware_id, + ACPI_HIDWORD (info.address), ACPI_LODWORD (info.address), + info.current_status)); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_dump_root_devices + * + * PARAMETERS: None + * + * DESCRIPTION: Dump all objects of type "device" + * + ******************************************************************************/ + +void +acpi_ns_dump_root_devices (void) +{ + acpi_handle sys_bus_handle; + acpi_status status; + + + ACPI_FUNCTION_NAME ("Ns_dump_root_devices"); + + + /* Only dump the table if tracing is enabled */ + + if (!(ACPI_LV_TABLES & acpi_dbg_level)) { + return; + } + + status = acpi_get_handle (0, ACPI_NS_SYSTEM_BUS, &sys_bus_handle); + if (ACPI_FAILURE (status)) { + return; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Display of all devices in the namespace:\n")); + + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, sys_bus_handle, + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, + acpi_ns_dump_one_device, NULL, NULL); +} + +#endif + + diff -Nru a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c --- a/drivers/acpi/namespace/nsload.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/namespace/nsload.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: nsload - namespace loading/expanding/contracting procedures - * $Revision: 56 $ + * $Revision: 57 $ * *****************************************************************************/ @@ -37,59 +37,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_load_namespace - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Load the name space from what ever is pointed to by DSDT. - * (DSDT points to either the BIOS or a buffer.) - * - ******************************************************************************/ - -acpi_status -acpi_ns_load_namespace ( - void) -{ - acpi_status status; - - - ACPI_FUNCTION_TRACE ("Acpi_load_name_space"); - - - /* There must be at least a DSDT installed */ - - if (acpi_gbl_DSDT == NULL) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "DSDT is not in memory\n")); - return_ACPI_STATUS (AE_NO_ACPI_TABLES); - } - - /* - * Load the namespace. The DSDT is required, - * but the SSDT and PSDT tables are optional. - */ - status = acpi_ns_load_table_by_type (ACPI_TABLE_DSDT); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - /* Ignore exceptions from these */ - - (void) acpi_ns_load_table_by_type (ACPI_TABLE_SSDT); - (void) acpi_ns_load_table_by_type (ACPI_TABLE_PSDT); - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - "ACPI Namespace successfully loaded at root %p\n", - acpi_gbl_root_node)); - - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ns_one_parse_pass + * FUNCTION: Ns_one_complete_parse * * PARAMETERS: Pass_number - 1 or 2 * Table_desc - The table to be parsed. @@ -203,6 +151,7 @@ return_ACPI_STATUS (status); } +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * @@ -421,6 +370,58 @@ /******************************************************************************* * + * FUNCTION: Acpi_load_namespace + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the name space from what ever is pointed to by DSDT. + * (DSDT points to either the BIOS or a buffer.) + * + ******************************************************************************/ + +acpi_status +acpi_ns_load_namespace ( + void) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Acpi_load_name_space"); + + + /* There must be at least a DSDT installed */ + + if (acpi_gbl_DSDT == NULL) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "DSDT is not in memory\n")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* + * Load the namespace. The DSDT is required, + * but the SSDT and PSDT tables are optional. + */ + status = acpi_ns_load_table_by_type (ACPI_TABLE_DSDT); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Ignore exceptions from these */ + + (void) acpi_ns_load_table_by_type (ACPI_TABLE_SSDT); + (void) acpi_ns_load_table_by_type (ACPI_TABLE_PSDT); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, + "ACPI Namespace successfully loaded at root %p\n", + acpi_gbl_root_node)); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * * FUNCTION: Acpi_ns_delete_subtree * * PARAMETERS: Start_handle - Handle in namespace where search begins @@ -550,4 +551,5 @@ return_ACPI_STATUS (status); } +#endif diff -Nru a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/namespace/nsxfeval.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,719 @@ +/******************************************************************************* + * + * Module Name: nsxfeval - Public interfaces to the ACPI subsystem + * ACPI Object evaluation interfaces + * $Revision: 1 $ + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2002, R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfeval") + + +/******************************************************************************* + * + * FUNCTION: Acpi_evaluate_object_typed + * + * PARAMETERS: Handle - Object handle (optional) + * *Pathname - Object pathname (optional) + * **External_params - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * *Return_buffer - Where to put method's return value (if + * any). If NULL, no value is returned. + * Return_type - Expected type of return object + * + * RETURN: Status + * + * DESCRIPTION: Find and evaluate the given object, passing the given + * parameters if necessary. One of "Handle" or "Pathname" must + * be valid (non-null) + * + ******************************************************************************/ + +acpi_status +acpi_evaluate_object_typed ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *external_params, + acpi_buffer *return_buffer, + acpi_object_type return_type) +{ + acpi_status status; + u8 must_free = FALSE; + + + ACPI_FUNCTION_TRACE ("Acpi_evaluate_object_typed"); + + + /* Return buffer must be valid */ + + if (!return_buffer) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { + must_free = TRUE; + } + + /* Evaluate the object */ + + status = acpi_evaluate_object (handle, pathname, external_params, return_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Type ANY means "don't care" */ + + if (return_type == ACPI_TYPE_ANY) { + return_ACPI_STATUS (AE_OK); + } + + if (return_buffer->length == 0) { + /* Error because caller specifically asked for a return value */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No return value\n")); + + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Examine the object type returned from Evaluate_object */ + + if (((acpi_object *) return_buffer->pointer)->type == return_type) { + return_ACPI_STATUS (AE_OK); + } + + /* Return object type does not match requested type */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Incorrect return type [%s] requested [%s]\n", + acpi_ut_get_type_name (((acpi_object *) return_buffer->pointer)->type), + acpi_ut_get_type_name (return_type))); + + if (must_free) { + /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ + + acpi_os_free (return_buffer->pointer); + return_buffer->pointer = NULL; + } + + return_buffer->length = 0; + return_ACPI_STATUS (AE_TYPE); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_evaluate_object + * + * PARAMETERS: Handle - Object handle (optional) + * *Pathname - Object pathname (optional) + * **External_params - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * *Return_buffer - Where to put method's return value (if + * any). If NULL, no value is returned. + * + * RETURN: Status + * + * DESCRIPTION: Find and evaluate the given object, passing the given + * parameters if necessary. One of "Handle" or "Pathname" must + * be valid (non-null) + * + ******************************************************************************/ + +acpi_status +acpi_evaluate_object ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *external_params, + acpi_buffer *return_buffer) +{ + acpi_status status; + acpi_operand_object **internal_params = NULL; + acpi_operand_object *internal_return_obj = NULL; + ACPI_SIZE buffer_space_needed; + u32 i; + + + ACPI_FUNCTION_TRACE ("Acpi_evaluate_object"); + + + /* + * If there are parameters to be passed to the object + * (which must be a control method), the external objects + * must be converted to internal objects + */ + if (external_params && external_params->count) { + /* + * Allocate a new parameter block for the internal objects + * Add 1 to count to allow for null terminated internal list + */ + internal_params = ACPI_MEM_CALLOCATE (((ACPI_SIZE) external_params->count + 1) * + sizeof (void *)); + if (!internal_params) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Convert each external object in the list to an + * internal object + */ + for (i = 0; i < external_params->count; i++) { + status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], + &internal_params[i]); + if (ACPI_FAILURE (status)) { + acpi_ut_delete_internal_object_list (internal_params); + return_ACPI_STATUS (status); + } + } + internal_params[external_params->count] = NULL; + } + + /* + * Three major cases: + * 1) Fully qualified pathname + * 2) No handle, not fully qualified pathname (error) + * 3) Valid handle + */ + if ((pathname) && + (acpi_ns_valid_root_prefix (pathname[0]))) { + /* + * The path is fully qualified, just evaluate by name + */ + status = acpi_ns_evaluate_by_name (pathname, internal_params, + &internal_return_obj); + } + else if (!handle) { + /* + * A handle is optional iff a fully qualified pathname + * is specified. Since we've already handled fully + * qualified names above, this is an error + */ + if (!pathname) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Both Handle and Pathname are NULL\n")); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Handle is NULL and Pathname is relative\n")); + } + + status = AE_BAD_PARAMETER; + } + else { + /* + * We get here if we have a handle -- and if we have a + * pathname it is relative. The handle will be validated + * in the lower procedures + */ + if (!pathname) { + /* + * The null pathname case means the handle is for + * the actual object to be evaluated + */ + status = acpi_ns_evaluate_by_handle (handle, internal_params, + &internal_return_obj); + } + else { + /* + * Both a Handle and a relative Pathname + */ + status = acpi_ns_evaluate_relative (handle, pathname, internal_params, + &internal_return_obj); + } + } + + + /* + * If we are expecting a return value, and all went well above, + * copy the return value to an external object. + */ + if (return_buffer) { + if (!internal_return_obj) { + return_buffer->length = 0; + } + else { + if (ACPI_GET_DESCRIPTOR_TYPE (internal_return_obj) == ACPI_DESC_TYPE_NAMED) { + /* + * If we received a NS Node as a return object, this means that + * the object we are evaluating has nothing interesting to + * return (such as a mutex, etc.) We return an error because + * these types are essentially unsupported by this interface. + * We don't check up front because this makes it easier to add + * support for various types at a later date if necessary. + */ + status = AE_TYPE; + internal_return_obj = NULL; /* No need to delete a NS Node */ + return_buffer->length = 0; + } + + if (ACPI_SUCCESS (status)) { + /* + * Find out how large a buffer is needed + * to contain the returned object + */ + status = acpi_ut_get_object_size (internal_return_obj, + &buffer_space_needed); + if (ACPI_SUCCESS (status)) { + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); + if (ACPI_FAILURE (status)) { + /* + * Caller's buffer is too small or a new one can't be allocated + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Needed buffer size %X, %s\n", + (u32) buffer_space_needed, acpi_format_exception (status))); + } + else { + /* + * We have enough space for the object, build it + */ + status = acpi_ut_copy_iobject_to_eobject (internal_return_obj, + return_buffer); + } + } + } + } + } + + /* Delete the return and parameter objects */ + + if (internal_return_obj) { + /* + * Delete the internal return object. (Or at least + * decrement the reference count by one) + */ + acpi_ut_remove_reference (internal_return_obj); + } + + /* + * Free the input parameter list (if we created one), + */ + if (internal_params) { + /* Free the allocated parameter block */ + + acpi_ut_delete_internal_object_list (internal_params); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_walk_namespace + * + * PARAMETERS: Type - acpi_object_type to search for + * Start_object - Handle in namespace where search begins + * Max_depth - Depth to which search is to reach + * User_function - Called when an object of "Type" is found + * Context - Passed to user function + * Return_value - Location where return value of + * User_function is put if terminated early + * + * RETURNS Return value from the User_function if terminated early. + * Otherwise, returns NULL. + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the object specified by Start_handle. + * The User_function is called whenever an object that matches + * the type parameter is found. If the user function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * The point of this procedure is to provide a generic namespace + * walk routine that can be called from multiple places to + * provide multiple services; the User Function can be tailored + * to each task, whether it is a print function, a compare + * function, etc. + * + ******************************************************************************/ + +acpi_status +acpi_walk_namespace ( + acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + acpi_walk_callback user_function, + void *context, + void **return_value) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Acpi_walk_namespace"); + + + /* Parameter validation */ + + if ((type > ACPI_TYPE_MAX) || + (!max_depth) || + (!user_function)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Lock the namespace around the walk. + * The namespace will be unlocked/locked around each call + * to the user function - since this function + * must be allowed to make Acpi calls itself. + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK, + user_function, context, return_value); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_get_device_callback + * + * PARAMETERS: Callback from Acpi_get_device + * + * RETURN: Status + * + * DESCRIPTION: Takes callbacks from Walk_namespace and filters out all non- + * present devices, or if they specified a HID, it filters based + * on that. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_get_device_callback ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + acpi_status status; + acpi_namespace_node *node; + u32 flags; + acpi_device_id hid; + acpi_device_id cid; + acpi_get_devices_info *info; + + + info = context; + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + node = acpi_ns_map_handle_to_node (obj_handle); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + if (!node) { + return (AE_BAD_PARAMETER); + } + + /* + * Run _STA to determine if device is present + */ + status = acpi_ut_execute_STA (node, &flags); + if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + if (!(flags & 0x01)) { + /* Don't return at the device or children of the device if not there */ + return (AE_CTRL_DEPTH); + } + + /* + * Filter based on device HID & CID + */ + if (info->hid != NULL) { + status = acpi_ut_execute_HID (node, &hid); + if (status == AE_NOT_FOUND) { + return (AE_OK); + } + else if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + if (ACPI_STRNCMP (hid.buffer, info->hid, sizeof (hid.buffer)) != 0) { + status = acpi_ut_execute_CID (node, &cid); + if (status == AE_NOT_FOUND) { + return (AE_OK); + } + else if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + /* TBD: Handle CID packages */ + + if (ACPI_STRNCMP (cid.buffer, info->hid, sizeof (cid.buffer)) != 0) { + return (AE_OK); + } + } + } + + status = info->user_function (obj_handle, nesting_level, info->context, return_value); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_get_devices + * + * PARAMETERS: HID - HID to search for. Can be NULL. + * User_function - Called when a matching object is found + * Context - Passed to user function + * Return_value - Location where return value of + * User_function is put if terminated early + * + * RETURNS Return value from the User_function if terminated early. + * Otherwise, returns NULL. + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the object specified by Start_handle. + * The User_function is called whenever an object that matches + * the type parameter is found. If the user function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * This is a wrapper for Walk_namespace, but the callback performs + * additional filtering. Please see Acpi_get_device_callback. + * + ******************************************************************************/ + +acpi_status +acpi_get_devices ( + NATIVE_CHAR *HID, + acpi_walk_callback user_function, + void *context, + void **return_value) +{ + acpi_status status; + acpi_get_devices_info info; + + + ACPI_FUNCTION_TRACE ("Acpi_get_devices"); + + + /* Parameter validation */ + + if (!user_function) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * We're going to call their callback from OUR callback, so we need + * to know what it is, and their context parameter. + */ + info.context = context; + info.user_function = user_function; + info.hid = HID; + + /* + * Lock the namespace around the walk. + * The namespace will be unlocked/locked around each call + * to the user function - since this function + * must be allowed to make Acpi calls itself. + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, + ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, + acpi_ns_get_device_callback, &info, + return_value); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_attach_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_attach_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler, + void *data) +{ + acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler || + !data) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_attach_data (node, handler, data); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_detach_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_detach_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler) +{ + acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_detach_data (node, handler); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_get_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_get_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler, + void **data) +{ + acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler || + !data) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_get_attached_data (node, handler, data); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + diff -Nru a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c --- a/drivers/acpi/namespace/nsxfobj.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/namespace/nsxfobj.c Fri Jul 26 19:58:50 2002 @@ -2,7 +2,7 @@ * * Module Name: nsxfobj - Public interfaces to the ACPI subsystem * ACPI Object oriented interfaces - * $Revision: 112 $ + * $Revision: 113 $ * ******************************************************************************/ @@ -32,384 +32,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsxfobj") - -/******************************************************************************* - * - * FUNCTION: Acpi_evaluate_object_typed - * - * PARAMETERS: Handle - Object handle (optional) - * *Pathname - Object pathname (optional) - * **External_params - List of parameters to pass to method, - * terminated by NULL. May be NULL - * if no parameters are being passed. - * *Return_buffer - Where to put method's return value (if - * any). If NULL, no value is returned. - * Return_type - Expected type of return object - * - * RETURN: Status - * - * DESCRIPTION: Find and evaluate the given object, passing the given - * parameters if necessary. One of "Handle" or "Pathname" must - * be valid (non-null) - * - ******************************************************************************/ - -acpi_status -acpi_evaluate_object_typed ( - acpi_handle handle, - acpi_string pathname, - acpi_object_list *external_params, - acpi_buffer *return_buffer, - acpi_object_type return_type) -{ - acpi_status status; - u8 must_free = FALSE; - - - ACPI_FUNCTION_TRACE ("Acpi_evaluate_object_typed"); - - - /* Return buffer must be valid */ - - if (!return_buffer) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - - if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { - must_free = TRUE; - } - - /* Evaluate the object */ - - status = acpi_evaluate_object (handle, pathname, external_params, return_buffer); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - /* Type ANY means "don't care" */ - - if (return_type == ACPI_TYPE_ANY) { - return_ACPI_STATUS (AE_OK); - } - - if (return_buffer->length == 0) { - /* Error because caller specifically asked for a return value */ - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "No return value\n")); - - return_ACPI_STATUS (AE_NULL_OBJECT); - } - - /* Examine the object type returned from Evaluate_object */ - - if (((acpi_object *) return_buffer->pointer)->type == return_type) { - return_ACPI_STATUS (AE_OK); - } - - /* Return object type does not match requested type */ - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Incorrect return type [%s] requested [%s]\n", - acpi_ut_get_type_name (((acpi_object *) return_buffer->pointer)->type), - acpi_ut_get_type_name (return_type))); - - if (must_free) { - /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ - - acpi_os_free (return_buffer->pointer); - return_buffer->pointer = NULL; - } - - return_buffer->length = 0; - return_ACPI_STATUS (AE_TYPE); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_evaluate_object - * - * PARAMETERS: Handle - Object handle (optional) - * *Pathname - Object pathname (optional) - * **External_params - List of parameters to pass to method, - * terminated by NULL. May be NULL - * if no parameters are being passed. - * *Return_buffer - Where to put method's return value (if - * any). If NULL, no value is returned. - * - * RETURN: Status - * - * DESCRIPTION: Find and evaluate the given object, passing the given - * parameters if necessary. One of "Handle" or "Pathname" must - * be valid (non-null) - * - ******************************************************************************/ - -acpi_status -acpi_evaluate_object ( - acpi_handle handle, - acpi_string pathname, - acpi_object_list *external_params, - acpi_buffer *return_buffer) -{ - acpi_status status; - acpi_operand_object **internal_params = NULL; - acpi_operand_object *internal_return_obj = NULL; - ACPI_SIZE buffer_space_needed; - u32 i; - - - ACPI_FUNCTION_TRACE ("Acpi_evaluate_object"); - - - /* - * If there are parameters to be passed to the object - * (which must be a control method), the external objects - * must be converted to internal objects - */ - if (external_params && external_params->count) { - /* - * Allocate a new parameter block for the internal objects - * Add 1 to count to allow for null terminated internal list - */ - internal_params = ACPI_MEM_CALLOCATE (((ACPI_SIZE) external_params->count + 1) * - sizeof (void *)); - if (!internal_params) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* - * Convert each external object in the list to an - * internal object - */ - for (i = 0; i < external_params->count; i++) { - status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], - &internal_params[i]); - if (ACPI_FAILURE (status)) { - acpi_ut_delete_internal_object_list (internal_params); - return_ACPI_STATUS (status); - } - } - internal_params[external_params->count] = NULL; - } - - /* - * Three major cases: - * 1) Fully qualified pathname - * 2) No handle, not fully qualified pathname (error) - * 3) Valid handle - */ - if ((pathname) && - (acpi_ns_valid_root_prefix (pathname[0]))) { - /* - * The path is fully qualified, just evaluate by name - */ - status = acpi_ns_evaluate_by_name (pathname, internal_params, - &internal_return_obj); - } - else if (!handle) { - /* - * A handle is optional iff a fully qualified pathname - * is specified. Since we've already handled fully - * qualified names above, this is an error - */ - if (!pathname) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Both Handle and Pathname are NULL\n")); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Handle is NULL and Pathname is relative\n")); - } - - status = AE_BAD_PARAMETER; - } - else { - /* - * We get here if we have a handle -- and if we have a - * pathname it is relative. The handle will be validated - * in the lower procedures - */ - if (!pathname) { - /* - * The null pathname case means the handle is for - * the actual object to be evaluated - */ - status = acpi_ns_evaluate_by_handle (handle, internal_params, - &internal_return_obj); - } - else { - /* - * Both a Handle and a relative Pathname - */ - status = acpi_ns_evaluate_relative (handle, pathname, internal_params, - &internal_return_obj); - } - } - - - /* - * If we are expecting a return value, and all went well above, - * copy the return value to an external object. - */ - if (return_buffer) { - if (!internal_return_obj) { - return_buffer->length = 0; - } - else { - if (ACPI_GET_DESCRIPTOR_TYPE (internal_return_obj) == ACPI_DESC_TYPE_NAMED) { - /* - * If we received a NS Node as a return object, this means that - * the object we are evaluating has nothing interesting to - * return (such as a mutex, etc.) We return an error because - * these types are essentially unsupported by this interface. - * We don't check up front because this makes it easier to add - * support for various types at a later date if necessary. - */ - status = AE_TYPE; - internal_return_obj = NULL; /* No need to delete a NS Node */ - return_buffer->length = 0; - } - - if (ACPI_SUCCESS (status)) { - /* - * Find out how large a buffer is needed - * to contain the returned object - */ - status = acpi_ut_get_object_size (internal_return_obj, - &buffer_space_needed); - if (ACPI_SUCCESS (status)) { - /* Validate/Allocate/Clear caller buffer */ - - status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); - if (ACPI_FAILURE (status)) { - /* - * Caller's buffer is too small or a new one can't be allocated - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Needed buffer size %X, %s\n", - (u32) buffer_space_needed, acpi_format_exception (status))); - } - else { - /* - * We have enough space for the object, build it - */ - status = acpi_ut_copy_iobject_to_eobject (internal_return_obj, - return_buffer); - } - } - } - } - } - - /* Delete the return and parameter objects */ - - if (internal_return_obj) { - /* - * Delete the internal return object. (Or at least - * decrement the reference count by one) - */ - acpi_ut_remove_reference (internal_return_obj); - } - - /* - * Free the input parameter list (if we created one), - */ - if (internal_params) { - /* Free the allocated parameter block */ - - acpi_ut_delete_internal_object_list (internal_params); - } - - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_get_next_object - * - * PARAMETERS: Type - Type of object to be searched for - * Parent - Parent object whose children we are getting - * Last_child - Previous child that was found. - * The NEXT child will be returned - * Ret_handle - Where handle to the next object is placed - * - * RETURN: Status - * - * DESCRIPTION: Return the next peer object within the namespace. If Handle is - * valid, Scope is ignored. Otherwise, the first object within - * Scope is returned. - * - ******************************************************************************/ - -acpi_status -acpi_get_next_object ( - acpi_object_type type, - acpi_handle parent, - acpi_handle child, - acpi_handle *ret_handle) -{ - acpi_status status; - acpi_namespace_node *node; - acpi_namespace_node *parent_node = NULL; - acpi_namespace_node *child_node = NULL; - - - /* Parameter validation */ - - if (type > ACPI_TYPE_MAX) { - return (AE_BAD_PARAMETER); - } - - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* If null handle, use the parent */ - - if (!child) { - /* Start search at the beginning of the specified scope */ - - parent_node = acpi_ns_map_handle_to_node (parent); - if (!parent_node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - } - else { - /* Non-null handle, ignore the parent */ - /* Convert and validate the handle */ - - child_node = acpi_ns_map_handle_to_node (child); - if (!child_node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - } - - /* Internal function does the real work */ - - node = acpi_ns_get_next_node (type, parent_node, child_node); - if (!node) { - status = AE_NOT_FOUND; - goto unlock_and_exit; - } - - if (ret_handle) { - *ret_handle = acpi_ns_convert_entry_to_handle (node); - } - - -unlock_and_exit: - - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return (status); -} - - /******************************************************************************* * * FUNCTION: Acpi_get_type @@ -535,271 +157,38 @@ /******************************************************************************* * - * FUNCTION: Acpi_walk_namespace - * - * PARAMETERS: Type - acpi_object_type to search for - * Start_object - Handle in namespace where search begins - * Max_depth - Depth to which search is to reach - * User_function - Called when an object of "Type" is found - * Context - Passed to user function - * Return_value - Location where return value of - * User_function is put if terminated early - * - * RETURNS Return value from the User_function if terminated early. - * Otherwise, returns NULL. - * - * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, - * starting (and ending) at the object specified by Start_handle. - * The User_function is called whenever an object that matches - * the type parameter is found. If the user function returns - * a non-zero value, the search is terminated immediately and this - * value is returned to the caller. - * - * The point of this procedure is to provide a generic namespace - * walk routine that can be called from multiple places to - * provide multiple services; the User Function can be tailored - * to each task, whether it is a print function, a compare - * function, etc. - * - ******************************************************************************/ - -acpi_status -acpi_walk_namespace ( - acpi_object_type type, - acpi_handle start_object, - u32 max_depth, - acpi_walk_callback user_function, - void *context, - void **return_value) -{ - acpi_status status; - - - ACPI_FUNCTION_TRACE ("Acpi_walk_namespace"); - - - /* Parameter validation */ - - if ((type > ACPI_TYPE_MAX) || - (!max_depth) || - (!user_function)) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - - /* - * Lock the namespace around the walk. - * The namespace will be unlocked/locked around each call - * to the user function - since this function - * must be allowed to make Acpi calls itself. - */ - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK, - user_function, context, return_value); - - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ns_get_device_callback + * FUNCTION: Acpi_get_next_object * - * PARAMETERS: Callback from Acpi_get_device + * PARAMETERS: Type - Type of object to be searched for + * Parent - Parent object whose children we are getting + * Last_child - Previous child that was found. + * The NEXT child will be returned + * Ret_handle - Where handle to the next object is placed * * RETURN: Status * - * DESCRIPTION: Takes callbacks from Walk_namespace and filters out all non- - * present devices, or if they specified a HID, it filters based - * on that. - * - ******************************************************************************/ - -static acpi_status -acpi_ns_get_device_callback ( - acpi_handle obj_handle, - u32 nesting_level, - void *context, - void **return_value) -{ - acpi_status status; - acpi_namespace_node *node; - u32 flags; - acpi_device_id hid; - acpi_device_id cid; - acpi_get_devices_info *info; - - - info = context; - - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return (status); - } - - node = acpi_ns_map_handle_to_node (obj_handle); - status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return (status); - } - - if (!node) { - return (AE_BAD_PARAMETER); - } - - /* - * Run _STA to determine if device is present - */ - status = acpi_ut_execute_STA (node, &flags); - if (ACPI_FAILURE (status)) { - return (AE_CTRL_DEPTH); - } - - if (!(flags & 0x01)) { - /* Don't return at the device or children of the device if not there */ - return (AE_CTRL_DEPTH); - } - - /* - * Filter based on device HID & CID - */ - if (info->hid != NULL) { - status = acpi_ut_execute_HID (node, &hid); - if (status == AE_NOT_FOUND) { - return (AE_OK); - } - else if (ACPI_FAILURE (status)) { - return (AE_CTRL_DEPTH); - } - - if (ACPI_STRNCMP (hid.buffer, info->hid, sizeof (hid.buffer)) != 0) { - status = acpi_ut_execute_CID (node, &cid); - if (status == AE_NOT_FOUND) { - return (AE_OK); - } - else if (ACPI_FAILURE (status)) { - return (AE_CTRL_DEPTH); - } - - /* TBD: Handle CID packages */ - - if (ACPI_STRNCMP (cid.buffer, info->hid, sizeof (cid.buffer)) != 0) { - return (AE_OK); - } - } - } - - status = info->user_function (obj_handle, nesting_level, info->context, return_value); - return (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_get_devices - * - * PARAMETERS: HID - HID to search for. Can be NULL. - * User_function - Called when a matching object is found - * Context - Passed to user function - * Return_value - Location where return value of - * User_function is put if terminated early - * - * RETURNS Return value from the User_function if terminated early. - * Otherwise, returns NULL. - * - * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, - * starting (and ending) at the object specified by Start_handle. - * The User_function is called whenever an object that matches - * the type parameter is found. If the user function returns - * a non-zero value, the search is terminated immediately and this - * value is returned to the caller. - * - * This is a wrapper for Walk_namespace, but the callback performs - * additional filtering. Please see Acpi_get_device_callback. + * DESCRIPTION: Return the next peer object within the namespace. If Handle is + * valid, Scope is ignored. Otherwise, the first object within + * Scope is returned. * ******************************************************************************/ acpi_status -acpi_get_devices ( - NATIVE_CHAR *HID, - acpi_walk_callback user_function, - void *context, - void **return_value) +acpi_get_next_object ( + acpi_object_type type, + acpi_handle parent, + acpi_handle child, + acpi_handle *ret_handle) { acpi_status status; - acpi_get_devices_info info; - - - ACPI_FUNCTION_TRACE ("Acpi_get_devices"); - - - /* Parameter validation */ - - if (!user_function) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - - /* - * We're going to call their callback from OUR callback, so we need - * to know what it is, and their context parameter. - */ - info.context = context; - info.user_function = user_function; - info.hid = HID; - - /* - * Lock the namespace around the walk. - * The namespace will be unlocked/locked around each call - * to the user function - since this function - * must be allowed to make Acpi calls itself. - */ - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, - ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, - acpi_ns_get_device_callback, &info, - return_value); - - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_attach_data - * - * PARAMETERS: - * - * RETURN: Status - * - * DESCRIPTION: - * - ******************************************************************************/ - -acpi_status -acpi_attach_data ( - acpi_handle obj_handle, - ACPI_OBJECT_HANDLER handler, - void *data) -{ acpi_namespace_node *node; - acpi_status status; + acpi_namespace_node *parent_node = NULL; + acpi_namespace_node *child_node = NULL; /* Parameter validation */ - if (!obj_handle || - !handler || - !data) { + if (type > ACPI_TYPE_MAX) { return (AE_BAD_PARAMETER); } @@ -808,117 +197,43 @@ return (status); } - /* Convert and validate the handle */ - - node = acpi_ns_map_handle_to_node (obj_handle); - if (!node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - status = acpi_ns_attach_data (node, handler, data); - -unlock_and_exit: - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_detach_data - * - * PARAMETERS: - * - * RETURN: Status - * - * DESCRIPTION: - * - ******************************************************************************/ - -acpi_status -acpi_detach_data ( - acpi_handle obj_handle, - ACPI_OBJECT_HANDLER handler) -{ - acpi_namespace_node *node; - acpi_status status; - + /* If null handle, use the parent */ - /* Parameter validation */ + if (!child) { + /* Start search at the beginning of the specified scope */ - if (!obj_handle || - !handler) { - return (AE_BAD_PARAMETER); + parent_node = acpi_ns_map_handle_to_node (parent); + if (!parent_node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } } + else { + /* Non-null handle, ignore the parent */ + /* Convert and validate the handle */ - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return (status); + child_node = acpi_ns_map_handle_to_node (child); + if (!child_node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } } - /* Convert and validate the handle */ + /* Internal function does the real work */ - node = acpi_ns_map_handle_to_node (obj_handle); + node = acpi_ns_get_next_node (type, parent_node, child_node); if (!node) { - status = AE_BAD_PARAMETER; + status = AE_NOT_FOUND; goto unlock_and_exit; } - status = acpi_ns_detach_data (node, handler); - -unlock_and_exit: - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_get_data - * - * PARAMETERS: - * - * RETURN: Status - * - * DESCRIPTION: - * - ******************************************************************************/ - -acpi_status -acpi_get_data ( - acpi_handle obj_handle, - ACPI_OBJECT_HANDLER handler, - void **data) -{ - acpi_namespace_node *node; - acpi_status status; - - - /* Parameter validation */ - - if (!obj_handle || - !handler || - !data) { - return (AE_BAD_PARAMETER); - } - - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Convert and validate the handle */ - - node = acpi_ns_map_handle_to_node (obj_handle); - if (!node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; + if (ret_handle) { + *ret_handle = acpi_ns_convert_entry_to_handle (node); } - status = acpi_ns_get_attached_data (node, handler, data); unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); } diff -Nru a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c --- a/drivers/acpi/parser/psargs.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/parser/psargs.c Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psargs - Parse AML opcode arguments - * $Revision: 61 $ + * $Revision: 62 $ * *****************************************************************************/ @@ -332,7 +332,7 @@ NATIVE_CHAR *path; acpi_parse_object *name_op; acpi_status status; - acpi_namespace_node *method_node = NULL; + acpi_operand_object *method_desc; acpi_namespace_node *node; acpi_generic_state scope_info; @@ -369,30 +369,36 @@ &node); if (ACPI_SUCCESS (status)) { if (node->type == ACPI_TYPE_METHOD) { - method_node = node; - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "method - %p Path=%p\n", - method_node, path)); + method_desc = acpi_ns_get_attached_object (node); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Desc %p Path=%p\n", + node, method_desc, path)); name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP); - if (name_op) { - /* Change arg into a METHOD CALL and attach name to it */ + if (!name_op) { + return_VOID; + } - acpi_ps_init_op (arg, AML_INT_METHODCALL_OP); + /* Change arg into a METHOD CALL and attach name to it */ - name_op->common.value.name = path; + acpi_ps_init_op (arg, AML_INT_METHODCALL_OP); - /* Point METHODCALL/NAME to the METHOD Node */ + name_op->common.value.name = path; - name_op->common.node = method_node; - acpi_ps_append_arg (arg, name_op); + /* Point METHODCALL/NAME to the METHOD Node */ - if (!acpi_ns_get_attached_object (method_node)) { - return_VOID; - } + name_op->common.node = node; + acpi_ps_append_arg (arg, name_op); - *arg_count = (acpi_ns_get_attached_object (method_node))->method.param_count; + if (!method_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p has no attached object\n", + node)); + return_VOID; } + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Args %X\n", + node, method_desc->method.param_count)); + + *arg_count = method_desc->method.param_count; return_VOID; } diff -Nru a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c --- a/drivers/acpi/parser/psopcode.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/parser/psopcode.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psopcode - Parser/Interpreter opcode information table - * $Revision: 70 $ + * $Revision: 71 $ * *****************************************************************************/ @@ -734,7 +734,7 @@ acpi_ps_get_opcode_name ( u16 opcode) { -#ifdef ACPI_DEBUG +#ifdef ACPI_DISASSEMBLER const acpi_opcode_info *op; diff -Nru a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c --- a/drivers/acpi/parser/psparse.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/parser/psparse.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines - * $Revision: 128 $ + * $Revision: 129 $ * *****************************************************************************/ @@ -473,7 +473,7 @@ parser_state = &walk_state->parser_state; walk_state->arg_types = 0; -#ifndef PARSER_ONLY +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { /* We are restarting a preempted control method */ diff -Nru a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c --- a/drivers/acpi/parser/psutils.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/parser/psutils.c Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psutils - Parser miscellaneous utilities (Parser only) - * $Revision: 52 $ + * $Revision: 54 $ * *****************************************************************************/ @@ -88,7 +88,7 @@ op->common.data_type = ACPI_DESC_TYPE_PARSER; op->common.aml_opcode = opcode; - ACPI_DEBUG_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name, + ACPI_DISASM_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name, (acpi_ps_get_opcode_info (opcode))->name, sizeof (op->common.aml_op_name))); } @@ -186,7 +186,7 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", op)); } - if (op->common.flags == ACPI_PARSEOP_GENERIC) { + if (op->common.flags & ACPI_PARSEOP_GENERIC) { acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE, op); } else { diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c --- a/drivers/acpi/pci_irq.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/pci_irq.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 10 $) + * pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 11 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c --- a/drivers/acpi/pci_link.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/pci_link.c Fri Jul 26 19:58:50 2002 @@ -1,5 +1,5 @@ /* - * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 33 $) + * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 34 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -54,13 +54,13 @@ static int acpi_pci_link_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_pci_link_driver = { - name: ACPI_PCI_LINK_DRIVER_NAME, - class: ACPI_PCI_LINK_CLASS, - ids: ACPI_PCI_LINK_HID, - ops: { - add: acpi_pci_link_add, - remove: acpi_pci_link_remove, - }, + .name = ACPI_PCI_LINK_DRIVER_NAME, + .class = ACPI_PCI_LINK_CLASS, + .ids = ACPI_PCI_LINK_HID, + .ops = { + .add = acpi_pci_link_add, + .remove = acpi_pci_link_remove, + }, }; struct acpi_pci_link_irq { diff -Nru a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c --- a/drivers/acpi/pci_root.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/pci_root.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 39 $) + * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -47,13 +47,13 @@ static int acpi_pci_root_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_pci_root_driver = { - name: ACPI_PCI_ROOT_DRIVER_NAME, - class: ACPI_PCI_ROOT_CLASS, - ids: ACPI_PCI_ROOT_HID, - ops: { - add: acpi_pci_root_add, - remove: acpi_pci_root_remove, - }, + .name = ACPI_PCI_ROOT_DRIVER_NAME, + .class = ACPI_PCI_ROOT_CLASS, + .ids = ACPI_PCI_ROOT_HID, + .ops = { + .add = acpi_pci_root_add, + .remove = acpi_pci_root_remove, + }, }; struct acpi_pci_root { diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c --- a/drivers/acpi/power.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/power.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_power.c - ACPI Bus Power Management ($Revision: 38 $) + * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -43,13 +43,13 @@ int acpi_power_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_power_driver = { - name: ACPI_POWER_DRIVER_NAME, - class: ACPI_POWER_CLASS, - ids: ACPI_POWER_HID, - ops: { - add: acpi_power_add, - remove: acpi_power_remove, - }, + .name = ACPI_POWER_DRIVER_NAME, + .class = ACPI_POWER_CLASS, + .ids = ACPI_POWER_HID, + .ops = { + .add = acpi_power_add, + .remove = acpi_power_remove, + }, }; struct acpi_power_resource diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Fri Jul 26 19:58:52 2002 +++ b/drivers/acpi/processor.c Fri Jul 26 19:58:52 2002 @@ -1,5 +1,5 @@ /* - * acpi_processor.c - ACPI Processor Driver ($Revision: 69 $) + * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -78,13 +78,13 @@ static int acpi_processor_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_processor_driver = { - name: ACPI_PROCESSOR_DRIVER_NAME, - class: ACPI_PROCESSOR_CLASS, - ids: ACPI_PROCESSOR_HID, - ops: { - add: acpi_processor_add, - remove: acpi_processor_remove, - }, + .name = ACPI_PROCESSOR_DRIVER_NAME, + .class = ACPI_PROCESSOR_CLASS, + .ids = ACPI_PROCESSOR_HID, + .ops = { + .add = acpi_processor_add, + .remove = acpi_processor_remove, + }, }; /* Power Management */ diff -Nru a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c --- a/drivers/acpi/resources/rsio.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/resources/rsio.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: rsio - IO and DMA resource descriptors - * $Revision: 21 $ + * $Revision: 22 $ * ******************************************************************************/ @@ -399,7 +399,7 @@ buffer += 1; temp8 = *buffer; - /* Decode the IRQ bits */ + /* Decode the DMA channel bits */ for (i = 0, index = 0; index < 8; index++) { if ((temp8 >> index) & 0x01) { @@ -407,19 +407,16 @@ i++; } } - if (i == 0) { - /* Zero channels is invalid! */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found Zero DMA channels in resource list\n")); - return_ACPI_STATUS (AE_BAD_DATA); - } - output_struct->data.dma.number_of_channels = i; + /* Zero DMA channels is valid */ - - /* - * Calculate the structure size based upon the number of interrupts - */ - struct_size += ((ACPI_SIZE) output_struct->data.dma.number_of_channels - 1) * 4; + output_struct->data.dma.number_of_channels = i; + if (i > 0) { + /* + * Calculate the structure size based upon the number of interrupts + */ + struct_size += ((ACPI_SIZE) i - 1) * 4; + } /* * Point to Byte 2 diff -Nru a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c --- a/drivers/acpi/resources/rsirq.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/resources/rsirq.c Fri Jul 26 19:58:51 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: rsirq - IRQ resource descriptors - * $Revision: 29 $ + * $Revision: 30 $ * ******************************************************************************/ @@ -96,18 +96,15 @@ } } - if (i == 0) { - /* Zero interrupts is invalid! */ + /* Zero interrupts is valid */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found Zero interrupt levels in resource list\n")); - return_ACPI_STATUS (AE_BAD_DATA); - } output_struct->data.irq.number_of_interrupts = i; - - /* - * Calculate the structure size based upon the number of interrupts - */ - struct_size += ((ACPI_SIZE) output_struct->data.irq.number_of_interrupts - 1) * 4; + if (i > 0) { + /* + * Calculate the structure size based upon the number of interrupts + */ + struct_size += ((ACPI_SIZE) i - 1) * 4; + } /* * Point to Byte 3 if it is used diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c --- a/drivers/acpi/system.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/system.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_system.c - ACPI System Driver ($Revision: 60 $) + * acpi_system.c - ACPI System Driver ($Revision: 63 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -63,13 +63,13 @@ static int acpi_system_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_system_driver = { - name: ACPI_SYSTEM_DRIVER_NAME, - class: ACPI_SYSTEM_CLASS, - ids: ACPI_SYSTEM_HID, - ops: { - add: acpi_system_add, - remove: acpi_system_remove - }, + .name = ACPI_SYSTEM_DRIVER_NAME, + .class = ACPI_SYSTEM_CLASS, + .ids = ACPI_SYSTEM_HID, + .ops = { + .add = acpi_system_add, + .remove = acpi_system_remove + }, }; struct acpi_system @@ -383,10 +383,10 @@ static struct file_operations acpi_system_event_ops = { - open: acpi_system_open_event, - read: acpi_system_read_event, - release: acpi_system_close_event, - poll: acpi_system_poll_event, + .open = acpi_system_open_event, + .read = acpi_system_read_event, + .release = acpi_system_close_event, + .poll = acpi_system_poll_event, }; static int @@ -479,7 +479,7 @@ static ssize_t acpi_system_read_dsdt (struct file*, char*, size_t, loff_t*); static struct file_operations acpi_system_dsdt_ops = { - read: acpi_system_read_dsdt, + .read = acpi_system_read_dsdt, }; static ssize_t @@ -522,7 +522,7 @@ static ssize_t acpi_system_read_fadt (struct file*, char*, size_t, loff_t*); static struct file_operations acpi_system_fadt_ops = { - read: acpi_system_read_fadt, + .read = acpi_system_read_fadt, }; static ssize_t @@ -1165,15 +1165,15 @@ /* Simple wrapper calling power down function. */ static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) + struct tty_struct *tty) { acpi_power_off(); } struct sysrq_key_op sysrq_acpi_poweroff_op = { - handler: &acpi_sysrq_power_off, - help_msg: "Off", - action_msg: "Power Off\n" + .handler = &acpi_sysrq_power_off, + .help_msg = "Off", + .action_msg = "Power Off\n" }; #endif /* CONFIG_MAGIC_SYSRQ */ diff -Nru a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c --- a/drivers/acpi/tables/tbrsdt.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/tables/tbrsdt.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: tbrsdt - ACPI RSDT table utilities - * $Revision: 1 $ + * $Revision: 2 $ * *****************************************************************************/ @@ -270,12 +270,6 @@ if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - - /* - * Valid RSDT signature, verify the checksum. If it fails, just - * print a warning and ignore it. - */ - status = acpi_tb_verify_table_checksum (table_info.pointer); /* Get the number of tables defined in the RSDT or XSDT */ diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/tables.c Fri Jul 26 19:58:51 2002 @@ -330,6 +330,11 @@ return -ENODEV; } + if (acpi_table_compute_checksum(header, header->length)) { + printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n"); + return -ENODEV; + } + sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3; if (sdt.count > ACPI_MAX_TABLES) { printk(KERN_WARNING PREFIX "Truncated %lu XSDT entries\n", @@ -367,6 +372,11 @@ if (strncmp(header->signature, "RSDT", 4)) { printk(KERN_WARNING PREFIX "RSDT signature incorrect\n"); + return -ENODEV; + } + + if (acpi_table_compute_checksum(header, header->length)) { + printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n"); return -ENODEV; } diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c --- a/drivers/acpi/thermal.c Fri Jul 26 19:58:51 2002 +++ b/drivers/acpi/thermal.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 40 $) + * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -65,13 +65,13 @@ static int acpi_thermal_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_thermal_driver = { - name: ACPI_THERMAL_DRIVER_NAME, - class: ACPI_THERMAL_CLASS, - ids: ACPI_THERMAL_HID, - ops: { - add: acpi_thermal_add, - remove: acpi_thermal_remove, - }, + .name = ACPI_THERMAL_DRIVER_NAME, + .class = ACPI_THERMAL_CLASS, + .ids = ACPI_THERMAL_HID, + .ops = { + .add = acpi_thermal_add, + .remove = acpi_thermal_remove, + }, }; struct acpi_thermal_state { diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c Fri Jul 26 19:58:50 2002 +++ b/drivers/acpi/utilities/utglobal.c Fri Jul 26 19:58:50 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: utglobal - Global variables for the ACPI subsystem - * $Revision: 164 $ + * $Revision: 165 $ * *****************************************************************************/ @@ -27,6 +27,7 @@ #include "acpi.h" #include "acnamesp.h" +#include "amlcode.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utglobal") @@ -357,15 +358,15 @@ /* Region type decoding */ -static const NATIVE_CHAR *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = +const NATIVE_CHAR *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "System_memory", "System_iO", - "PCIConfig", + "PCI_Config", "Embedded_control", "SMBus", "CMOS", - "PCIBar_target", + "PCIBARTarget", "Data_table", }; @@ -554,55 +555,6 @@ return (acpi_gbl_mutex_names[mutex_id]); } - -/* Various strings for future use */ - -#if 0 -#include "amlcode.h" - -/* Data used in keeping track of fields */ - -static const NATIVE_CHAR *acpi_gbl_FEnames[NUM_FIELD_NAMES] = -{ - "skip", - "?access?" -}; /* FE = Field Element */ - - -static const NATIVE_CHAR *acpi_gbl_match_ops[NUM_MATCH_OPS] = -{ - "Error", - "MTR", - "MEQ", - "MLE", - "MLT", - "MGE", - "MGT" -}; - - -/* Access type decoding */ - -static const NATIVE_CHAR *acpi_gbl_access_types[NUM_ACCESS_TYPES] = -{ - "Any_acc", - "Byte_acc", - "Word_acc", - "DWord_acc", - "QWord_acc", - "Buffer_acc", -}; - - -/* Update rule decoding */ - -static const NATIVE_CHAR *acpi_gbl_update_rules[NUM_UPDATE_RULES] = -{ - "Preserve", - "Write_as_ones", - "Write_as_zeros" -}; -#endif /* Future use */ #endif diff -Nru a/drivers/base/fs.c b/drivers/base/fs.c --- a/drivers/base/fs.c Fri Jul 26 19:58:51 2002 +++ b/drivers/base/fs.c Fri Jul 26 19:58:51 2002 @@ -106,13 +106,17 @@ static int create_symlink(struct driver_dir_entry * parent, char * name, char * path) { struct driver_file_entry * entry; + int error; entry = kmalloc(sizeof(struct driver_file_entry),GFP_KERNEL); if (!entry) return -ENOMEM; entry->name = name; entry->mode = S_IRUGO; - return driverfs_create_symlink(parent,entry,path); + error = driverfs_create_symlink(parent,entry,path); + if (error) + kfree(entry); + return error; } int device_bus_link(struct device * dev) diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c Fri Jul 26 19:58:52 2002 +++ b/drivers/block/DAC960.c Fri Jul 26 19:58:52 2002 @@ -2884,7 +2884,7 @@ Command->BufferHeader = Request->bio; Command->RequestBuffer = Request->buffer; blkdev_dequeue_request(Request); - blkdev_release_request(Request); + blk_put_request(Request); DAC960_QueueReadWriteCommand(Command); return true; } diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c --- a/drivers/block/genhd.c Fri Jul 26 19:58:51 2002 +++ b/drivers/block/genhd.c Fri Jul 26 19:58:51 2002 @@ -177,16 +177,12 @@ extern int blk_dev_init(void); extern int soc_probe(void); extern int atmdev_init(void); -extern int i2o_init(void); extern int cpqarray_init(void); int __init device_init(void) { rwlock_init(&gendisk_lock); blk_dev_init(); -#ifdef CONFIG_I2O - i2o_init(); -#endif #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Fri Jul 26 19:58:50 2002 +++ b/drivers/block/ll_rw_blk.c Fri Jul 26 19:58:50 2002 @@ -1233,9 +1233,47 @@ return rq; } -void blk_put_request(struct request *rq) +/** + * blk_insert_request - insert a special request in to a request queue + * @q: request queue where request should be inserted + * @rq: request to be inserted + * @at_head: insert request at head or tail of queue + * @data: private data + * + * Description: + * Many block devices need to execute commands asynchronously, so they don't + * block the whole kernel from preemption during request execution. This is + * accomplished normally by inserting aritficial requests tagged as + * REQ_SPECIAL in to the corresponding request queue, and letting them be + * scheduled for actual execution by the request queue. + * + * We have the option of inserting the head or the tail of the queue. + * Typically we use the tail for new ioctls and so forth. We use the head + * of the queue for things like a QUEUE_FULL message from a device, or a + * host that is unable to accept a particular command. + */ +void blk_insert_request(request_queue_t *q, struct request *rq, + int at_head, void *data) { - blkdev_release_request(rq); + unsigned long flags; + + /* + * tell I/O scheduler that this isn't a regular read/write (ie it + * must not attempt merges on this) and that it acts as a soft + * barrier + */ + rq->flags &= REQ_QUEUED; + rq->flags |= REQ_SPECIAL | REQ_BARRIER; + + rq->special = data; + + spin_lock_irqsave(q->queue_lock, flags); + /* If command is tagged, release the tag */ + if(blk_rq_tagged(rq)) + blk_queue_end_tag(q, rq); + _elv_add_request(q, rq, !at_head, 0); + q->request_fn(q); + spin_unlock_irqrestore(q->queue_lock, flags); } /* RO fail safe mechanism */ @@ -1307,7 +1345,7 @@ /* * Must be called with queue lock held and interrupts disabled */ -void blkdev_release_request(struct request *req) +void blk_put_request(struct request *req) { struct request_list *rl = req->rl; request_queue_t *q = req->q; @@ -1370,7 +1408,7 @@ req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; - blkdev_release_request(next); + blk_put_request(next); } } @@ -1568,7 +1606,7 @@ add_request(q, req, insert_here); out: if (freereq) - blkdev_release_request(freereq); + blk_put_request(freereq); spin_unlock_irq(q->queue_lock); return 0; @@ -2003,7 +2041,7 @@ if (req->waiting) complete(req->waiting); - blkdev_release_request(req); + blk_put_request(req); } #define MB(kb) ((kb) << 10) @@ -2064,7 +2102,6 @@ EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(blk_queue_bounce_limit); EXPORT_SYMBOL(generic_make_request); -EXPORT_SYMBOL(blkdev_release_request); EXPORT_SYMBOL(generic_unplug_device); EXPORT_SYMBOL(blk_plug_device); EXPORT_SYMBOL(blk_remove_plug); @@ -2088,6 +2125,7 @@ EXPORT_SYMBOL(blk_get_request); EXPORT_SYMBOL(__blk_get_request); EXPORT_SYMBOL(blk_put_request); +EXPORT_SYMBOL(blk_insert_request); EXPORT_SYMBOL(blk_queue_prep_rq); diff -Nru a/drivers/block/paride/ppc6lnx.c b/drivers/block/paride/ppc6lnx.c --- a/drivers/block/paride/ppc6lnx.c Fri Jul 26 19:58:50 2002 +++ b/drivers/block/paride/ppc6lnx.c Fri Jul 26 19:58:50 2002 @@ -724,4 +724,3 @@ //*************************************************************************** -MODULE_LICENSE("GPL"); diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c --- a/drivers/block/umem.c Fri Jul 26 19:58:52 2002 +++ b/drivers/block/umem.c Fri Jul 26 19:58:52 2002 @@ -819,7 +819,7 @@ static int mm_revalidate(kdev_t i_rdev) { int card_number = DEVICE_NR(i_rdev); - kdev_t device = mk_mdev(MAJOR_NR, card_number << MM_SHIFT); + kdev_t device = mk_kdev(MAJOR_NR, card_number << MM_SHIFT); int res = dev_lock_part(device); if (res < 0) return res; @@ -862,7 +862,7 @@ size = cards[card_number].mm_size * (1024 / MM_HARDSECT); geo.heads = 64; geo.sectors = 32; - geo.start = get_start_sect(inode->i_bdev); + geo.start = get_start_sect(i->i_bdev); geo.cylinders = size / (geo.heads * geo.sectors); if (copy_to_user((void *) arg, &geo, sizeof(geo))) diff -Nru a/drivers/char/epca.h b/drivers/char/epca.h --- a/drivers/char/epca.h Fri Jul 26 19:58:51 2002 +++ b/drivers/char/epca.h Fri Jul 26 19:58:51 2002 @@ -121,7 +121,7 @@ int close_delay; int count; int blocked_open; - int event; + ulong event; int asyncflags; uint dev; long session; diff -Nru a/drivers/char/serial_21285.c b/drivers/char/serial_21285.c --- a/drivers/char/serial_21285.c Fri Jul 26 19:58:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,497 +0,0 @@ -/* - * linux/drivers/char/serial_21285.c - * - * Driver for the serial port on the 21285 StrongArm-110 core logic chip. - * - * Based on drivers/char/serial.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define BAUD_BASE (mem_fclk_21285/64) - -#define SERIAL_21285_NAME "ttyFB" -#define SERIAL_21285_MAJOR 204 -#define SERIAL_21285_MINOR 4 - -#define SERIAL_21285_AUXNAME "cuafb" -#define SERIAL_21285_AUXMAJOR 205 -#define SERIAL_21285_AUXMINOR 4 - -static struct tty_driver rs285_driver, callout_driver; -static int rs285_refcount; -static struct tty_struct *rs285_table[1]; - -static struct termios *rs285_termios[1]; -static struct termios *rs285_termios_locked[1]; - -static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; -static struct tty_struct *rs285_tty; -static int rs285_use_count; - -static int rs285_write_room(struct tty_struct *tty) -{ - return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1); -} - -static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs) -{ - if (!rs285_tty) { - disable_irq(IRQ_CONRX); - return; - } - while (!(*CSR_UARTFLG & 0x10)) { - int ch, flag; - ch = *CSR_UARTDR; - flag = *CSR_RXSTAT; - if (flag & 4) - tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN); - if (flag & 2) - flag = TTY_PARITY; - else if (flag & 1) - flag = TTY_FRAME; - tty_insert_flip_char(rs285_tty, ch, flag); - } - tty_flip_buffer_push(rs285_tty); -} - -static void rs285_send_xchar(struct tty_struct *tty, char ch) -{ - x_char = ch; - enable_irq(IRQ_CONTX); -} - -static void rs285_throttle(struct tty_struct *tty) -{ - if (I_IXOFF(tty)) - rs285_send_xchar(tty, STOP_CHAR(tty)); -} - -static void rs285_unthrottle(struct tty_struct *tty) -{ - if (I_IXOFF(tty)) { - if (x_char) - x_char = 0; - else - rs285_send_xchar(tty, START_CHAR(tty)); - } -} - -static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs) -{ - while (!(*CSR_UARTFLG & 0x20)) { - if (x_char) { - *CSR_UARTDR = x_char; - x_char = 0; - continue; - } - if (putp == getp) { - disable_irq(IRQ_CONTX); - break; - } - *CSR_UARTDR = *getp; - if (++getp >= wbuf + sizeof(wbuf)) - getp = wbuf; - } - if (rs285_tty) - wake_up_interruptible(&rs285_tty->write_wait); -} - -static inline int rs285_xmit(int ch) -{ - if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf)) - return 0; - *putp = ch; - if (++putp >= wbuf + sizeof(wbuf)) - putp = wbuf; - enable_irq(IRQ_CONTX); - return 1; -} - -static int rs285_write(struct tty_struct *tty, int from_user, - const u_char * buf, int count) -{ - int i; - - if (from_user && verify_area(VERIFY_READ, buf, count)) - return -EINVAL; - - for (i = 0; i < count; i++) { - char ch; - if (from_user) - __get_user(ch, buf + i); - else - ch = buf[i]; - if (!rs285_xmit(ch)) - break; - } - return i; -} - -static void rs285_put_char(struct tty_struct *tty, u_char ch) -{ - rs285_xmit(ch); -} - -static int rs285_chars_in_buffer(struct tty_struct *tty) -{ - return sizeof(wbuf) - rs285_write_room(tty); -} - -static void rs285_flush_buffer(struct tty_struct *tty) -{ - disable_irq(IRQ_CONTX); - putp = getp = wbuf; - if (x_char) - enable_irq(IRQ_CONTX); -} - -static inline void rs285_set_cflag(int cflag) -{ - int h_lcr, baud, quot; - - switch (cflag & CSIZE) { - case CS5: - h_lcr = 0x10; - break; - case CS6: - h_lcr = 0x30; - break; - case CS7: - h_lcr = 0x50; - break; - default: /* CS8 */ - h_lcr = 0x70; - break; - - } - if (cflag & CSTOPB) - h_lcr |= 0x08; - if (cflag & PARENB) - h_lcr |= 0x02; - if (!(cflag & PARODD)) - h_lcr |= 0x04; - - switch (cflag & CBAUD) { - case B200: baud = 200; break; - case B300: baud = 300; break; - case B1200: baud = 1200; break; - case B1800: baud = 1800; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - default: - case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - case B57600: baud = 57600; break; - case B115200: baud = 115200; break; - } - - /* - * The documented expression for selecting the divisor is: - * BAUD_BASE / baud - 1 - * However, typically BAUD_BASE is not divisible by baud, so - * we want to select the divisor that gives us the minimum - * error. Therefore, we want: - * int(BAUD_BASE / baud - 0.5) -> - * int(BAUD_BASE / baud - (baud >> 1) / baud) -> - * int((BAUD_BASE - (baud >> 1)) / baud) - */ - quot = (BAUD_BASE - (baud >> 1)) / baud; - - *CSR_UARTCON = 0; - *CSR_L_UBRLCR = quot & 0xff; - *CSR_M_UBRLCR = (quot >> 8) & 0x0f; - *CSR_H_UBRLCR = h_lcr; - *CSR_UARTCON = 1; -} - -static void rs285_set_termios(struct tty_struct *tty, struct termios *old) -{ - if (old && tty->termios->c_cflag == old->c_cflag) - return; - rs285_set_cflag(tty->termios->c_cflag); -} - - -static void rs285_stop(struct tty_struct *tty) -{ - disable_irq(IRQ_CONTX); -} - -static void rs285_start(struct tty_struct *tty) -{ - enable_irq(IRQ_CONTX); -} - -static void rs285_wait_until_sent(struct tty_struct *tty, int timeout) -{ - int orig_jiffies = jiffies; - while (*CSR_UARTFLG & 8) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - current->state = TASK_RUNNING; -} - -static int rs285_open(struct tty_struct *tty, struct file *filp) -{ - int line; - - MOD_INC_USE_COUNT; - line = minor(tty->device) - tty->driver.minor_start; - if (line) { - MOD_DEC_USE_COUNT; - return -ENODEV; - } - - tty->driver_data = NULL; - if (!rs285_tty) - rs285_tty = tty; - - enable_irq(IRQ_CONRX); - rs285_use_count++; - return 0; -} - -static void rs285_close(struct tty_struct *tty, struct file *filp) -{ - if (!--rs285_use_count) { - rs285_wait_until_sent(tty, 0); - disable_irq(IRQ_CONRX); - disable_irq(IRQ_CONTX); - rs285_tty = NULL; - } - MOD_DEC_USE_COUNT; -} - -static int __init rs285_init(void) -{ - int baud = B9600; - - if (machine_is_personal_server()) - baud = B57600; - - rs285_driver.magic = TTY_DRIVER_MAGIC; - rs285_driver.driver_name = "serial_21285"; - rs285_driver.name = SERIAL_21285_NAME; - rs285_driver.major = SERIAL_21285_MAJOR; - rs285_driver.minor_start = SERIAL_21285_MINOR; - rs285_driver.num = 1; - rs285_driver.type = TTY_DRIVER_TYPE_SERIAL; - rs285_driver.subtype = SERIAL_TYPE_NORMAL; - rs285_driver.init_termios = tty_std_termios; - rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL; - rs285_driver.flags = TTY_DRIVER_REAL_RAW; - rs285_driver.refcount = &rs285_refcount; - rs285_driver.table = rs285_table; - rs285_driver.termios = rs285_termios; - rs285_driver.termios_locked = rs285_termios_locked; - - rs285_driver.open = rs285_open; - rs285_driver.close = rs285_close; - rs285_driver.write = rs285_write; - rs285_driver.put_char = rs285_put_char; - rs285_driver.write_room = rs285_write_room; - rs285_driver.chars_in_buffer = rs285_chars_in_buffer; - rs285_driver.flush_buffer = rs285_flush_buffer; - rs285_driver.throttle = rs285_throttle; - rs285_driver.unthrottle = rs285_unthrottle; - rs285_driver.send_xchar = rs285_send_xchar; - rs285_driver.set_termios = rs285_set_termios; - rs285_driver.stop = rs285_stop; - rs285_driver.start = rs285_start; - rs285_driver.wait_until_sent = rs285_wait_until_sent; - - callout_driver = rs285_driver; - callout_driver.name = SERIAL_21285_AUXNAME; - callout_driver.major = SERIAL_21285_AUXMAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - - if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL)) - panic("Couldn't get rx irq for rs285"); - - if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL)) - panic("Couldn't get tx irq for rs285"); - - if (tty_register_driver(&rs285_driver)) - printk(KERN_ERR "Couldn't register 21285 serial driver\n"); - if (tty_register_driver(&callout_driver)) - printk(KERN_ERR "Couldn't register 21285 callout driver\n"); - - return 0; -} - -static void __exit rs285_fini(void) -{ - unsigned long flags; - int ret; - - save_flags(flags); - cli(); - ret = tty_unregister_driver(&callout_driver); - if (ret) - printk(KERN_ERR "Unable to unregister 21285 callout driver " - "(%d)\n", ret); - ret = tty_unregister_driver(&rs285_driver); - if (ret) - printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n", - ret); - free_irq(IRQ_CONTX, NULL); - free_irq(IRQ_CONRX, NULL); - restore_flags(flags); -} - -module_init(rs285_init); -module_exit(rs285_fini); - -#ifdef CONFIG_SERIAL_21285_CONSOLE -/************** console driver *****************/ - -static void rs285_console_write(struct console *co, const char *s, u_int count) -{ - int i; - - disable_irq(IRQ_CONTX); - for (i = 0; i < count; i++) { - while (*CSR_UARTFLG & 0x20); - *CSR_UARTDR = s[i]; - if (s[i] == '\n') { - while (*CSR_UARTFLG & 0x20); - *CSR_UARTDR = '\r'; - } - } - enable_irq(IRQ_CONTX); -} - -static kdev_t rs285_console_device(struct console *c) -{ - return mk_kdev(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); -} - -static int __init rs285_console_setup(struct console *co, char *options) -{ - int baud = 9600; - int bits = 8; - int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; - - if (machine_is_personal_server()) - baud = 57600; - - if (options) { - char *s = options; - baud = simple_strtoul(options, NULL, 10); - while (*s >= '0' && *s <= '9') - s++; - if (*s) - parity = *s++; - if (*s) - bits = *s - '0'; - } - - /* - * Now construct a cflag setting. - */ - switch (baud) { - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - case 9600: - cflag |= B9600; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - default: - cflag |= B9600; - break; - } - switch (bits) { - case 7: - cflag |= CS7; - break; - default: - cflag |= CS8; - break; - } - switch (parity) { - case 'o': - case 'O': - cflag |= PARODD; - break; - case 'e': - case 'E': - cflag |= PARENB; - break; - } - co->cflag = cflag; - rs285_set_cflag(cflag); - rs285_console_write(NULL, "\e[2J\e[Hboot ", 12); - if (options) - rs285_console_write(NULL, options, strlen(options)); - else - rs285_console_write(NULL, "no options", 10); - rs285_console_write(NULL, "\n", 1); - - return 0; -} - -static struct console rs285_cons = -{ - name: SERIAL_21285_NAME, - write: rs285_console_write, - device: rs285_console_device, - setup: rs285_console_setup, - flags: CON_PRINTBUFFER, - index: -1, -}; - -void __init rs285_console_init(void) -{ - register_console(&rs285_cons); -} - -#endif /* CONFIG_SERIAL_21285_CONSOLE */ - -MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/serial_amba.c b/drivers/char/serial_amba.c --- a/drivers/char/serial_amba.c Fri Jul 26 19:58:50 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2014 +0,0 @@ -/* - * linux/drivers/char/serial_amba.c - * - * Driver for AMBA serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * 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 - * - * - * This is a generic driver for ARM AMBA-type serial ports. They - * have a lot of 16550-like features, but are not register compatable. - * Note that although they do have CTS, DCD and DSR inputs, they do - * not have an RI input, nor do they have DTR or RTS outputs. If - * required, these have to be supplied via some other means (eg, GPIO) - * and hooked into this driver. - * - * This could very easily become a generic serial driver for dumb UARTs - * (eg, {82,16x}50, 21285, SA1100). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define SERIAL_AMBA_NAME "ttyAM" -#define SERIAL_AMBA_MAJOR 204 -#define SERIAL_AMBA_MINOR 16 -#define SERIAL_AMBA_NR 2 - -#define CALLOUT_AMBA_NAME "cuaam" -#define CALLOUT_AMBA_MAJOR 205 -#define CALLOUT_AMBA_MINOR 16 -#define CALLOUT_AMBA_NR SERIAL_AMBA_NR - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define DEBUG 0 -#define DEBUG_LEDS 0 - -#if DEBUG_LEDS -extern int get_leds(void); -extern int set_leds(int); -#endif - -/* - * Access routines for the AMBA UARTs - */ -#define UART_GET_INT_STATUS(p) IO_READ((p)->uart_base + AMBA_UARTIIR) -#define UART_GET_FR(p) IO_READ((p)->uart_base + AMBA_UARTFR) -#define UART_GET_CHAR(p) IO_READ((p)->uart_base + AMBA_UARTDR) -#define UART_PUT_CHAR(p, c) IO_WRITE((p)->uart_base + AMBA_UARTDR, (c)) -#define UART_GET_RSR(p) IO_READ((p)->uart_base + AMBA_UARTRSR) -#define UART_GET_CR(p) IO_READ((p)->uart_base + AMBA_UARTCR) -#define UART_PUT_CR(p,c) IO_WRITE((p)->uart_base + AMBA_UARTCR, (c)) -#define UART_GET_LCRL(p) IO_READ((p)->uart_base + AMBA_UARTLCR_L) -#define UART_PUT_LCRL(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_L, (c)) -#define UART_GET_LCRM(p) IO_READ((p)->uart_base + AMBA_UARTLCR_M) -#define UART_PUT_LCRM(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_M, (c)) -#define UART_GET_LCRH(p) IO_READ((p)->uart_base + AMBA_UARTLCR_H) -#define UART_PUT_LCRH(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_H, (c)) -#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0) -#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0) -#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0) - -#define AMBA_UARTRSR_ANY (AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE) -#define AMBA_UARTFR_MODEM_ANY (AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS) - -/* - * Things needed by tty driver - */ -static struct tty_driver ambanormal_driver, ambacallout_driver; -static int ambauart_refcount; -static struct tty_struct *ambauart_table[SERIAL_AMBA_NR]; -static struct termios *ambauart_termios[SERIAL_AMBA_NR]; -static struct termios *ambauart_termios_locked[SERIAL_AMBA_NR]; - -#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -/* - * Things needed internally to this driver - */ - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static u_char *tmp_buf; -static DECLARE_MUTEX(tmp_buf_sem); - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 -#define AMBA_ISR_PASS_LIMIT 256 - -#define EVT_WRITE_WAKEUP 0 - -struct amba_icount { - __u32 cts; - __u32 dsr; - __u32 rng; - __u32 dcd; - __u32 rx; - __u32 tx; - __u32 frame; - __u32 overrun; - __u32 parity; - __u32 brk; - __u32 buf_overrun; -}; - -/* - * Static information about the port - */ -struct amba_port { - unsigned int uart_base; - unsigned int irq; - unsigned int uartclk; - unsigned int fifosize; - unsigned int tiocm_support; - void (*set_mctrl)(struct amba_port *, u_int mctrl); -}; - -/* - * This is the state information which is persistent across opens - */ -struct amba_state { - struct amba_icount icount; - unsigned int line; - unsigned int close_delay; - unsigned int closing_wait; - unsigned int custom_divisor; - unsigned int flags; - struct termios normal_termios; - struct termios callout_termios; - - int count; - struct amba_info *info; -}; - -#define AMBA_XMIT_SIZE 1024 -/* - * This is the state information which is only valid when the port is open. - */ -struct amba_info { - struct amba_port *port; - struct amba_state *state; - struct tty_struct *tty; - unsigned char x_char; - unsigned char old_status; - unsigned char read_status_mask; - unsigned char ignore_status_mask; - struct circ_buf xmit; - unsigned int flags; -#ifdef SUPPORT_SYSRQ - unsigned long sysrq; -#endif - - unsigned int event; - unsigned int timeout; - unsigned int lcr_h; - unsigned int mctrl; - int blocked_open; - pid_t session; - pid_t pgrp; - - struct tasklet_struct tlet; - - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - wait_queue_head_t delta_msr_wait; -}; - -#ifdef CONFIG_SERIAL_AMBA_CONSOLE -static struct console ambauart_cons; -#endif -static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios); -static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout); - -#if 1 //def CONFIG_SERIAL_INTEGRATOR -static void amba_set_mctrl_null(struct amba_port *port, u_int mctrl) -{ -} - -static struct amba_port amba_ports[SERIAL_AMBA_NR] = { - { - uart_base: IO_ADDRESS(INTEGRATOR_UART0_BASE), - irq: IRQ_UARTINT0, - uartclk: 14745600, - fifosize: 8, - set_mctrl: amba_set_mctrl_null, - }, - { - uart_base: IO_ADDRESS(INTEGRATOR_UART1_BASE), - irq: IRQ_UARTINT1, - uartclk: 14745600, - fifosize: 8, - set_mctrl: amba_set_mctrl_null, - } -}; -#endif - -static struct amba_state amba_state[SERIAL_AMBA_NR]; - -static void ambauart_enable_rx_interrupt(struct amba_info *info) -{ - unsigned int cr; - - cr = UART_GET_CR(info->port); - cr |= AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE; - UART_PUT_CR(info->port, cr); -} - -static void ambauart_disable_rx_interrupt(struct amba_info *info) -{ - unsigned int cr; - - cr = UART_GET_CR(info->port); - cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); - UART_PUT_CR(info->port, cr); -} - -static void ambauart_enable_tx_interrupt(struct amba_info *info) -{ - unsigned int cr; - - cr = UART_GET_CR(info->port); - cr |= AMBA_UARTCR_TIE; - UART_PUT_CR(info->port, cr); -} - -static void ambauart_disable_tx_interrupt(struct amba_info *info) -{ - unsigned int cr; - - cr = UART_GET_CR(info->port); - cr &= ~AMBA_UARTCR_TIE; - UART_PUT_CR(info->port, cr); -} - -static void ambauart_stop(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - - save_flags(flags); cli(); - ambauart_disable_tx_interrupt(info); - restore_flags(flags); -} - -static void ambauart_start(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - - save_flags(flags); cli(); - if (info->xmit.head != info->xmit.tail - && info->xmit.buf) - ambauart_enable_tx_interrupt(info); - restore_flags(flags); -} - - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static void ambauart_event(struct amba_info *info, int event) -{ - info->event |= 1 << event; - tasklet_schedule(&info->tlet); -} - -static void -#ifdef SUPPORT_SYSRQ -ambauart_rx_chars(struct amba_info *info, struct pt_regs *regs) -#else -ambauart_rx_chars(struct amba_info *info) -#endif -{ - struct tty_struct *tty = info->tty; - unsigned int status, ch, rsr, flg, ignored = 0; - struct amba_icount *icount = &info->state->icount; - struct amba_port *port = info->port; - - status = UART_GET_FR(port); - while (UART_RX_DATA(status)) { - ch = UART_GET_CHAR(port); - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; - icount->rx++; - - flg = TTY_NORMAL; - - /* - * Note that the error handling code is - * out of the main execution path - */ - rsr = UART_GET_RSR(port); - if (rsr & AMBA_UARTRSR_ANY) - goto handle_error; -#ifdef SUPPORT_SYSRQ - if (info->sysrq) { - if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL, NULL); - info->sysrq = 0; - goto ignore_char; - } - info->sysrq = 0; - } -#endif - error_return: - *tty->flip.flag_buf_ptr++ = flg; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - ignore_char: - status = UART_GET_FR(port); - } -out: - tty_flip_buffer_push(tty); - return; - -handle_error: - if (rsr & AMBA_UARTRSR_BE) { - rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE); - icount->brk++; - -#ifdef SUPPORT_SYSRQ - if (info->state->line == ambauart_cons.index) { - if (!info->sysrq) { - info->sysrq = jiffies + HZ*5; - goto ignore_char; - } - } -#endif - } else if (rsr & AMBA_UARTRSR_PE) - icount->parity++; - else if (rsr & AMBA_UARTRSR_FE) - icount->frame++; - if (rsr & AMBA_UARTRSR_OE) - icount->overrun++; - - if (rsr & info->ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - rsr &= info->read_status_mask; - - if (rsr & AMBA_UARTRSR_BE) - flg = TTY_BREAK; - else if (rsr & AMBA_UARTRSR_PE) - flg = TTY_PARITY; - else if (rsr & AMBA_UARTRSR_FE) - flg = TTY_FRAME; - - if (rsr & AMBA_UARTRSR_OE) { - /* - * CHECK: does overrun affect the current character? - * ASSUMPTION: it does not. - */ - *tty->flip.flag_buf_ptr++ = flg; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; - ch = 0; - flg = TTY_OVERRUN; - } -#ifdef SUPPORT_SYSRQ - info->sysrq = 0; -#endif - goto error_return; -} - -static void ambauart_tx_chars(struct amba_info *info) -{ - struct amba_port *port = info->port; - int count; - - if (info->x_char) { - UART_PUT_CHAR(port, info->x_char); - info->state->icount.tx++; - info->x_char = 0; - return; - } - if (info->xmit.head == info->xmit.tail - || info->tty->stopped - || info->tty->hw_stopped) { - ambauart_disable_tx_interrupt(info); - return; - } - - count = port->fifosize; - do { - UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]); - info->xmit.tail = (info->xmit.tail + 1) & (AMBA_XMIT_SIZE - 1); - info->state->icount.tx++; - if (info->xmit.head == info->xmit.tail) - break; - } while (--count > 0); - - if (CIRC_CNT(info->xmit.head, - info->xmit.tail, - AMBA_XMIT_SIZE) < WAKEUP_CHARS) - ambauart_event(info, EVT_WRITE_WAKEUP); - - if (info->xmit.head == info->xmit.tail) { - ambauart_disable_tx_interrupt(info); - } -} - -static void ambauart_modem_status(struct amba_info *info) -{ - unsigned int status, delta; - struct amba_icount *icount = &info->state->icount; - - status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; - - delta = status ^ info->old_status; - info->old_status = status; - - if (!delta) - return; - - if (delta & AMBA_UARTFR_DCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & AMBA_UARTFR_DCD) - hardpps(); -#endif - if (info->flags & ASYNC_CHECK_CD) { - if (status & AMBA_UARTFR_DCD) - wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { - if (info->tty) - tty_hangup(info->tty); - } - } - } - - if (delta & AMBA_UARTFR_DSR) - icount->dsr++; - - if (delta & AMBA_UARTFR_CTS) { - icount->cts++; - - if (info->flags & ASYNC_CTS_FLOW) { - status &= AMBA_UARTFR_CTS; - - if (info->tty->hw_stopped) { - if (status) { - info->tty->hw_stopped = 0; - ambauart_enable_tx_interrupt(info); - ambauart_event(info, EVT_WRITE_WAKEUP); - } - } else { - if (!status) { - info->tty->hw_stopped = 1; - ambauart_disable_tx_interrupt(info); - } - } - } - } - wake_up_interruptible(&info->delta_msr_wait); - -} - -static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs) -{ - struct amba_info *info = dev_id; - unsigned int status, pass_counter = 0; - -#if DEBUG_LEDS - // tell the world - set_leds(get_leds() | RED_LED); -#endif - - status = UART_GET_INT_STATUS(info->port); - do { - /* - * FIXME: what about clearing the interrupts? - */ - - if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS)) -#ifdef SUPPORT_SYSRQ - ambauart_rx_chars(info, regs); -#else - ambauart_rx_chars(info); -#endif - if (status & AMBA_UARTIIR_TIS) - ambauart_tx_chars(info); - if (status & AMBA_UARTIIR_MIS) - ambauart_modem_status(info); - if (pass_counter++ > AMBA_ISR_PASS_LIMIT) - break; - - status = UART_GET_INT_STATUS(info->port); - } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS)); - -#if DEBUG_LEDS - // tell the world - set_leds(get_leds() & ~RED_LED); -#endif -} - -static void ambauart_tasklet_action(unsigned long data) -{ - struct amba_info *info = (struct amba_info *)data; - struct tty_struct *tty; - - tty = info->tty; - if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) - return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); -} - -static int ambauart_startup(struct amba_info *info) -{ - unsigned long flags; - unsigned long page; - int retval = 0; - - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - - if (info->xmit.buf) - free_page(page); - else - info->xmit.buf = (unsigned char *) page; - - /* - * Allocate the IRQ - */ - retval = request_irq(info->port->irq, ambauart_int, 0, "amba", info); - if (retval) { - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - retval = 0; - } - goto errout; - } - - info->mctrl = 0; - if (info->tty->termios->c_cflag & CBAUD) - info->mctrl = TIOCM_RTS | TIOCM_DTR; - info->port->set_mctrl(info->port, info->mctrl); - - /* - * initialise the old status of the modem signals - */ - info->old_status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; - - /* - * Finally, enable interrupts - */ - ambauart_enable_rx_interrupt(info); - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit.head = info->xmit.tail = 0; - - /* - * Set up the tty->alt_speed kludge - */ - if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - } - - /* - * and set the speed of the serial port - */ - ambauart_change_speed(info, 0); - - info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); - return 0; - -errout: - restore_flags(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void ambauart_shutdown(struct amba_info *info) -{ - unsigned long flags; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - save_flags(flags); cli(); /* Disable interrupts */ - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be woken up - */ - wake_up_interruptible(&info->delta_msr_wait); - - /* - * Free the IRQ - */ - free_irq(info->port->irq, info); - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = NULL; - free_page(pg); - } - - /* - * disable all interrupts, disable the port - */ - UART_PUT_CR(info->port, 0); - - /* disable break condition and fifos */ - UART_PUT_LCRH(info->port, UART_GET_LCRH(info->port) & - ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); - - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS); - info->port->set_mctrl(info->port, info->mctrl); - - /* kill off our tasklet */ - tasklet_kill(&info->tlet); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); -} - -static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios) -{ - unsigned int lcr_h, baud, quot, cflag, old_cr, bits; - unsigned long flags; - - if (!info->tty || !info->tty->termios) - return; - - cflag = info->tty->termios->c_cflag; - -#if DEBUG - printk("ambauart_set_cflag(0x%x) called\n", cflag); -#endif - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; bits = 7; break; - case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; bits = 8; break; - case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; bits = 9; break; - default: lcr_h = AMBA_UARTLCR_H_WLEN_8; bits = 10; break; // CS8 - } - if (cflag & CSTOPB) { - lcr_h |= AMBA_UARTLCR_H_STP2; - bits ++; - } - if (cflag & PARENB) { - lcr_h |= AMBA_UARTLCR_H_PEN; - bits++; - if (!(cflag & PARODD)) - lcr_h |= AMBA_UARTLCR_H_EPS; - } - if (info->port->fifosize > 1) - lcr_h |= AMBA_UARTLCR_H_FEN; - - do { - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(info->tty); - if (!baud) - baud = 9600; - - if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->state->custom_divisor; - else - quot = (info->port->uartclk / (16 * baud)) - 1; - - if (!quot && old_termios) { - info->tty->termios->c_cflag &= ~CBAUD; - info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); - old_termios = NULL; - } - } while (quot == 0 && old_termios); - - /* As a last resort, if the quotient is zero, default to 9600 bps */ - if (!quot) - quot = (info->port->uartclk / (16 * 9600)) - 1; - - info->timeout = (info->port->fifosize * HZ * bits * quot) / - (info->port->uartclk / 16); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - - if (cflag & CRTSCTS) - info->flags |= ASYNC_CTS_FLOW; - else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else - info->flags |= ASYNC_CHECK_CD; - - /* - * Set up parity check flag - */ -#define RELEVENT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - info->read_status_mask = AMBA_UARTRSR_OE; - if (I_INPCK(info->tty)) - info->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) - info->read_status_mask |= AMBA_UARTRSR_BE; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; - if (I_IGNBRK(info->tty)) { - info->ignore_status_mask |= AMBA_UARTRSR_BE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns to (for real raw support). - */ - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= AMBA_UARTRSR_OE; - } - - /* first, disable everything */ - save_flags(flags); cli(); - old_cr = UART_GET_CR(info->port) &= ~AMBA_UARTCR_MSIE; - - if ((info->flags & ASYNC_HARDPPS_CD) || - (cflag & CRTSCTS) || - !(cflag & CLOCAL)) - old_cr |= AMBA_UARTCR_MSIE; - - UART_PUT_CR(info->port, 0); - restore_flags(flags); - - /* Set baud rate */ - UART_PUT_LCRM(info->port, ((quot & 0xf00) >> 8)); - UART_PUT_LCRL(info->port, (quot & 0xff)); - - /* - * ----------v----------v----------v----------v----- - * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L - * ----------^----------^----------^----------^----- - */ - UART_PUT_LCRH(info->port, lcr_h); - UART_PUT_CR(info->port, old_cr); -} - -static void ambauart_put_char(struct tty_struct *tty, u_char ch) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - - if (!tty || !info->xmit.buf) - return; - - save_flags(flags); cli(); - if (CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE) != 0) { - info->xmit.buf[info->xmit.head] = ch; - info->xmit.head = (info->xmit.head + 1) & (AMBA_XMIT_SIZE - 1); - } - restore_flags(flags); -} - -static void ambauart_flush_chars(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - - if (info->xmit.head == info->xmit.tail - || tty->stopped - || tty->hw_stopped - || !info->xmit.buf) - return; - - save_flags(flags); cli(); - ambauart_enable_tx_interrupt(info); - restore_flags(flags); -} - -static int ambauart_write(struct tty_struct *tty, int from_user, - const u_char * buf, int count) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - int c, ret = 0; - - if (!tty || !info->xmit.buf || !tmp_buf) - return 0; - - save_flags(flags); - if (from_user) { - down(&tmp_buf_sem); - while (1) { - int c1; - c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - AMBA_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - - c -= copy_from_user(tmp_buf, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - cli(); - c1 = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - AMBA_XMIT_SIZE); - if (c1 < c) - c = c1; - memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); - info->xmit.head = (info->xmit.head + c) & - (AMBA_XMIT_SIZE - 1); - restore_flags(flags); - buf += c; - count -= c; - ret += c; - } - up(&tmp_buf_sem); - } else { - cli(); - while (1) { - c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - AMBA_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(info->xmit.buf + info->xmit.head, buf, c); - info->xmit.head = (info->xmit.head + c) & - (AMBA_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } - restore_flags(flags); - } - if (info->xmit.head != info->xmit.tail - && !tty->stopped - && !tty->hw_stopped) - ambauart_enable_tx_interrupt(info); - return ret; -} - -static int ambauart_write_room(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - - return CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE); -} - -static int ambauart_chars_in_buffer(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - - return CIRC_CNT(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE); -} - -static void ambauart_flush_buffer(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - -#if DEBUG - printk("ambauart_flush_buffer(%d) called\n", - minor(tty->device) - tty->driver.minor_start); -#endif - save_flags(flags); cli(); - info->xmit.head = info->xmit.tail = 0; - restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void ambauart_send_xchar(struct tty_struct *tty, char ch) -{ - struct amba_info *info = tty->driver_data; - - info->x_char = ch; - if (ch) - ambauart_enable_tx_interrupt(info); -} - -static void ambauart_throttle(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - - if (I_IXOFF(tty)) - ambauart_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios->c_cflag & CRTSCTS) { - save_flags(flags); cli(); - info->mctrl &= ~TIOCM_RTS; - info->port->set_mctrl(info->port, info->mctrl); - restore_flags(flags); - } -} - -static void ambauart_unthrottle(struct tty_struct *tty) -{ - struct amba_info *info = (struct amba_info *) tty->driver_data; - unsigned long flags; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - ambauart_send_xchar(tty, START_CHAR(tty)); - } - - if (tty->termios->c_cflag & CRTSCTS) { - save_flags(flags); cli(); - info->mctrl |= TIOCM_RTS; - info->port->set_mctrl(info->port, info->mctrl); - restore_flags(flags); - } -} - -static int get_serial_info(struct amba_info *info, struct serial_struct *retinfo) -{ - struct amba_state *state = info->state; - struct amba_port *port = info->port; - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = 0; - tmp.line = state->line; - tmp.port = port->uart_base; - if (HIGH_BITS_OFFSET) - tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET; - tmp.irq = port->irq; - tmp.flags = 0; - tmp.xmit_fifo_size = port->fifosize; - tmp.baud_base = port->uartclk / 16; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait; - tmp.custom_divisor = state->custom_divisor; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct amba_info *info, - struct serial_struct *newinfo) -{ - struct serial_struct new_serial; - struct amba_state *state, old_state; - struct amba_port *port; - unsigned long new_port; - unsigned int i, change_irq, change_port; - int retval = 0; - - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - state = info->state; - old_state = *state; - port = info->port; - - new_port = new_serial.port; - if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; - - change_irq = new_serial.irq != port->irq; - change_port = new_port != port->uart_base; - - if (!capable(CAP_SYS_ADMIN)) { - if (change_irq || change_port || - (new_serial.baud_base != port->uartclk / 16) || - (new_serial.close_delay != state->close_delay) || - (new_serial.xmit_fifo_size != port->fifosize) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (state->flags & ~ASYNC_USR_MASK))) - return -EPERM; - state->flags = ((state->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - state->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)) - return -EINVAL; - - if (new_serial.type && change_port) { - for (i = 0; i < SERIAL_AMBA_NR; i++) - if ((port != amba_ports + i) && - amba_ports[i].uart_base != new_port) - return -EADDRINUSE; - } - - if ((change_port || change_irq) && (state->count > 1)) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - port->uartclk = new_serial.baud_base * 16; - state->flags = ((state->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | - (info->flags & ASYNC_INTERNAL_FLAGS)); - state->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ / 100; - state->closing_wait = new_serial.closing_wait * HZ / 100; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - port->fifosize = new_serial.xmit_fifo_size; - - if (change_port || change_irq) { - /* - * We need to shutdown the serial port at the old - * port/irq combination. - */ - ambauart_shutdown(info); - port->irq = new_serial.irq; - port->uart_base = new_port; - } - -check_and_exit: - if (!port->uart_base) - return 0; - if (info->flags & ASYNC_INITIALIZED) { - if ((old_state.flags & ASYNC_SPD_MASK) != - (state->flags & ASYNC_SPD_MASK) || - (old_state.custom_divisor != state->custom_divisor)) { - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - ambauart_change_speed(info, NULL); - } - } else - retval = ambauart_startup(info); - return retval; -} - - -/* - * get_lsr_info - get line status register info - */ -static int get_lsr_info(struct amba_info *info, unsigned int *value) -{ - unsigned int result, status; - unsigned long flags; - - save_flags(flags); cli(); - status = UART_GET_FR(info->port); - restore_flags(flags); - result = status & AMBA_UARTFR_BUSY ? TIOCSER_TEMT : 0; - - /* - * If we're about to load something into the transmit - * register, we'll pretend the transmitter isn't empty to - * avoid a race condition (depending on when the transmit - * interrupt happens). - */ - if (info->x_char || - ((CIRC_CNT(info->xmit.head, info->xmit.tail, - AMBA_XMIT_SIZE) > 0) && - !info->tty->stopped && !info->tty->hw_stopped)) - result &= TIOCSER_TEMT; - - return put_user(result, value); -} - -static int get_modem_info(struct amba_info *info, unsigned int *value) -{ - unsigned int result = info->mctrl; - unsigned int status; - - status = UART_GET_FR(info->port); - if (status & AMBA_UARTFR_DCD) - result |= TIOCM_CAR; - if (status & AMBA_UARTFR_DSR) - result |= TIOCM_DSR; - if (status & AMBA_UARTFR_CTS) - result |= TIOCM_CTS; - - return put_user(result, value); -} - -static int set_modem_info(struct amba_info *info, unsigned int cmd, - unsigned int *value) -{ - unsigned int arg, old; - unsigned long flags; - - if (get_user(arg, value)) - return -EFAULT; - - old = info->mctrl; - switch (cmd) { - case TIOCMBIS: - info->mctrl |= arg; - break; - - case TIOCMBIC: - info->mctrl &= ~arg; - break; - - case TIOCMSET: - info->mctrl = arg; - break; - - default: - return -EINVAL; - } - save_flags(flags); cli(); - if (old != info->mctrl) - info->port->set_mctrl(info->port, info->mctrl); - restore_flags(flags); - return 0; -} - -static void ambauart_break_ctl(struct tty_struct *tty, int break_state) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - unsigned int lcr_h; - - save_flags(flags); cli(); - lcr_h = UART_GET_LCRH(info->port); - if (break_state == -1) - lcr_h |= AMBA_UARTLCR_H_BRK; - else - lcr_h &= ~AMBA_UARTLCR_H_BRK; - UART_PUT_LCRH(info->port, lcr_h); - restore_flags(flags); -} - -static int ambauart_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct amba_info *info = tty->driver_data; - struct amba_icount cprev, cnow; - struct serial_icounter_struct icount; - unsigned long flags; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TIOCMGET: - return get_modem_info(info, (unsigned int *)arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *)arg); - case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *)arg); - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *)arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *)arg); - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: - save_flags(flags); cli(); - /* note the counters on entry */ - cprev = info->state->icount; - /* Force modem status interrupts on */ - UART_PUT_CR(info->port, UART_GET_CR(info->port) | AMBA_UARTCR_MSIE); - restore_flags(flags); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - save_flags(flags); cli(); - cnow = info->state->icount; /* atomic copy */ - restore_flags(flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - save_flags(flags); cli(); - cnow = info->state->icount; - restore_flags(flags); - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; - - return copy_to_user((void *)arg, &icount, sizeof(icount)) - ? -EFAULT : 0; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void ambauart_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - struct amba_info *info = tty->driver_data; - unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; - - if ((cflag ^ old_termios->c_cflag) == 0 && - RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) - return; - - ambauart_change_speed(info, old_termios); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(cflag & CBAUD)) { - save_flags(flags); cli(); - info->mctrl &= ~(TIOCM_RTS | TIOCM_DTR); - info->port->set_mctrl(info->port, info->mctrl); - restore_flags(flags); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (cflag & CBAUD)) { - save_flags(flags); cli(); - info->mctrl |= TIOCM_DTR; - if (!(cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) - info->mctrl |= TIOCM_RTS; - info->port->set_mctrl(info->port, info->mctrl); - restore_flags(flags); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(cflag & CRTSCTS)) { - tty->hw_stopped = 0; - ambauart_start(tty); - } - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -static void ambauart_close(struct tty_struct *tty, struct file *filp) -{ - struct amba_info *info = tty->driver_data; - struct amba_state *state; - unsigned long flags; - - if (!info) - return; - - state = info->state; - -#if DEBUG - printk("ambauart_close() called\n"); -#endif - - save_flags(flags); cli(); - - if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - - if ((tty->count == 1) && (state->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("ambauart_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - if (--state->count < 0) { - printk("rs_close: bad serial port count for %s%d: %d\n", - tty->driver.name, info->state->line, state->count); - state->count = 0; - } - if (state->count) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - info->flags |= ASYNC_CLOSING; - restore_flags(flags); - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->state->closing_wait); - /* - * At this point, we stop accepting input. To do this, we - * disable the receive line status interrupts. - */ - if (info->flags & ASYNC_INITIALIZED) { - ambauart_disable_rx_interrupt(info); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - ambauart_wait_until_sent(tty, info->timeout); - } - ambauart_shutdown(info); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - tty->closing = 0; - info->event = 0; - info->tty = NULL; - if (info->blocked_open) { - if (info->state->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->state->close_delay); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; -} - -static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct amba_info *info = (struct amba_info *) tty->driver_data; - unsigned long char_time, expire; - unsigned int status; - - if (info->port->fifosize == 0) - return; - - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (info->timeout - HZ/50) / info->port->fifosize; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than info->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*info->timeout. - */ - if (!timeout || timeout > 2 * info->timeout) - timeout = 2 * info->timeout; - - expire = jiffies + timeout; -#if DEBUG - printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n", - minor(tty->device) - tty->driver.minor_start, jiffies, - expire); -#endif - while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, expire)) - break; - status = UART_GET_FR(info->port); - } - set_current_state(TASK_RUNNING); -} - -static void ambauart_hangup(struct tty_struct *tty) -{ - struct amba_info *info = tty->driver_data; - struct amba_state *state = info->state; - - ambauart_flush_buffer(tty); - if (info->flags & ASYNC_CLOSING) - return; - ambauart_shutdown(info); - info->event = 0; - state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); - info->tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -static int block_til_ready(struct tty_struct *tty, struct file *filp, - struct amba_info *info) -{ - DECLARE_WAITQUEUE(wait, current); - struct amba_state *state = info->state; - unsigned long flags; - int do_clocal = 0, extra_count = 0, retval; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); - return (info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; - } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); - save_flags(flags); cli(); - if (!tty_hung_up_p(filp)) { - extra_count = 1; - state->count--; - } - restore_flags(flags); - info->blocked_open++; - while (1) { - save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { - info->mctrl = TIOCM_DTR | TIOCM_RTS; - info->port->set_mctrl(info->port, info->mctrl); - } - restore_flags(flags); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; - break; - } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && - (do_clocal || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); - if (extra_count) - state->count++; - info->blocked_open--; - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static struct amba_info *ambauart_get(int line) -{ - struct amba_info *info; - struct amba_state *state = amba_state + line; - - state->count++; - if (state->info) - return state->info; - info = kmalloc(sizeof(struct amba_info), GFP_KERNEL); - if (info) { - memset(info, 0, sizeof(struct amba_info)); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->delta_msr_wait); - info->flags = state->flags; - info->state = state; - info->port = amba_ports + line; - tasklet_init(&info->tlet, ambauart_tasklet_action, - (unsigned long)info); - } - if (state->info) { - kfree(info); - return state->info; - } - state->info = info; - return info; -} - -static int ambauart_open(struct tty_struct *tty, struct file *filp) -{ - struct amba_info *info; - int retval, line = minor(tty->device) - tty->driver.minor_start; - -#if DEBUG - printk("ambauart_open(%d) called\n", line); -#endif - - // is this a line that we've got? - MOD_INC_USE_COUNT; - if (line >= SERIAL_AMBA_NR) { - MOD_DEC_USE_COUNT; - return -ENODEV; - } - - info = ambauart_get(line); - if (!info) - return -ENOMEM; - - tty->driver_data = info; - info->tty = tty; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - /* - * Make sure we have the temporary buffer allocated - */ - if (!tmp_buf) { - unsigned long page = get_zeroed_page(GFP_KERNEL); - if (tmp_buf) - free_page(page); - else if (!page) { - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - tmp_buf = (u_char *)page; - } - - /* - * If the port is in the middle of closing, bail out now. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); - MOD_DEC_USE_COUNT; - return -EAGAIN; - } - - /* - * Start up the serial port - */ - retval = ambauart_startup(info); - if (retval) { - MOD_DEC_USE_COUNT; - return retval; - } - - retval = block_til_ready(tty, filp, info); - if (retval) { - MOD_DEC_USE_COUNT; - return retval; - } - - if ((info->state->count == 1) && - (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; - } -#ifdef CONFIG_SERIAL_AMBA_CONSOLE - if (ambauart_cons.cflag && ambauart_cons.index == line) { - tty->termios->c_cflag = ambauart_cons.cflag; - ambauart_cons.cflag = 0; - } -#endif - ambauart_change_speed(info, NULL); - info->session = current->session; - info->pgrp = current->pgrp; - return 0; -} - -int __init ambauart_init(void) -{ - int i; - - ambanormal_driver.magic = TTY_DRIVER_MAGIC; - ambanormal_driver.driver_name = "serial_amba"; - ambanormal_driver.name = SERIAL_AMBA_NAME; - ambanormal_driver.major = SERIAL_AMBA_MAJOR; - ambanormal_driver.minor_start = SERIAL_AMBA_MINOR; - ambanormal_driver.num = SERIAL_AMBA_NR; - ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL; - ambanormal_driver.subtype = SERIAL_TYPE_NORMAL; - ambanormal_driver.init_termios = tty_std_termios; - ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - ambanormal_driver.refcount = &ambauart_refcount; - ambanormal_driver.table = ambauart_table; - ambanormal_driver.termios = ambauart_termios; - ambanormal_driver.termios_locked = ambauart_termios_locked; - - ambanormal_driver.open = ambauart_open; - ambanormal_driver.close = ambauart_close; - ambanormal_driver.write = ambauart_write; - ambanormal_driver.put_char = ambauart_put_char; - ambanormal_driver.flush_chars = ambauart_flush_chars; - ambanormal_driver.write_room = ambauart_write_room; - ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer; - ambanormal_driver.flush_buffer = ambauart_flush_buffer; - ambanormal_driver.ioctl = ambauart_ioctl; - ambanormal_driver.throttle = ambauart_throttle; - ambanormal_driver.unthrottle = ambauart_unthrottle; - ambanormal_driver.send_xchar = ambauart_send_xchar; - ambanormal_driver.set_termios = ambauart_set_termios; - ambanormal_driver.stop = ambauart_stop; - ambanormal_driver.start = ambauart_start; - ambanormal_driver.hangup = ambauart_hangup; - ambanormal_driver.break_ctl = ambauart_break_ctl; - ambanormal_driver.wait_until_sent = ambauart_wait_until_sent; - ambanormal_driver.read_proc = NULL; - - /* - * The callout device is just like the normal device except for - * the major number and the subtype code. - */ - ambacallout_driver = ambanormal_driver; - ambacallout_driver.name = CALLOUT_AMBA_NAME; - ambacallout_driver.major = CALLOUT_AMBA_MAJOR; - ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT; - ambacallout_driver.read_proc = NULL; - ambacallout_driver.proc_entry = NULL; - - if (tty_register_driver(&ambanormal_driver)) - panic("Couldn't register AMBA serial driver\n"); - if (tty_register_driver(&ambacallout_driver)) - panic("Couldn't register AMBA callout driver\n"); - - for (i = 0; i < SERIAL_AMBA_NR; i++) { - struct amba_state *state = amba_state + i; - state->line = i; - state->close_delay = 5 * HZ / 10; - state->closing_wait = 30 * HZ; - state->callout_termios = ambacallout_driver.init_termios; - state->normal_termios = ambanormal_driver.init_termios; - } - - return 0; -} - -__initcall(ambauart_init); - -#ifdef CONFIG_SERIAL_AMBA_CONSOLE -/************** console driver *****************/ - -/* - * This code is currently never used; console->read is never called. - * Therefore, although we have an implementation, we don't use it. - * FIXME: the "const char *s" should be fixed to "char *s" some day. - * (when the definition in include/linux/console.h is also fixed) - */ -#ifdef used_and_not_const_char_pointer -static int ambauart_console_read(struct console *co, const char *s, u_int count) -{ - struct amba_port *port = &amba_ports[co->index]; - unsigned int status; - char *w; - int c; -#if DEBUG - printk("ambauart_console_read() called\n"); -#endif - - c = 0; - w = s; - while (c < count) { - status = UART_GET_FR(port); - if (UART_RX_DATA(status)) { - *w++ = UART_GET_CHAR(port); - c++; - } else { - // nothing more to get, return - return c; - } - } - // return the count - return c; -} -#endif - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console must be locked when we get here. - */ -static void ambauart_console_write(struct console *co, const char *s, u_int count) -{ - struct amba_port *port = &amba_ports[co->index]; - unsigned int status, old_cr; - int i; - - /* - * First save the CR then disable the interrupts - */ - old_cr = UART_GET_CR(port); - UART_PUT_CR(port, AMBA_UARTCR_UARTEN); - - /* - * Now, do each character - */ - for (i = 0; i < count; i++) { - do { - status = UART_GET_FR(port); - } while (!UART_TX_READY(status)); - UART_PUT_CHAR(port, s[i]); - if (s[i] == '\n') { - do { - status = UART_GET_FR(port); - } while (!UART_TX_READY(status)); - UART_PUT_CHAR(port, '\r'); - } - } - - /* - * Finally, wait for transmitter to become empty - * and restore the TCR - */ - do { - status = UART_GET_FR(port); - } while (status & AMBA_UARTFR_BUSY); - UART_PUT_CR(port, old_cr); -} - -static kdev_t ambauart_console_device(struct console *c) -{ - return mk_kdev(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index); -} - -static int __init ambauart_console_setup(struct console *co, char *options) -{ - struct amba_port *port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - u_int cflag = CREAD | HUPCL | CLOCAL; - u_int lcr_h, quot; - - if (co->index >= SERIAL_AMBA_NR) - co->index = 0; - - port = &amba_ports[co->index]; - - if (options) { - char *s = options; - baud = simple_strtoul(s, NULL, 10); - while (*s >= '0' && *s <= '9') - s++; - if (*s) parity = *s++; - if (*s) bits = *s - '0'; - } - - /* - * Now construct a cflag setting. - */ - switch (baud) { - case 1200: cflag |= B1200; break; - case 2400: cflag |= B2400; break; - case 4800: cflag |= B4800; break; - default: cflag |= B9600; baud = 9600; break; - case 19200: cflag |= B19200; break; - case 38400: cflag |= B38400; break; - case 57600: cflag |= B57600; break; - case 115200: cflag |= B115200; break; - } - switch (bits) { - case 7: cflag |= CS7; lcr_h = AMBA_UARTLCR_H_WLEN_7; break; - default: cflag |= CS8; lcr_h = AMBA_UARTLCR_H_WLEN_8; break; - } - switch (parity) { - case 'o': - case 'O': cflag |= PARODD; lcr_h |= AMBA_UARTLCR_H_PEN; break; - case 'e': - case 'E': cflag |= PARENB; lcr_h |= AMBA_UARTLCR_H_PEN | - AMBA_UARTLCR_H_EPS; break; - } - - co->cflag = cflag; - - if (port->fifosize > 1) - lcr_h |= AMBA_UARTLCR_H_FEN; - - quot = (port->uartclk / (16 * baud)) - 1; - - UART_PUT_LCRL(port, (quot & 0xff)); - UART_PUT_LCRM(port, (quot >> 8)); - UART_PUT_LCRH(port, lcr_h); - - /* we will enable the port as we need it */ - UART_PUT_CR(port, 0); - - return 0; -} - -static struct console ambauart_cons = -{ - name: SERIAL_AMBA_NAME, - write: ambauart_console_write, -#ifdef used_and_not_const_char_pointer - read: ambauart_console_read, -#endif - device: ambauart_console_device, - setup: ambauart_console_setup, - flags: CON_PRINTBUFFER, - index: -1, -}; - -void __init ambauart_console_init(void) -{ - register_console(&ambauart_cons); -} - -#endif /* CONFIG_SERIAL_AMBA_CONSOLE */ - -MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h --- a/drivers/char/specialix_io8.h Fri Jul 26 19:58:50 2002 +++ b/drivers/char/specialix_io8.h Fri Jul 26 19:58:50 2002 @@ -110,7 +110,7 @@ struct tty_struct * tty; int count; int blocked_open; - int event; + ulong event; int timeout; int close_delay; long session; diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Fri Jul 26 19:58:51 2002 +++ b/drivers/char/tty_io.c Fri Jul 26 19:58:51 2002 @@ -545,6 +545,7 @@ #endif do_tty_hangup((void *) tty); } +EXPORT_SYMBOL(tty_vhangup); int tty_hung_up_p(struct file * filp) { @@ -1458,6 +1459,10 @@ if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = 1; if (filp->f_owner.pid == 0) { + retval = security_ops->file_set_fowner(filp); + if (retval) + return retval; + filp->f_owner.pid = (-tty->pgrp) ? : current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help --- a/drivers/ide/Config.help Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/Config.help Fri Jul 26 19:58:52 2002 @@ -84,6 +84,16 @@ Support for outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +CONFIG_ATAPI + If you wish to enable basic support for devices attached to the system + through the ATA interface, and which are using using the ATAPI protocol + (CD-ROM, CD-RW, DVD, DVD-RW, LS120, ZIP, ...), say Y. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called atapi.o. + CONFIG_BLK_DEV_IDECD If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is a newer protocol used by IDE CD-ROM and TAPE drives, similar to the diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in --- a/drivers/ide/Config.in Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/Config.in Fri Jul 26 19:58:52 2002 @@ -1,40 +1,37 @@ # -# IDE ATA ATAPI Block device driver configuration +# ATA/ATAPI block device driver configuration # -# Andre Hedrick -# -mainmenu_option next_comment -comment 'ATA and ATAPI Block devices' - -dep_tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE $CONFIG_IDE -comment 'Please see Documentation/ide.txt for help/info on IDE drives' +dep_tristate 'Enhanced ATA/ATAPI device (disk,cdrom,...) support' CONFIG_BLK_DEV_IDE $CONFIG_IDE if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE $CONFIG_X86 define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_IDE - dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE - dep_mbool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK - dep_mbool ' Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK - dep_tristate ' PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA - dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE - dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE - dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE - dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI + dep_tristate ' ATA disk support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE + dep_bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK + dep_bool ' Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK + + dep_tristate ' ATAPI device support (CD-ROM, floppy)' CONFIG_ATAPI $CONFIG_BLK_DEV_IDE + dep_tristate ' CD-ROM support' CONFIG_BLK_DEV_IDECD $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE + dep_tristate ' Tape support' CONFIG_BLK_DEV_IDETAPE $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE + dep_tristate ' Floppy support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE + dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_ATAPI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI + + dep_tristate ' PCMCIA/CardBus support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA - comment 'ATA host chip set support' - dep_bool ' CMD640 chip set bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86 + comment 'ATA host controller support' + dep_bool ' RZ1000 bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86 + dep_bool ' CMD640 bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86 dep_bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640 dep_bool ' ISA-PNP support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP - if [ "$CONFIG_PCI" = "y" ]; then - dep_bool ' RZ1000 chip set bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86 - comment ' PCI host chip set support' - dep_bool ' Boot off-board chip sets first support' CONFIG_BLK_DEV_OFFBOARD $CONFIG_PCI - dep_bool ' Sharing PCI ATA interrupts support' CONFIG_IDEPCI_SHARE_IRQ $CONFIG_PCI + if [ "$CONFIG_PCI" != "n" ]; then + comment ' PCI host controller support' + dep_bool ' Boot off-board controllers first' CONFIG_BLK_DEV_OFFBOARD $CONFIG_PCI + dep_bool ' Sharing PCI ATA interrupts' CONFIG_IDEPCI_SHARE_IRQ $CONFIG_PCI dep_bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_PCI dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI - dep_bool ' ATA tagged command queueing (DANGEROUS)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL + dep_bool ' Tagged command queueing (DANGEROUS)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32 @@ -110,7 +107,7 @@ fi # assume no ISA -> also no VLB - dep_bool ' Other ISA/VLB IDE chipset support' CONFIG_IDE_CHIPSETS $CONFIG_ISA + dep_bool ' ISA/VLB IDE chipset support' CONFIG_IDE_CHIPSETS $CONFIG_ISA if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then comment 'Note: most of these also require special kernel boot parameters' bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX @@ -122,15 +119,13 @@ dep_tristate ' QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 fi - if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \ - "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \ - "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" != "n" -o \ + "$CONFIG_BLK_DEV_IDEDMA_PMAC" != "n" -o \ + "$CONFIG_BLK_DEV_IDEDMA_ICS" != "n" ]; then bool ' IGNORE word93 Validation BITS' CONFIG_IDEDMA_IVB fi - - define_bool CONFIG_ATAPI y else - bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY + bool 'Old disk only (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_ONLY fi @@ -142,8 +137,6 @@ define_bool CONFIG_IDEDMA_AUTO n fi -dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL -dep_tristate ' Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID -dep_tristate ' Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID - -endmenu +dep_tristate 'Support for software RAID controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL +dep_tristate ' Support Promise (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID +dep_tristate ' Highpoint 370 EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile --- a/drivers/ide/Makefile Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/Makefile Fri Jul 26 19:58:52 2002 @@ -15,7 +15,7 @@ obj-$(CONFIG_BLK_DEV_IDE) += ide-mod.o obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o -# obj-$(CONFIG_ATAPI) += atapi.o +obj-$(CONFIG_ATAPI) += atapi.o obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o @@ -69,6 +69,6 @@ obj-$(CONFIG_BLK_DEV_ATARAID_HPT) += hptraid.o ide-mod-objs := device.o ide-taskfile.o main.o ide.o probe.o \ - ioctl.o atapi.o ata-timing.o $(ide-obj-y) + ioctl.o ata-timing.o $(ide-obj-y) include $(TOPDIR)/Rules.make diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c --- a/drivers/ide/aec62xx.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/aec62xx.c Fri Jul 26 19:58:51 2002 @@ -42,10 +42,11 @@ #include #include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define AEC_DRIVE_TIMING 0x40 @@ -167,7 +168,7 @@ return; } - aec_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); + aec_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); } #ifdef CONFIG_BLK_DEV_IDEDMA diff -Nru a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c --- a/drivers/ide/ali14xx.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ali14xx.c Fri Jul 26 19:58:51 2002 @@ -37,12 +37,13 @@ #include #include -#include #include +#include +#include #include -#include "ata-timing.h" +#include "timing.h" /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c --- a/drivers/ide/alim15x3.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/alim15x3.c Fri Jul 26 19:58:52 2002 @@ -26,30 +26,30 @@ #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" -static byte m5229_revision; -static byte chip_is_1543c_e; +static u8 m5229_revision; +static int chip_is_1543c_e; static struct pci_dev *isa_dev; -static void ali15x3_tune_drive(struct ata_device *drive, byte pio) +static void ali15x3_tune_drive(struct ata_device *drive, u8 pio) { struct ata_timing *t; struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; int s_time, a_time, c_time; - byte s_clc, a_clc, r_clc; + u8 s_clc, a_clc, r_clc; unsigned long flags; int port = hwif->unit ? 0x5c : 0x58; int portFIFO = hwif->unit ? 0x55 : 0x54; - byte cd_dma_fifo = 0; + u8 cd_dma_fifo = 0; if (pio == 255) pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); else - pio = XFER_PIO_0 + min_t(byte, pio, 4); + pio = XFER_PIO_0 + min_t(u8, pio, 4); t = ata_timing_data(pio); @@ -100,15 +100,15 @@ local_irq_restore(flags); } -static int ali15x3_tune_chipset(struct ata_device *drive, byte speed) +static int ali15x3_tune_chipset(struct ata_device *drive, u8 speed) { struct pci_dev *dev = drive->channel->pci_dev; - byte unit = (drive->select.b.unit & 0x01); - byte tmpbyte = 0x00; - int m5229_udma = drive->channel->unit ? 0x57 : 0x56; + u8 unit = (drive->select.b.unit & 0x01); + u8 tmpbyte = 0x00; + int m5229_udma = drive->channel->unit ? 0x57 : 0x56; if (speed < XFER_UDMA_0) { - byte ultra_enable = (unit) ? 0x7f : 0xf7; + u8 ultra_enable = unit ? 0x7f : 0xf7; /* * clear "ultra enable" bit */ @@ -135,7 +135,7 @@ pci_write_config_byte(dev, 0x4b, tmpbyte); } } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif return ide_config_drive_speed(drive, speed); } @@ -212,10 +212,10 @@ { struct pci_dev *dev = hwif->pci_dev; unsigned int ata66 = 0; - byte cable_80_pin[2] = { 0, 0 }; + u8 cable_80_pin[2] = { 0, 0 }; unsigned long flags; - byte tmpbyte; + u8 tmpbyte; local_irq_save(flags); @@ -305,8 +305,8 @@ static void __init ali15x3_init_channel(struct ata_channel *hwif) { #ifndef CONFIG_SPARC64 - byte ideic, inmir; - byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, + u8 ideic, inmir; + u8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; hwif->irq = hwif->unit ? 15 : 14; diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c --- a/drivers/ide/amd74xx.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/amd74xx.c Fri Jul 26 19:58:51 2002 @@ -42,11 +42,12 @@ #include #include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define AMD_IDE_ENABLE (0x00 + amd_config->base) @@ -171,7 +172,7 @@ return; } - amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); + amd_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); } #ifdef CONFIG_BLK_DEV_IDEDMA diff -Nru a/drivers/ide/ata-timing.c b/drivers/ide/ata-timing.c --- a/drivers/ide/ata-timing.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ata-timing.c Fri Jul 26 19:58:51 2002 @@ -23,7 +23,10 @@ */ #include -#include "ata-timing.h" +#include +#include + +#include "timing.h" /* * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). These were taken diff -Nru a/drivers/ide/ata-timing.h b/drivers/ide/ata-timing.h --- a/drivers/ide/ata-timing.h Fri Jul 26 19:58:52 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,95 +0,0 @@ -#ifndef _ATA_TIMING_H -#define _ATA_TIMING_H - -/* - * $Id: ata-timing.h,v 2.0 2002/03/12 13:02:22 vojtech Exp $ - * - * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord - * Copyright (C) 1999-2001 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#define XFER_PIO_5 0x0d -#define XFER_UDMA_SLOW 0x4f - -struct ata_timing { - short mode; - short setup; /* t1 */ - short act8b; /* t2 for 8-bit io */ - short rec8b; /* t2i for 8-bit io */ - short cyc8b; /* t0 for 8-bit io */ - short active; /* t2 or tD */ - short recover; /* t2i or tK */ - short cycle; /* t0 */ - short udma; /* t2CYCTYP/2 */ -}; - -extern struct ata_timing ata_timing[]; - -#define IDE_TIMING_SETUP 0x01 -#define IDE_TIMING_ACT8B 0x02 -#define IDE_TIMING_REC8B 0x04 -#define IDE_TIMING_CYC8B 0x08 -#define IDE_TIMING_8BIT 0x0e -#define IDE_TIMING_ACTIVE 0x10 -#define IDE_TIMING_RECOVER 0x20 -#define IDE_TIMING_CYCLE 0x40 -#define IDE_TIMING_UDMA 0x80 -#define IDE_TIMING_ALL 0xff - -#define FIT(v,x,y) max_t(int,min_t(int,v,y),x) -#define ENOUGH(v,unit) (((v)-1)/(unit)+1) -#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) - -/* see hpt366.c for details */ -#define XFER_UDMA_66_3 0x100 -#define XFER_UDMA_66_4 0x200 - -#define XFER_MODE 0xff0 -#define XFER_UDMA_133 0x800 -#define XFER_UDMA_100 0x400 -#define XFER_UDMA_66 0x300 -#define XFER_UDMA 0x040 -#define XFER_MWDMA 0x020 -#define XFER_SWDMA 0x010 -#define XFER_EPIO 0x001 -#define XFER_PIO 0x000 - -#define XFER_UDMA_ALL 0xf40 -#define XFER_UDMA_80W 0xf00 - -/* External interface to host chips channel timing setup. - * - * It's a bit elaborate due to the legacy we have to bear. - */ - -extern short ata_timing_mode(struct ata_device *drive, int map); -extern void ata_timing_quantize(struct ata_timing *t, struct ata_timing *q, - int T, int UT); -extern void ata_timing_merge(struct ata_timing *a, struct ata_timing *b, - struct ata_timing *m, unsigned int what); -void ata_timing_merge_8bit(struct ata_timing *t); -extern struct ata_timing* ata_timing_data(short speed); -extern int ata_timing_compute(struct ata_device *drive, - short speed, struct ata_timing *t, int T, int UT); -extern u8 ata_best_pio_mode(struct ata_device *drive); - -#endif diff -Nru a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c --- a/drivers/ide/cmd640.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/cmd640.c Fri Jul 26 19:58:51 2002 @@ -106,13 +106,13 @@ #include #include #include +#include #include #include -#include #include -#include "ata-timing.h" +#include "timing.h" /* * This flag is set in ide.c by the parameter: ide0=cmd640_vlb @@ -200,7 +200,7 @@ * Interface to access cmd640x registers */ static unsigned int cmd640_key; -static void (*put_cmd640_reg)(unsigned short reg, byte val); +static void (*put_cmd640_reg)(unsigned short reg, u8 val); static u8 (*get_cmd640_reg)(unsigned short reg); /* @@ -214,17 +214,19 @@ * Therefore, we must use direct IO instead. */ +/* This is broken, but no more so than the old code.. */ +static spinlock_t cmd640_lock = SPIN_LOCK_UNLOCKED; + /* PCI method 1 access */ -static void put_cmd640_reg_pci1 (unsigned short reg, byte val) +static void put_cmd640_reg_pci1 (unsigned short reg, u8 val) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outl_p((reg & 0xfc) | cmd640_key, 0xcf8); outb_p(val, (reg & 3) | 0xcfc); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } static u8 get_cmd640_reg_pci1 (unsigned short reg) @@ -232,11 +234,10 @@ u8 b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outl_p((reg & 0xfc) | cmd640_key, 0xcf8); b = inb_p((reg & 3) | 0xcfc); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return b; } @@ -246,12 +247,11 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outb_p(0x10, 0xcf8); outb_p(val, cmd640_key + reg); outb_p(0, 0xcf8); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } static u8 get_cmd640_reg_pci2 (unsigned short reg) @@ -259,12 +259,11 @@ u8 b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outb_p(0x10, 0xcf8); b = inb_p(cmd640_key + reg); outb_p(0, 0xcf8); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return b; } @@ -274,11 +273,10 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outb_p(reg, cmd640_key); outb_p(val, cmd640_key + 4); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } static u8 get_cmd640_reg_vlb (unsigned short reg) @@ -286,11 +284,10 @@ u8 b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outb_p(reg, cmd640_key); b = inb_p(cmd640_key + 4); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return b; } @@ -367,8 +364,7 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ udelay(100); @@ -376,11 +372,11 @@ outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ udelay(100); if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return 0; /* nothing responded */ } } - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return 1; /* success */ } @@ -461,8 +457,7 @@ u8 b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&cmd640_lock, flags); b = get_cmd640_reg(reg); if (mode) { /* want prefetch on? */ # if CMD640_PREFETCH_MASKS @@ -478,7 +473,7 @@ b |= prefetch_masks[index]; /* disable prefetch */ } put_cmd640_reg(reg, b); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } /* @@ -579,8 +574,7 @@ /* * Now that everything is ready, program the new timings */ - save_flags (flags); - cli(); + spin_lock(&cmd640_lock, flags); /* * Program the address_setup clocks into ARTTIM reg, * and then the active/recovery counts into the DRWTIM reg @@ -589,7 +583,7 @@ setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f; put_cmd640_reg(arttim_regs[index], setup_count); put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); - restore_flags(flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } /* @@ -647,7 +641,7 @@ /* * Drive PIO mode selection: */ -static void cmd640_tune_drive(struct ata_device *drive, byte mode_wanted) +static void cmd640_tune_drive(struct ata_device *drive, u8 mode_wanted) { u8 b; struct ata_timing *t; diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c --- a/drivers/ide/cmd64x.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/cmd64x.c Fri Jul 26 19:58:51 2002 @@ -18,13 +18,13 @@ #include #include #include -#include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define CMD_DEBUG 0 @@ -81,8 +81,8 @@ * Registers and masks for easy access by drive index: */ #if 0 -static byte prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; -static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; +static u8 prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; +static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; #endif /* @@ -93,15 +93,15 @@ { unsigned long flags; struct ata_device *drives = drive->channel->drives; - byte temp_b; - static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; - static const byte recovery_counts[] = + u8 temp_b; + static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const u8 recovery_counts[] = {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; - static const byte arttim_regs[2][2] = { + static const u8 arttim_regs[2][2] = { { ARTTIM0, ARTTIM1 }, { ARTTIM23, ARTTIM23 } }; - static const byte drwtim_regs[2][2] = { + static const u8 drwtim_regs[2][2] = { { DRWTIM0, DRWTIM1 }, { DRWTIM2, DRWTIM3 } }; @@ -142,11 +142,11 @@ */ (void) pci_read_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave], &temp_b); (void) pci_write_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave], - ((byte) setup_count) | (temp_b & 0x3f)); + ((u8) setup_count) | (temp_b & 0x3f)); (void) pci_write_config_byte(drive->channel->pci_dev, drwtim_regs[channel][slave], - (byte) ((active_count << 4) | recovery_count)); - cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]); - cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]); + (u8) ((active_count << 4) | recovery_count)); + cmdprintk ("Write %x to %x\n", ((u8) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]); + cmdprintk ("Write %x to %x\n", (u8) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]); local_irq_restore(flags); } @@ -405,7 +405,7 @@ return ide_config_drive_speed(drive, speed); } -static int cmd680_tune_chipset(struct ata_device *drive, byte speed) +static int cmd680_tune_chipset(struct ata_device *drive, u8 speed) { struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; @@ -520,9 +520,9 @@ dma_stat = inb(dma_base+2); /* get DMA status */ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ if (jack_slap) { - byte dma_intr = 0; - byte dma_mask = (ch->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; - byte dma_reg = (ch->unit) ? ARTTIM2 : CFR; + u8 dma_intr = 0; + u8 dma_mask = (ch->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; + u8 dma_reg = (ch->unit) ? ARTTIM2 : CFR; (void) pci_read_config_byte(dev, dma_reg, &dma_intr); /* * DAMN BMIDE is not connected to PCI space! diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c --- a/drivers/ide/cs5530.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/cs5530.c Fri Jul 26 19:58:51 2002 @@ -20,22 +20,22 @@ #include #include #include -#include #include #include #include +#include #include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" /* * Set a new transfer mode at the drive */ -int cs5530_set_xfer_mode(struct ata_device *drive, byte mode) +int cs5530_set_xfer_mode(struct ata_device *drive, u8 mode) { int error = 0; @@ -67,7 +67,7 @@ * The ide_init_cs5530() routine guarantees that all drives * will have valid default PIO timings set up before we get here. */ -static void cs5530_tuneproc(struct ata_device *drive, byte pio) /* pio=255 means "autotune" */ +static void cs5530_tuneproc(struct ata_device *drive, u8 pio) { struct ata_channel *hwif = drive->channel; unsigned int format, basereg = CS5530_BASEREG(hwif); @@ -75,7 +75,7 @@ if (pio == 255) pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); else - pio = XFER_PIO_0 + min_t(byte, pio, 4); + pio = XFER_PIO_0 + min_t(u8, pio, 4); if (!cs5530_set_xfer_mode(drive, pio)) { format = (inl(basereg+4) >> 31) & 1; @@ -206,7 +206,7 @@ unsigned short pcicmd = 0; unsigned long flags; - pci_for_each_dev (dev) { + pci_for_each_dev(dev) { if (dev->vendor == PCI_VENDOR_ID_CYRIX) { switch (dev->device) { case PCI_DEVICE_ID_CYRIX_PCI_MASTER: @@ -256,7 +256,7 @@ */ pci_write_config_byte(master_0, 0x40, 0x1e); - /* + /* * Set max PCI burst size (16-bytes seems to work best): * 16bytes: set bit-1 at 0x41 (reg value of 0x16) * all others: clear bit-1 at 0x41, and do: diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c --- a/drivers/ide/cy82c693.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/cy82c693.c Fri Jul 26 19:58:51 2002 @@ -47,11 +47,12 @@ #include #include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" /* the current version */ @@ -141,7 +142,7 @@ * for mode 3 and 4 drives 8 and 16-bit timings are the same * */ -/* FIXME: use generic ata-timings library --bkz */ +/* FIXME: use generic timings library --bkz */ static void compute_clocks(u8 pio, pio_clocks_t *p_pclk) { struct ata_timing *t; @@ -186,8 +187,8 @@ */ static void cy82c693_dma_enable(struct ata_device *drive, int mode, int single) { - byte index; - byte data; + u8 index; + u8 data; if (mode>2) /* make sure we set a valid mode */ mode = 2; @@ -206,7 +207,7 @@ printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, (data&0x3), ((data>>2)&1)); #endif - data = (byte)mode|(byte)(single<<2); + data = (u8) mode | (u8) (single << 2); OUT_BYTE(index, CY82_INDEX_PORT); OUT_BYTE(data, CY82_DATA_PORT); @@ -271,7 +272,7 @@ /* * tune ide drive - set PIO mode */ -static void cy82c693_tune_drive(struct ata_device *drive, byte pio) +static void cy82c693_tune_drive(struct ata_device *drive, u8 pio) { struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; diff -Nru a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c --- a/drivers/ide/dtc2278.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/dtc2278.c Fri Jul 26 19:58:51 2002 @@ -9,13 +9,13 @@ #include #include #include +#include #include #include -#include #include -#include "ata-timing.h" +#include "timing.h" /* * Changing this #undef to #define may solve start up problems in some systems. @@ -66,7 +66,7 @@ } } -static void tune_dtc2278(struct ata_device *drive, byte pio) +static void tune_dtc2278(struct ata_device *drive, u8 pio) { unsigned long flags; diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c --- a/drivers/ide/hpt34x.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/hpt34x.c Fri Jul 26 19:58:50 2002 @@ -21,16 +21,16 @@ #include #include #include -#include #include #include #include +#include #include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define HPT343_DEBUG_DRIVE_INFO 0 diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c --- a/drivers/ide/hpt366.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/hpt366.c Fri Jul 26 19:58:50 2002 @@ -53,18 +53,17 @@ #include #include #include -#include - #include #include #include +#include #include #include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" diff -Nru a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c --- a/drivers/ide/hptraid.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/hptraid.c Fri Jul 26 19:58:52 2002 @@ -105,10 +105,10 @@ if (!loc) return -EINVAL; val = 255; - if (put_user(val, (byte *) & loc->heads)) + if (put_user(val, (u8 *) & loc->heads)) return -EFAULT; val = 63; - if (put_user(val, (byte *) & loc->sectors)) + if (put_user(val, (u8 *) & loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors / 63 / 255; if (put_user diff -Nru a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c --- a/drivers/ide/ht6560b.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/ht6560b.c Fri Jul 26 19:58:50 2002 @@ -38,13 +38,13 @@ #include #include #include +#include #include #include -#include #include -#include "ata-timing.h" +#include "timing.h" /* #define DEBUG */ /* remove comments for DEBUG messages */ @@ -61,7 +61,7 @@ * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ #define HT_CONFIG_PORT 0x3e6 -#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8) +#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8) /* * FIFO + PREFETCH (both a/b-model) */ @@ -107,7 +107,7 @@ * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. */ -#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff) +#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff) #define HT_TIMING_DEFAULT 0xff /* @@ -194,7 +194,7 @@ return 1; } -static byte ht_pio2timings(struct ata_device *drive, byte pio) +static u8 ht_pio2timings(struct ata_device *drive, u8 pio) { int active_time, recovery_time; int active_cycles, recovery_cycles; @@ -204,7 +204,7 @@ if (pio == 255) pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); else - pio = XFER_PIO_0 + min_t(byte, pio, 4); + pio = XFER_PIO_0 + min_t(u8, pio, 4); t = ata_timing_data(pio); @@ -233,7 +233,7 @@ drive->name, pio - XFER_PIO_0, recovery_cycles, recovery_time, active_cycles, active_time); #endif - return (byte)((recovery_cycles << 4) | active_cycles); + return (u8)((recovery_cycles << 4) | active_cycles); } else { #ifdef DEBUG @@ -247,7 +247,7 @@ /* * Enable/Disable so called prefetch mode */ -static void ht_set_prefetch(struct ata_device *drive, byte state) +static void ht_set_prefetch(struct ata_device *drive, u8 state) { unsigned long flags; int t = HT_PREFETCH_MODE << 8; @@ -274,10 +274,10 @@ #endif } -static void tune_ht6560b(struct ata_device *drive, byte pio) +static void tune_ht6560b(struct ata_device *drive, u8 pio) { unsigned long flags; - byte timing; + u8 timing; switch (pio) { case 8: /* set prefetch off */ diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c --- a/drivers/ide/icside.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/icside.c Fri Jul 26 19:58:50 2002 @@ -377,7 +377,7 @@ return on; } -static int icside_set_speed(struct ata_device *drive, byte speed) +static int icside_set_speed(struct ata_device *drive, u8 speed) { return icside_config_if(drive, speed); } diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ide-cd.c Fri Jul 26 19:58:51 2002 @@ -1716,7 +1716,7 @@ static inline -void lba_to_msf (int lba, byte *m, byte *s, byte *f) +void lba_to_msf(int lba, u8 *m, u8 *s, u8 *f) { lba += CD_MSF_OFFSET; lba &= 0xffffff; /* negative lbas use only 24 bits */ @@ -1728,7 +1728,7 @@ static inline -int msf_to_lba (byte m, byte s, byte f) +int msf_to_lba(u8 m, u8 s, u8 f) { return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h --- a/drivers/ide/ide-cd.h Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/ide-cd.h Fri Jul 26 19:58:52 2002 @@ -80,7 +80,7 @@ __u8 close_tray : 1; /* can close the tray */ __u8 writing : 1; /* pseudo write in progress */ __u8 reserved : 3; - byte max_speed; /* Max speed of the drive */ + u8 max_speed; /* Max speed of the drive */ }; #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) @@ -92,7 +92,7 @@ __u8 door_locked : 1; /* We think that the drive door is locked. */ __u8 writing : 1; /* the drive is currently writing */ __u8 reserved : 4; - byte current_speed; /* Current speed of the drive */ + u8 current_speed; /* Current speed of the drive */ }; #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) @@ -132,7 +132,7 @@ } __attribute__((packed)); struct atapi_toc_entry { - byte reserved1; + u8 reserved1; #if defined(__BIG_ENDIAN_BITFIELD) __u8 adr : 4; __u8 control : 4; @@ -142,8 +142,8 @@ #else #error "Please fix " #endif - byte track; - byte reserved2; + u8 track; + u8 reserved2; union { unsigned lba; struct atapi_msf msf; @@ -176,8 +176,8 @@ #else #error "Please fix " #endif - u_char acdsc_trk; - u_char acdsc_ind; + u8 acdsc_trk; + u8 acdsc_ind; union { struct atapi_msf msf; int lba; @@ -207,7 +207,7 @@ #error "Please fix " #endif - byte page_length; + u8 page_length; #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved2 : 2; @@ -435,8 +435,8 @@ #error "Please fix " #endif - byte curlba[3]; - byte nslots; + u8 curlba[3]; + u8 nslots; __u16 slot_tablelen; }; @@ -454,7 +454,7 @@ #error "Please fix " #endif - byte reserved2[3]; + u8 reserved2[3]; }; struct atapi_changer_info { @@ -514,13 +514,11 @@ #define ABORTED_COMMAND 0x0b #define MISCOMPARE 0x0e - - /* This stuff should be in cdrom.h, since it is now generic... */ #if VERBOSE_IDE_CD_ERRORS /* The generic packet command opcodes for CD/DVD Logical Units, - * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const struct { unsigned short packet_command; const char * const text; diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/ide-disk.c Fri Jul 26 19:58:50 2002 @@ -24,8 +24,9 @@ #include #include #include -#include #include /* for invalidate_bdev() */ +#include +#include #include #include diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c --- a/drivers/ide/ide-floppy.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ide-floppy.c Fri Jul 26 19:58:51 2002 @@ -245,8 +245,8 @@ /* * Last error information */ - byte sense_key, asc, ascq; - byte ticks; /* delay this long before sending packet command */ + u8 sense_key, asc, ascq; + u8 ticks; /* delay this long before sending packet command */ int progress_indication; /* diff -Nru a/drivers/ide/ide-m8xx.c b/drivers/ide/ide-m8xx.c --- a/drivers/ide/ide-m8xx.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ide-m8xx.c Fri Jul 26 19:58:51 2002 @@ -29,8 +29,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -43,7 +44,7 @@ #include #include -#include "ata-timing.h" +#include "timing.h" static int identify (volatile unsigned char *p); static void print_fixed (volatile unsigned char *p); @@ -51,7 +52,7 @@ static int check_ide_device (unsigned long base); static int ide_interrupt_ack(struct ata_channel *); -static void m8xx_ide_tuneproc(struct ata_device *drive, byte pio); +static void m8xx_ide_tuneproc(struct ata_device *drive, u8 pio); typedef struct ide_ioport_desc { unsigned long base_off; /* Offset to PCMCIA memory */ @@ -437,7 +438,7 @@ /* Calculate PIO timings */ static void -m8xx_ide_tuneproc(struct ata_device *drive, byte pio) +m8xx_ide_tuneproc(struct ata_device *drive, u8 pio) { #if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) volatile pcmconf8xx_t *pcmp; diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c --- a/drivers/ide/ide-pci.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/ide-pci.c Fri Jul 26 19:58:52 2002 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ /* * This is the list of registered PCI chipset driver data structures. */ -static struct ata_pci_device *ata_pci_device_list = NULL; +static struct ata_pci_device *ata_pci_device_list; /* = NULL */ /* * This function supplies the data necessary to detect the particular chipset. diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c --- a/drivers/ide/ide-pmac.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/ide-pmac.c Fri Jul 26 19:58:52 2002 @@ -34,8 +34,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -51,7 +52,7 @@ #include #include #endif -#include "ata-timing.h" +#include "timing.h" #undef IDE_PMAC_DEBUG @@ -262,8 +263,8 @@ static int pmac_udma_irq_status(struct ata_device *drive); static int pmac_udma_setup(struct ata_device *drive, int map); static int pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr); -static int pmac_ide_tune_chipset(struct ata_device *drive, byte speed); -static void pmac_ide_tuneproc(struct ata_device *drive, byte pio); +static int pmac_ide_tune_chipset(struct ata_device *drive, u8 speed); +static void pmac_ide_tuneproc(struct ata_device *drive, u8 pio); static void pmac_ide_selectproc(struct ata_device *drive); #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -457,7 +458,7 @@ /* Calculate PIO timings */ static void __pmac -pmac_ide_tuneproc(struct ata_device *drive, byte pio) +pmac_ide_tuneproc(struct ata_device *drive, u8 pio) { struct ata_timing *t; int i; @@ -472,7 +473,7 @@ if (pio == 255) pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); else - pio = XFER_PIO_0 + min_t(byte, pio, 4); + pio = XFER_PIO_0 + min_t(u8, pio, 4); t = ata_timing_data(pio); @@ -523,8 +524,7 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC -static int __pmac -set_timings_udma(u32 *timings, byte speed) +static int __pmac set_timings_udma(u32 *timings, u8 speed) { unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; @@ -546,7 +546,7 @@ } static int __pmac -set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time) +set_timings_mdma(int intf_type, u32 *timings, u8 speed, int drive_cycle_time) { int cycleTime, accessTime, recTime; unsigned accessTicks, recTicks; @@ -659,7 +659,7 @@ * our, normal mdma function is supposed to be more precise */ static int __pmac -pmac_ide_tune_chipset (struct ata_device *drive, byte speed) +pmac_ide_tune_chipset (struct ata_device *drive, u8 speed) { int intf = pmac_ide_find(drive); int unit = (drive->select.b.unit & 0x01); @@ -1211,8 +1211,8 @@ static int __pmac pmac_ide_mdma_enable(struct ata_device *drive, int idx) { - byte bits = drive->id->dma_mword & 0x07; - byte feature = dma_bits_to_command(bits); + u8 bits = drive->id->dma_mword & 0x07; + u8 feature = dma_bits_to_command(bits); u32 *timings; int drive_cycle_time; struct hd_driveid *id = drive->id; @@ -1249,8 +1249,8 @@ static int __pmac pmac_ide_udma_enable(struct ata_device *drive, int idx, int high_speed) { - byte bits = drive->id->dma_ultra & 0x1f; - byte feature = udma_bits_to_command(bits, high_speed); + u8 bits = drive->id->dma_ultra & 0x1f; + u8 feature = udma_bits_to_command(bits, high_speed); u32 *timings; int ret; diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/ide-tape.c Fri Jul 26 19:58:50 2002 @@ -827,7 +827,7 @@ /* * Read position information */ - byte partition; + u8 partition; unsigned int first_frame_position; /* Current block */ unsigned int last_frame_position; unsigned int blocks_in_buffer; @@ -835,7 +835,7 @@ /* * Last error information */ - byte sense_key, asc, ascq; + u8 sense_key, asc, ascq; /* * Character device operation @@ -1237,7 +1237,7 @@ * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI */ -char *idetape_sense_key_verbose (byte idetape_sense_key) +char *idetape_sense_key_verbose(u8 idetape_sense_key) { switch (idetape_sense_key) { default: { diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/ide.c Fri Jul 26 19:58:52 2002 @@ -49,12 +49,13 @@ #endif #include #include -#include #include #include #include #include #include +#include +#include #include #include @@ -62,7 +63,7 @@ #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #include "ioctl.h" @@ -258,7 +259,7 @@ { MARK_ERR, MARK_ERR, "addr mark not found" } }; -static void dump_bits(struct ata_bit_messages *msgs, int nr, byte bits) +static void dump_bits(struct ata_bit_messages *msgs, int nr, u8 bits) { int i; int first = 1; @@ -516,258 +517,251 @@ * Issue a new request. * Caller must have already done spin_lock_irqsave(channel->lock, ...) */ -static void do_request(struct ata_channel *channel) +void do_ide_request(request_queue_t *q) { - struct ata_channel *ch; - struct ata_device *drive = NULL; - unsigned int unit; - ide_startstop_t ret; + struct ata_channel *channel = q->queuedata; - local_irq_disable(); /* necessary paranoia */ + while (!test_and_set_bit(IDE_BUSY, channel->active)) { + struct ata_channel *ch; + struct ata_device *drive = NULL; + unsigned int unit; + ide_startstop_t ret; - /* - * Select the next device which will be serviced. This selects - * only between devices on the same channel, since everything - * else will be scheduled on the queue level. - */ + /* + * Select the next device which will be serviced. This selects + * only between devices on the same channel, since everything + * else will be scheduled on the queue level. + */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *tmp = &channel->drives[unit]; + for (unit = 0; unit < MAX_DRIVES; ++unit) { + struct ata_device *tmp = &channel->drives[unit]; - if (!tmp->present) - continue; + if (!tmp->present) + continue; - /* There are no requests pending for this device. - */ - if (blk_queue_empty(&tmp->queue)) - continue; + /* There are no requests pending for this device. + */ + if (blk_queue_empty(&tmp->queue)) + continue; - /* This device still wants to remain idle. - */ - if (tmp->sleep && time_after(tmp->sleep, jiffies)) - continue; + /* This device still wants to remain idle. + */ + if (tmp->sleep && time_after(tmp->sleep, jiffies)) + continue; - /* Take this device, if there is no device choosen thus - * far or which is more urgent. - */ - if (!drive || (tmp->sleep && (!drive->sleep || time_after(drive->sleep, tmp->sleep)))) { - if (!blk_queue_plugged(&tmp->queue)) - drive = tmp; + /* Take this device, if there is no device choosen thus + * far or which is more urgent. + */ + if (!drive || (tmp->sleep && (!drive->sleep || time_after(drive->sleep, tmp->sleep)))) { + if (!blk_queue_plugged(&tmp->queue)) + drive = tmp; + } } - } - if (!drive) { - unsigned long sleep = 0; + if (!drive) { + unsigned long sleep = 0; - for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *tmp = &channel->drives[unit]; + for (unit = 0; unit < MAX_DRIVES; ++unit) { + struct ata_device *tmp = &channel->drives[unit]; - if (!tmp->present) - continue; + if (!tmp->present) + continue; - /* This device is sleeping and waiting to be serviced - * earlier than any other device we checked thus far. - */ - if (tmp->sleep && (!sleep || time_after(sleep, tmp->sleep))) - sleep = tmp->sleep; - } + /* This device is sleeping and waiting to be serviced + * earlier than any other device we checked thus far. + */ + if (tmp->sleep && (!sleep || time_after(sleep, tmp->sleep))) + sleep = tmp->sleep; + } - if (sleep) { - /* - * Take a short snooze, and then wake up again. Just - * in case there are big differences in relative - * throughputs.. don't want to hog the cpu too much. - */ + if (sleep) { + /* + * Take a short snooze, and then wake up again. Just + * in case there are big differences in relative + * throughputs.. don't want to hog the cpu too much. + */ - if (time_after(jiffies, sleep - WAIT_MIN_SLEEP)) - sleep = jiffies + WAIT_MIN_SLEEP; + if (time_after(jiffies, sleep - WAIT_MIN_SLEEP)) + sleep = jiffies + WAIT_MIN_SLEEP; #if 1 - if (timer_pending(&channel->timer)) - printk(KERN_ERR "%s: timer already active\n", __FUNCTION__); + if (timer_pending(&channel->timer)) + printk(KERN_ERR "%s: timer already active\n", __FUNCTION__); #endif - set_bit(IDE_SLEEP, channel->active); - mod_timer(&channel->timer, sleep); + set_bit(IDE_SLEEP, channel->active); + mod_timer(&channel->timer, sleep); - /* - * We purposely leave us busy while sleeping becouse we - * are prepared to handle the IRQ from it. - * - * FIXME: Make sure sleeping can't interferre with - * operations of other devices on the same channel. - */ - } else { - /* FIXME: use queue plugging instead of active to block - * upper layers from stomping on us */ - /* Ugly, but how can we sleep for the lock otherwise? - * */ - - ide_release_lock(&ide_irq_lock);/* for atari only */ - clear_bit(IDE_BUSY, channel->active); - - /* All requests are done. - * - * Disable IRQs from the last drive on this channel, to - * make sure that it wan't throw stones at us when we - * are not prepared to take them. - */ - - if (channel->drive && !channel->drive->using_tcq) - ata_irq_enable(channel->drive, 0); - } + /* + * We purposely leave us busy while sleeping becouse we + * are prepared to handle the IRQ from it. + * + * FIXME: Make sure sleeping can't interferre with + * operations of other devices on the same channel. + */ + } else { + /* FIXME: use queue plugging instead of active to block + * upper layers from stomping on us */ + /* Ugly, but how can we sleep for the lock otherwise? + * */ + + ide_release_lock(&ide_irq_lock);/* for atari only */ + clear_bit(IDE_BUSY, channel->active); + + /* All requests are done. + * + * Disable IRQs from the last drive on this channel, to + * make sure that it wan't throw stones at us when we + * are not prepared to take them. + */ - return; - } + if (channel->drive && !channel->drive->using_tcq) + ata_irq_enable(channel->drive, 0); + } - /* Remember the last drive we where acting on. - */ - ch = drive->channel; - ch->drive = drive; + return; + } - /* Feed commands to a drive until it barfs. - */ - do { - struct request *rq = NULL; - sector_t block; + /* Remember the last drive we where acting on. + */ + ch = drive->channel; + ch->drive = drive; - /* Abort early if we can't queue another command. for non tcq, - * ata_can_queue is always 1 since we never get here unless the - * drive is idle. + /* Feed commands to a drive until it barfs. */ + do { + struct request *rq = NULL; + sector_t block; - if (!ata_can_queue(drive)) { - if (!ata_pending_commands(drive)) { - clear_bit(IDE_BUSY, ch->active); - if (drive->using_tcq) - ata_irq_enable(drive, 0); - } - break; - } + /* Abort early if we can't queue another command. for non tcq, + * ata_can_queue is always 1 since we never get here unless the + * drive is idle. + */ - drive->sleep = 0; + if (!ata_can_queue(drive)) { + if (!ata_pending_commands(drive)) { + clear_bit(IDE_BUSY, ch->active); + if (drive->using_tcq) + ata_irq_enable(drive, 0); + } + break; + } - if (test_bit(IDE_DMA, ch->active)) { - printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name); - break; - } + drive->sleep = 0; - /* There's a small window between where the queue could be - * replugged while we are in here when using tcq (in which case - * the queue is probably empty anyways...), so check and leave - * if appropriate. When not using tcq, this is still a severe - * BUG! - */ + if (test_bit(IDE_DMA, ch->active)) { + printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name); + break; + } - if (blk_queue_plugged(&drive->queue)) { - BUG_ON(!drive->using_tcq); - break; - } + /* There's a small window between where the queue could be + * replugged while we are in here when using tcq (in which case + * the queue is probably empty anyways...), so check and leave + * if appropriate. When not using tcq, this is still a severe + * BUG! + */ - if (!(rq = elv_next_request(&drive->queue))) { - if (!ata_pending_commands(drive)) { - clear_bit(IDE_BUSY, ch->active); - if (drive->using_tcq) - ata_irq_enable(drive, 0); + if (blk_queue_plugged(&drive->queue)) { + BUG_ON(!drive->using_tcq); + break; } - drive->rq = NULL; - break; - } + if (!(rq = elv_next_request(&drive->queue))) { + if (!ata_pending_commands(drive)) { + clear_bit(IDE_BUSY, ch->active); + if (drive->using_tcq) + ata_irq_enable(drive, 0); + } + drive->rq = NULL; - /* If there are queued commands, we can't start a - * non-fs request (really, a non-queuable command) - * until the queue is empty. - */ - if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive)) - break; + break; + } - drive->rq = rq; + /* If there are queued commands, we can't start a + * non-fs request (really, a non-queuable command) + * until the queue is empty. + */ + if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive)) + break; - spin_unlock(ch->lock); - /* allow other IRQs while we start this request */ - local_irq_enable(); + drive->rq = rq; - /* - * This initiates handling of a new I/O request. - */ + spin_unlock(ch->lock); + /* allow other IRQs while we start this request */ + local_irq_enable(); + + /* + * This initiates handling of a new I/O request. + */ - BUG_ON(!(rq->flags & REQ_STARTED)); + BUG_ON(!(rq->flags & REQ_STARTED)); #ifdef DEBUG - printk("%s: %s: current=0x%08lx\n", ch->name, __FUNCTION__, (unsigned long) rq); + printk("%s: %s: current=0x%08lx\n", ch->name, __FUNCTION__, (unsigned long) rq); #endif - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) - goto kill_rq; + /* bail early if we've exceeded max_failures */ + if (drive->max_failures && (drive->failures > drive->max_failures)) + goto kill_rq; - block = rq->sector; + block = rq->sector; - /* Strange disk manager remap. - */ - if (rq->flags & REQ_CMD) - if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY) - block += drive->sect0; + /* Strange disk manager remap. + */ + if (rq->flags & REQ_CMD) + if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY) + block += drive->sect0; - /* Yecch - this will shift the entire interval, possibly killing some - * innocent following sector. - */ - if (block == 0 && drive->remap_0_to_1 == 1) - block = 1; /* redirect MBR access to EZ-Drive partn table */ + /* Yecch - this will shift the entire interval, possibly killing some + * innocent following sector. + */ + if (block == 0 && drive->remap_0_to_1 == 1) + block = 1; /* redirect MBR access to EZ-Drive partn table */ - ata_select(drive, 0); - ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT, - WAIT_READY, rq); + ata_select(drive, 0); + ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT, + WAIT_READY, rq); - if (ret != ATA_OP_READY) { - printk(KERN_ERR "%s: drive not ready for command\n", drive->name); + if (ret != ATA_OP_READY) { + printk(KERN_ERR "%s: drive not ready for command\n", drive->name); - goto kill_rq; - } + goto kill_rq; + } - if (!ata_ops(drive)) { - printk(KERN_WARNING "%s: device type %d not supported\n", - drive->name, drive->type); - goto kill_rq; - } + if (!ata_ops(drive)) { + printk(KERN_WARNING "%s: device type %d not supported\n", + drive->name, drive->type); + goto kill_rq; + } - /* The normal way of execution is to pass and execute the request - * handler down to the device type driver. - */ + /* The normal way of execution is to pass and execute the request + * handler down to the device type driver. + */ - if (ata_ops(drive)->do_request) { - ret = ata_ops(drive)->do_request(drive, rq, block); - } else { + if (ata_ops(drive)->do_request) { + ret = ata_ops(drive)->do_request(drive, rq, block); + } else { kill_rq: - if (ata_ops(drive) && ata_ops(drive)->end_request) - ata_ops(drive)->end_request(drive, rq, 0); - else - ata_end_request(drive, rq, 0, 0); - ret = ATA_OP_FINISHED; + if (ata_ops(drive) && ata_ops(drive)->end_request) + ata_ops(drive)->end_request(drive, rq, 0); + else + ata_end_request(drive, rq, 0, 0); + ret = ATA_OP_FINISHED; - } - spin_lock_irq(ch->lock); - - /* continue if command started, so we are busy */ - } while (ret != ATA_OP_CONTINUES); - /* make sure the BUSY bit is set */ - /* FIXME: perhaps there is some place where we miss to set it? */ -// set_bit(IDE_BUSY, ch->active); -} - -void do_ide_request(request_queue_t *q) -{ - struct ata_channel *ch = q->queuedata; + } + spin_lock_irq(ch->lock); - while (!test_and_set_bit(IDE_BUSY, ch->active)) { - do_request(ch); + /* continue if command started, so we are busy */ + } while (ret != ATA_OP_CONTINUES); + /* make sure the BUSY bit is set */ + /* FIXME: perhaps there is some place where we miss to set it? */ + // set_bit(IDE_BUSY, ch->active); } } /* * This is our timeout function for all drive operations. But note that it can * also be invoked as a result of a "sleep" operation triggered by the - * mod_timer() call in do_request. + * mod_timer() call in do_ide_request. * * FIXME: This should take a drive context instead of a channel. * FIXME: This should not explicitly reenter the request handling engine. @@ -892,7 +886,8 @@ if (ret == ATA_OP_FINISHED) { /* Reenter the request handling engine. */ - do_request(ch); + clear_bit(IDE_BUSY, ch->active); + do_ide_request(&drive->queue); } } spin_unlock_irqrestore(ch->lock, flags); @@ -1049,9 +1044,10 @@ * another interrupt. */ - if (!ch->handler) - do_request(ch); - else + if (!ch->handler) { + clear_bit(IDE_BUSY, ch->active); + do_ide_request(&drive->queue); + } else printk("%s: %s: huh? expected NULL handler on exit\n", drive->name, __FUNCTION__); } diff -Nru a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c --- a/drivers/ide/ioctl.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ioctl.c Fri Jul 26 19:58:51 2002 @@ -26,7 +26,7 @@ #include #include #include - +#include #include #include @@ -230,13 +230,13 @@ if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)) return -EINVAL; - if (put_user(drive->bios_head, (byte *) &loc->heads)) + if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT; - if (put_user(drive->bios_sect, (byte *) &loc->sectors)) + if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT; - if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) + if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT; if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect, @@ -283,18 +283,18 @@ case HDIO_GET_NICE: - return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | - drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP, + return put_user(drive->dsc_overlap | drive->atapi_overlap << 1, (long *) arg); case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP)))) + if (arg != (arg & 1)) return -EPERM; - drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1; + drive->dsc_overlap = arg & 1; + /* Only CD-ROM's and tapes support DSC overlap. */ if (drive->dsc_overlap && !(drive->type == ATA_ROM || drive->type == ATA_TAPE)) { drive->dsc_overlap = 0; diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c --- a/drivers/ide/it8172.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/it8172.c Fri Jul 26 19:58:50 2002 @@ -33,16 +33,15 @@ #include #include #include -#include -#include #include #include +#include #include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" diff -Nru a/drivers/ide/main.c b/drivers/ide/main.c --- a/drivers/ide/main.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/main.c Fri Jul 26 19:58:50 2002 @@ -35,12 +35,13 @@ #endif #include #include -#include #include #include #include #include #include +#include +#include #include #include @@ -48,7 +49,7 @@ #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #include "ioctl.h" @@ -1068,7 +1069,6 @@ } drive->revalidate = 1; - drive->suspend_reset = 0; return 0; } diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c --- a/drivers/ide/ns87415.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/ns87415.c Fri Jul 26 19:58:51 2002 @@ -126,7 +126,7 @@ { struct pci_dev *dev = hwif->pci_dev; unsigned int ctrl, using_inta; - byte progif; + u8 progif; /* Set a good latency timer and cache line size value. */ (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); diff -Nru a/drivers/ide/opti621.c b/drivers/ide/opti621.c --- a/drivers/ide/opti621.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/opti621.c Fri Jul 26 19:58:50 2002 @@ -99,7 +99,7 @@ #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define OPTI621_MAX_PIO 3 @@ -137,7 +137,7 @@ /* there are stored pio numbers from other calls of opti621_tune_drive */ -static void compute_pios(struct ata_device *drive, byte pio) +static void compute_pios(struct ata_device *drive, u8 pio) /* Store values into drive->drive_data * second_contr - 0 for primary controller, 1 for secondary * slave_drive - 0 -> pio is for master, 1 -> pio is for slave @@ -178,7 +178,7 @@ return ((time*bus_speed+999999)/1000000); } -static void write_reg(byte value, int reg) +static void write_reg(u8 value, int reg) /* Write value to register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). @@ -192,14 +192,14 @@ outb(0x83, reg_base+2); } -static byte read_reg(int reg) +static u8 read_reg(int reg) /* Read value from register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). * This is from setupvic.exe program. */ { - byte ret; + u8 ret; inw(reg_base+1); inw(reg_base+1); outb(3, reg_base+2); @@ -245,16 +245,16 @@ } /* Main tune procedure, called from tuneproc. */ -static void opti621_tune_drive(struct ata_device *drive, byte pio) +static void opti621_tune_drive(struct ata_device *drive, u8 pio) { /* primary and secondary drives share some registers, * so we have to program both drives */ unsigned long flags; - byte pio1, pio2; + u8 pio1, pio2; pio_clocks_t first, second; int ax, drdy; - byte cycle1, cycle2, misc; + u8 cycle1, cycle2, misc; struct ata_channel *hwif = drive->channel; /* sets drive->drive_data for both drives */ diff -Nru a/drivers/ide/pcidma.c b/drivers/ide/pcidma.c --- a/drivers/ide/pcidma.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/pcidma.c Fri Jul 26 19:58:50 2002 @@ -24,10 +24,11 @@ #include #include #include -#include #include +#include +#include -#include "ata-timing.h" +#include "timing.h" #include #include diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c --- a/drivers/ide/pdc202xx.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/pdc202xx.c Fri Jul 26 19:58:52 2002 @@ -48,16 +48,16 @@ #include #include #include -#include #include #include #include +#include #include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define PDC202XX_DEBUG_DRIVE_INFO 0 @@ -105,7 +105,7 @@ /* MC3-MC0 - DMA "C" timing */ }; -static void pdc_dump_bits(struct pdc_bit_messages *msgs, byte bits) +static void pdc_dump_bits(struct pdc_bit_messages *msgs, u8 bits) { int i; @@ -174,7 +174,7 @@ return map; } -static int pdc202xx_tune_chipset(struct ata_device *drive, byte speed) +static int pdc202xx_tune_chipset(struct ata_device *drive, u8 speed) { struct pci_dev *dev = drive->channel->pci_dev; u32 drive_conf; @@ -315,7 +315,7 @@ OUT_BYTE(value, reg); \ mdelay(delay); -static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed) +static int pdc202xx_new_tune_chipset(struct ata_device *drive, u8 speed) { struct ata_channel *hwif = drive->channel; u32 high_16 = pci_resource_start(hwif->pci_dev, 4); @@ -453,7 +453,7 @@ if (pio == 255) speed = ata_best_pio_mode(drive); else - speed = XFER_PIO_0 + min_t(byte, pio, 4); + speed = XFER_PIO_0 + min_t(u8, pio, 4); pdc202xx_tune_chipset(drive, speed); } @@ -695,7 +695,7 @@ break; default: if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { - byte irq = 0, irq2 = 0; + u8 irq = 0, irq2 = 0; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); pci_read_config_byte(dev, (PCI_INTERRUPT_LINE) | 0x80, &irq2); /* 0xbc */ diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c --- a/drivers/ide/pdc4030.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/pdc4030.c Fri Jul 26 19:58:51 2002 @@ -175,10 +175,10 @@ * by command F0. They all have the same success/failure notification - * 'P' (=0x50) on success, 'p' (=0x70) on failure. */ -int pdc4030_cmd(struct ata_device *drive, byte cmd) +int pdc4030_cmd(struct ata_device *drive, u8 cmd) { unsigned long timeout, timer; - byte status_val; + u8 status_val; promise_selectproc(drive); /* redundant? */ outb(0xF3, IDE_SECTOR_REG); diff -Nru a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c --- a/drivers/ide/pdcraid.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/pdcraid.c Fri Jul 26 19:58:51 2002 @@ -135,11 +135,11 @@ return -EINVAL; if (put_user (raid[minor].geom.heads, - (byte *) & loc->heads)) + (u8 *) & loc->heads)) return -EFAULT; if (put_user (raid[minor].geom.sectors, - (byte *) & loc->sectors)) + (u8 *) & loc->sectors)) return -EFAULT; if (put_user (bios_cyl, (unsigned short *) &loc->cylinders)) diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c --- a/drivers/ide/piix.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/piix.c Fri Jul 26 19:58:52 2002 @@ -45,11 +45,12 @@ #include #include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define PIIX_IDETIM0 0x40 @@ -240,7 +241,7 @@ return; } - piix_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); + piix_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); } #ifdef CONFIG_BLK_DEV_IDEDMA diff -Nru a/drivers/ide/probe.c b/drivers/ide/probe.c --- a/drivers/ide/probe.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/probe.c Fri Jul 26 19:58:50 2002 @@ -28,9 +28,10 @@ #include #include #include -#include #include #include +#include +#include #include #include @@ -302,18 +303,18 @@ /* * All hosts that use the 80c ribbon must use this! */ -byte eighty_ninty_three(struct ata_device *drive) +int eighty_ninty_three(struct ata_device *drive) { - return ((u8) ((drive->channel->udma_four) && + return ((drive->channel->udma_four) && #ifndef CONFIG_IDEDMA_IVB (drive->id->hw_config & 0x4000) && #endif - (drive->id->hw_config & 0x6000)) ? 1 : 0); + (drive->id->hw_config & 0x6000)) ? 1 : 0; } /* FIXME: Channel lock should be held. */ -int ide_config_drive_speed(struct ata_device *drive, byte speed) +int ide_config_drive_speed(struct ata_device *drive, u8 speed) { struct ata_channel *ch = drive->channel; int ret; diff -Nru a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c --- a/drivers/ide/qd65xx.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/qd65xx.c Fri Jul 26 19:58:51 2002 @@ -29,12 +29,13 @@ #include #include #include +#include #include #include -#include + #include -#include "ata-timing.h" +#include "timing.h" #include "qd65xx.h" /* @@ -85,7 +86,7 @@ static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ -static void qd_write_reg(byte content, byte reg) +static void qd_write_reg(u8 content, unsigned int reg) { unsigned long flags; @@ -95,10 +96,10 @@ restore_flags(flags); /* all CPUs */ } -byte __init qd_read_reg(byte reg) +static u8 __init qd_read_reg(unsigned int reg) { unsigned long flags; - byte read; + u8 read; save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ @@ -115,8 +116,8 @@ static void qd_select(struct ata_device *drive) { - byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | - (QD_TIMREG(drive) & 0x02); + u8 index = (((QD_TIMREG(drive)) & 0x80 ) >> 7) | + (QD_TIMREG(drive) & 0x02); if (timings[index] != QD_TIMING(drive)) qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); @@ -130,9 +131,9 @@ * upper nibble represents recovery time, in count of VLB clocks */ -static byte qd6500_compute_timing(struct ata_channel *hwif, int active_time, int recovery_time) +static u8 qd6500_compute_timing(struct ata_channel *hwif, int active_time, int recovery_time) { - byte active_cycle,recovery_cycle; + u8 active_cycle,recovery_cycle; if (system_bus_speed <= 33333) { active_cycle = 9 - IDE_IN(active_time * system_bus_speed / 1000000 + 1, 2, 9); @@ -151,12 +152,12 @@ * idem for qd6580 */ -static byte qd6580_compute_timing(int active_time, int recovery_time) +static u8 qd6580_compute_timing(int active_time, int recovery_time) { - byte active_cycle = 17 - IDE_IN(active_time * system_bus_speed / 1000000 + 1, 2, 17); - byte recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 2, 15); + u8 active_cycle = 17 - IDE_IN(active_time * system_bus_speed / 1000000 + 1, 2, 17); + u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 2, 15); - return((recovery_cycle<<4) | active_cycle); + return (recovery_cycle<<4) | active_cycle; } /* @@ -205,7 +206,7 @@ * records the timing, and enables selectproc as needed */ -static void qd_set_timing(struct ata_device *drive, byte timing) +static void qd_set_timing(struct ata_device *drive, u8 timing) { struct ata_channel *hwif = drive->channel; @@ -224,7 +225,7 @@ * qd6500_tune_drive */ -static void qd6500_tune_drive(struct ata_device *drive, byte pio) +static void qd6500_tune_drive(struct ata_device *drive, u8 pio) { int active_time = 175; int recovery_time = 415; /* worst case values from the dos driver */ @@ -245,7 +246,7 @@ * qd6580_tune_drive */ -static void qd6580_tune_drive(struct ata_device *drive, byte pio) +static void qd6580_tune_drive(struct ata_device *drive, u8 pio) { struct ata_timing *t; int base = drive->channel->select_data; @@ -257,7 +258,7 @@ if (pio == 255) pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); else - pio = XFER_PIO_0 + min_t(byte, pio, 4); + pio = XFER_PIO_0 + min_t(u8, pio, 4); t = ata_timing_data(pio); @@ -305,8 +306,8 @@ static int __init qd_testreg(int port) { - byte savereg; - byte readreg; + u8 savereg; + u8 readreg; unsigned long flags; save_flags(flags); /* all CPUs */ @@ -333,7 +334,7 @@ * called to setup an ata channel : adjusts attributes & links for tuning */ -void __init qd_setup(int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (struct ata_device *, byte pio)) +void __init qd_setup(int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (struct ata_device *, u8 pio)) { struct ata_channel *hwif = &ide_hwifs[unit]; @@ -354,7 +355,7 @@ */ void __init qd_unsetup(int unit) { struct ata_channel *hwif = &ide_hwifs[unit]; - byte config = hwif->config_data; + u8 config = hwif->config_data; int base = hwif->select_data; void *tuneproc = (void *) hwif->tuneproc; @@ -390,7 +391,7 @@ int __init qd_probe(int base) { - byte config; + u8 config; int unit; config = qd_read_reg(QD_CONFIG_PORT); @@ -417,7 +418,7 @@ } if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) { - byte control; + u8 control; if (qd_testreg(base) || qd_testreg(base+0x02)) return 1; /* bad registers */ diff -Nru a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h --- a/drivers/ide/qd65xx.h Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/qd65xx.h Fri Jul 26 19:58:51 2002 @@ -34,8 +34,8 @@ #define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) #define QD_CONTROL(hwif) (((hwif)->config_data & 0xff00) >> 8) -#define QD_TIMING(drive) (byte)(((drive)->drive_data) & 0x00ff) -#define QD_TIMREG(drive) (byte)((((drive)->drive_data) & 0xff00) >> 8) +#define QD_TIMING(drive) (u8)(((drive)->drive_data) & 0x00ff) +#define QD_TIMREG(drive) (u8)((((drive)->drive_data) & 0xff00) >> 8) #define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) #define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) diff -Nru a/drivers/ide/quirks.c b/drivers/ide/quirks.c --- a/drivers/ide/quirks.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/quirks.c Fri Jul 26 19:58:50 2002 @@ -24,8 +24,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -153,14 +154,14 @@ /* Consult the list of known "good" drives */ list = good_dma_drives; while (*list) { - if (!strcmp(*list++,id->model)) + if (!strcmp(*list++, id->model)) return 1; } } else { /* Consult the list of known "bad" drives */ list = bad_dma_drives; while (*list) { - if (!strcmp(*list++,id->model)) { + if (!strcmp(*list++, id->model)) { printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); return 1; diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c --- a/drivers/ide/serverworks.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/serverworks.c Fri Jul 26 19:58:51 2002 @@ -85,14 +85,14 @@ #include #include #include -#include #include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #undef SVWKS_DEBUG_DRIVE_INFO diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c --- a/drivers/ide/sis5513.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/sis5513.c Fri Jul 26 19:58:51 2002 @@ -44,13 +44,13 @@ #include #include #include -#include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" /* When DEBUG is defined it outputs initial PCI config register @@ -84,7 +84,7 @@ Fewer might be used depending on the actual chipset */ static unsigned char ide_regs_copy[0x58]; -static byte sis5513_max_config_register(void) { +static u8 sis5513_max_config_register(void) { switch(chipset_family) { case ATA_00: case ATA_16: return 0x4f; @@ -100,9 +100,9 @@ /* Read config registers, print differences from previous read */ static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) { int i; - byte reg_val; - byte changed=0; - byte max = sis5513_max_config_register(); + u8 reg_val; + u8 changed = 0; + u8 max = sis5513_max_config_register(); printk("SIS5513: %s, changed registers:\n", info); for(i=0; i<=max; i++) { @@ -121,9 +121,10 @@ } /* Load config registers, no printing */ -static void sis5513_load_registers(struct pci_dev* dev) { +static void sis5513_load_registers(struct pci_dev* dev) +{ int i; - byte max = sis5513_max_config_register(); + u8 max = sis5513_max_config_register(); for(i=0; i<=max; i++) { pci_read_config_byte(dev, i, &(ide_regs_copy[i])); @@ -131,14 +132,15 @@ } /* Print a register */ -static void sis5513_print_register(int reg) { +static void sis5513_print_register(int reg) +{ printk(" %0#x:%0#x", reg, ide_regs_copy[reg]); } /* Print valuable registers */ static void sis5513_print_registers(struct pci_dev* dev, char* marker) { int i; - byte max = sis5513_max_config_register(); + u8 max = sis5513_max_config_register(); sis5513_load_registers(dev); printk("SIS5513 %s\n", marker); @@ -193,9 +195,9 @@ /* Cycle time bits and values vary accross chip dma capabilities These three arrays hold the register layout and the values to set. Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ -static byte cycle_time_offset[] = {0,0,5,4,4,0,0}; -static byte cycle_time_range[] = {0,0,2,3,3,4,4}; -static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = { +static u8 cycle_time_offset[] = {0,0,5,4,4,0,0}; +static u8 cycle_time_range[] = {0,0,2,3,3,4,4}; +static u8 cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = { {0,0,0,0,0,0}, /* no udma */ {0,0,0,0,0,0}, /* no udma */ {3,2,1,0,0,0}, @@ -317,7 +319,7 @@ struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; - byte drive_pci, reg; + u8 drive_pci, reg; #ifdef DEBUG sis5513_load_verify_registers(dev, "sis5513_tune_chipset start"); @@ -418,7 +420,7 @@ #endif if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) { - byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */ + u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); } } @@ -427,7 +429,7 @@ 1/ tell IDE channels to operate in Compabitility mode only 2/ tell old chips to allow per drive IDE timings */ if (host_dev) { - byte reg; + u8 reg; switch(chipset_family) { case ATA_133: case ATA_100: diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c --- a/drivers/ide/sl82c105.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/sl82c105.c Fri Jul 26 19:58:51 2002 @@ -19,14 +19,14 @@ #include #include #include -#include #include +#include #include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" /* @@ -82,7 +82,7 @@ if (pio == 255) xfer_mode = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); else - xfer_mode = XFER_PIO_0 + min_t(byte, pio, 4); + xfer_mode = XFER_PIO_0 + min_t(u8, pio, 4); t = ata_timing_data(xfer_mode); @@ -258,7 +258,7 @@ * We only deal with PIO mode here - DMA mode 'using_dma' is not * initialised at the point that this function is called. */ -static void tune_sl82c105(struct ata_device *drive, byte pio) +static void tune_sl82c105(struct ata_device *drive, u8 pio) { config_for_pio(drive, pio, 1); @@ -320,7 +320,7 @@ static void __init sl82c105_init_dma(struct ata_channel *ch, unsigned long dma_base) { unsigned int bridge_rev; - byte dma_state; + u8 dma_state; dma_state = inb(dma_base + 2); bridge_rev = sl82c105_bridge_revision(ch->pci_dev); diff -Nru a/drivers/ide/tcq.c b/drivers/ide/tcq.c --- a/drivers/ide/tcq.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/tcq.c Fri Jul 26 19:58:52 2002 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/ide/timing.h b/drivers/ide/timing.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/ide/timing.h Fri Jul 26 19:58:52 2002 @@ -0,0 +1,83 @@ +/* + * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord + * Copyright (C) 1999-2001 Vojtech Pavlik + * + * 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 + */ + +#define XFER_PIO_5 0x0d +#define XFER_UDMA_SLOW 0x4f + +struct ata_timing { + short mode; + short setup; /* t1 */ + short act8b; /* t2 for 8-bit io */ + short rec8b; /* t2i for 8-bit io */ + short cyc8b; /* t0 for 8-bit io */ + short active; /* t2 or tD */ + short recover; /* t2i or tK */ + short cycle; /* t0 */ + short udma; /* t2CYCTYP/2 */ +}; + +extern struct ata_timing ata_timing[]; + +#define IDE_TIMING_SETUP 0x01 +#define IDE_TIMING_ACT8B 0x02 +#define IDE_TIMING_REC8B 0x04 +#define IDE_TIMING_CYC8B 0x08 +#define IDE_TIMING_8BIT 0x0e +#define IDE_TIMING_ACTIVE 0x10 +#define IDE_TIMING_RECOVER 0x20 +#define IDE_TIMING_CYCLE 0x40 +#define IDE_TIMING_UDMA 0x80 +#define IDE_TIMING_ALL 0xff + +#define FIT(v,x,y) max_t(int,min_t(int,v,y),x) +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) + +/* see hpt366.c for details */ +#define XFER_UDMA_66_3 0x100 +#define XFER_UDMA_66_4 0x200 + +#define XFER_MODE 0xff0 +#define XFER_UDMA_133 0x800 +#define XFER_UDMA_100 0x400 +#define XFER_UDMA_66 0x300 +#define XFER_UDMA 0x040 +#define XFER_MWDMA 0x020 +#define XFER_SWDMA 0x010 +#define XFER_EPIO 0x001 +#define XFER_PIO 0x000 + +#define XFER_UDMA_ALL 0xf40 +#define XFER_UDMA_80W 0xf00 + +/* External interface to host chips channel timing setup. + * + * It's a bit elaborate due to the legacy we have to bear. + */ + +extern short ata_timing_mode(struct ata_device *drive, int map); +extern void ata_timing_quantize(struct ata_timing *t, struct ata_timing *q, + int T, int UT); +extern void ata_timing_merge(struct ata_timing *a, struct ata_timing *b, + struct ata_timing *m, unsigned int what); +void ata_timing_merge_8bit(struct ata_timing *t); +extern struct ata_timing* ata_timing_data(short speed); +extern int ata_timing_compute(struct ata_device *drive, + short speed, struct ata_timing *t, int T, int UT); +extern u8 ata_best_pio_mode(struct ata_device *drive); diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c --- a/drivers/ide/trm290.c Fri Jul 26 19:58:50 2002 +++ b/drivers/ide/trm290.c Fri Jul 26 19:58:50 2002 @@ -251,7 +251,7 @@ { unsigned int cfgbase = 0; unsigned long flags; - byte reg; + u8 reg; struct pci_dev *dev = hwif->pci_dev; hwif->chipset = ide_trm290; diff -Nru a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c --- a/drivers/ide/umc8672.c Fri Jul 26 19:58:51 2002 +++ b/drivers/ide/umc8672.c Fri Jul 26 19:58:51 2002 @@ -46,13 +46,13 @@ #include #include #include +#include #include #include -#include #include -#include "ata-timing.h" +#include "timing.h" /* * Default speeds. These can be changed with "auto-tune" and/or hdparm. @@ -62,11 +62,11 @@ #define UMC_DRIVE2 1 /* 11 = Fastest Speed */ #define UMC_DRIVE3 1 /* In case of crash reduce speed */ -static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3}; -static const byte pio_to_umc [5] = {0,3,7,10,11}; /* rough guesses */ +static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3}; +static const u8 pio_to_umc[5] = {0,3,7,10,11}; /* rough guesses */ /* 0 1 2 3 4 5 6 7 8 9 10 11 */ -static const byte speedtab [3][12] = { +static const u8 speedtab[3][12] = { {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}}; @@ -77,13 +77,13 @@ outb_p (wert,0x109); } -static inline byte in_umc (char port) +static inline u8 in_umc (char port) { outb_p (port,0x108); return inb_p (0x109); } -static void umc_set_speeds (byte speeds[]) +static void umc_set_speeds(u8 speeds[]) { int i, tmp; @@ -106,14 +106,14 @@ speeds[0], speeds[1], speeds[2], speeds[3]); } -static void tune_umc(struct ata_device *drive, byte pio) +static void tune_umc(struct ata_device *drive, u8 pio) { unsigned long flags; if (pio == 255) pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; else - pio = min_t(byte, pio, 4); + pio = min_t(u8, pio, 4); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); save_flags(flags); /* all CPUs */ diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c --- a/drivers/ide/via82cxxx.c Fri Jul 26 19:58:52 2002 +++ b/drivers/ide/via82cxxx.c Fri Jul 26 19:58:52 2002 @@ -65,11 +65,12 @@ #include #include #include +#include #include #include -#include "ata-timing.h" +#include "timing.h" #include "pcihost.h" #define VIA_IDE_ENABLE 0x40 @@ -217,7 +218,7 @@ return; } - via_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); + via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); } #ifdef CONFIG_BLK_DEV_IDEDMA diff -Nru a/drivers/input/evbug.c b/drivers/input/evbug.c --- a/drivers/input/evbug.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/evbug.c Fri Jul 26 19:58:51 2002 @@ -80,11 +80,11 @@ MODULE_DEVICE_TABLE(input, evbug_ids); static struct input_handler evbug_handler = { - event: evbug_event, - connect: evbug_connect, - disconnect: evbug_disconnect, - name: "evbug", - id_table: evbug_ids, + .event = evbug_event, + .connect = evbug_connect, + .disconnect = evbug_disconnect, + .name = "evbug", + .id_table = evbug_ids, }; int __init evbug_init(void) diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c --- a/drivers/input/evdev.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/evdev.c Fri Jul 26 19:58:52 2002 @@ -233,7 +233,7 @@ struct evdev_list *list = file->private_data; struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; - int retval, t, u; + int t, u; if (!evdev->exist) return -ENODEV; @@ -243,24 +243,20 @@ return put_user(EV_VERSION, (int *) arg); case EVIOCGID: - if ((retval = put_user(dev->idbus, ((short *) arg) + 0))) return retval; - if ((retval = put_user(dev->idvendor, ((short *) arg) + 1))) return retval; - if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval; - if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval; - return 0; + return copy_to_user((void *) arg, &dev->id, sizeof(struct input_id)); case EVIOCGREP: - if ((retval = put_user(dev->rep[0], ((int *) arg) + 0))) return retval; - if ((retval = put_user(dev->rep[1], ((int *) arg) + 1))) return retval; + if (put_user(dev->rep[0], ((int *) arg) + 0)) return -EFAULT; + if (put_user(dev->rep[1], ((int *) arg) + 1)) return -EFAULT; return 0; case EVIOCSREP: - if ((retval = get_user(dev->rep[0], ((int *) arg) + 0))) return retval; - if ((retval = get_user(dev->rep[1], ((int *) arg) + 1))) return retval; + if (get_user(dev->rep[0], ((int *) arg) + 0)) return -EFAULT; + if (get_user(dev->rep[1], ((int *) arg) + 1)) return -EFAULT; return 0; case EVIOCGKEYCODE: - if ((retval = get_user(t, ((int *) arg) + 0))) return retval; + if (get_user(t, ((int *) arg) + 0)) return -EFAULT; if (t < 0 || t > dev->keycodemax) return -EINVAL; switch (dev->keycodesize) { case 1: u = *(u8*)(dev->keycode + t); break; @@ -268,13 +264,13 @@ case 4: u = *(u32*)(dev->keycode + t * 4); break; default: return -EINVAL; } - if ((retval = put_user(u, ((int *) arg) + 1))) return retval; + if (put_user(u, ((int *) arg) + 1)) return -EFAULT; return 0; case EVIOCSKEYCODE: - if ((retval = get_user(t, ((int *) arg) + 0))) return retval; + if (get_user(t, ((int *) arg) + 0)) return -EFAULT; if (t < 0 || t > dev->keycodemax) return -EINVAL; - if ((retval = get_user(u, ((int *) arg) + 1))) return retval; + if (get_user(u, ((int *) arg) + 1)) return -EFAULT; switch (dev->keycodesize) { case 1: *(u8*)(dev->keycode + t) = u; break; case 2: *(u16*)(dev->keycode + t * 2) = u; break; @@ -288,13 +284,11 @@ struct ff_effect effect; int err; - if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect))) { + if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect))) return -EFAULT; - } err = dev->upload_effect(dev, &effect); - if (put_user(effect.id, &(((struct ff_effect*)arg)->id))) { + if (put_user(effect.id, &(((struct ff_effect*)arg)->id))) return -EFAULT; - } return err; } else return -ENOSYS; @@ -306,8 +300,8 @@ else return -ENOSYS; case EVIOCGEFFECTS: - if ((retval = put_user(dev->ff_effects_max, (int*) arg))) - return retval; + if (put_user(dev->ff_effects_max, (int*) arg)) + return -EFAULT; return 0; default: @@ -384,11 +378,24 @@ int t = _IOC_NR(cmd) & ABS_MAX; - if ((retval = put_user(dev->abs[t], ((int *) arg) + 0))) return retval; - if ((retval = put_user(dev->absmin[t], ((int *) arg) + 1))) return retval; - if ((retval = put_user(dev->absmax[t], ((int *) arg) + 2))) return retval; - if ((retval = put_user(dev->absfuzz[t], ((int *) arg) + 3))) return retval; - if ((retval = put_user(dev->absflat[t], ((int *) arg) + 4))) return retval; + if (put_user(dev->abs[t], ((int *) arg) + 0)) return -EFAULT; + if (put_user(dev->absmin[t], ((int *) arg) + 1)) return -EFAULT; + if (put_user(dev->absmax[t], ((int *) arg) + 2)) return -EFAULT; + if (put_user(dev->absfuzz[t], ((int *) arg) + 3)) return -EFAULT; + if (put_user(dev->absflat[t], ((int *) arg) + 4)) return -EFAULT; + + return 0; + } + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { + + int t = _IOC_NR(cmd) & ABS_MAX; + + if (get_user(dev->abs[t], ((int *) arg) + 0)) return -EFAULT; + if (get_user(dev->absmin[t], ((int *) arg) + 1)) return -EFAULT; + if (get_user(dev->absmax[t], ((int *) arg) + 2)) return -EFAULT; + if (get_user(dev->absfuzz[t], ((int *) arg) + 3)) return -EFAULT; + if (get_user(dev->absflat[t], ((int *) arg) + 4)) return -EFAULT; return 0; } @@ -397,15 +404,15 @@ } static struct file_operations evdev_fops = { - owner: THIS_MODULE, - read: evdev_read, - write: evdev_write, - poll: evdev_poll, - open: evdev_open, - release: evdev_release, - ioctl: evdev_ioctl, - fasync: evdev_fasync, - flush: evdev_flush + .owner = THIS_MODULE, + .read = evdev_read, + .write = evdev_write, + .poll = evdev_poll, + .open = evdev_open, + .release = evdev_release, + .ioctl = evdev_ioctl, + .fasync = evdev_fasync, + .flush = evdev_flush }; static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) @@ -466,13 +473,13 @@ MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { - event: evdev_event, - connect: evdev_connect, - disconnect: evdev_disconnect, - fops: &evdev_fops, - minor: EVDEV_MINOR_BASE, - name: "evdev", - id_table: evdev_ids, + .event = evdev_event, + .connect = evdev_connect, + .disconnect = evdev_disconnect, + .fops = &evdev_fops, + .minor = EVDEV_MINOR_BASE, + .name = "evdev", + .id_table = evdev_ids, }; static int __init evdev_init(void) diff -Nru a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c --- a/drivers/input/gameport/cs461x.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/gameport/cs461x.c Fri Jul 26 19:58:50 2002 @@ -291,9 +291,9 @@ port->name = name; port->phys = phys; - port->idbus = BUS_PCI; - port->idvendor = pdev->vendor; - port->idproduct = pdev->device; + port->id.bustype = BUS_PCI; + port->id.vendor = pdev->vendor; + port->id.product = pdev->device; cs461x_pokeBA0(BA0_JSIO, 0xFF); // ? cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); @@ -312,10 +312,10 @@ } static struct pci_driver cs461x_pci_driver = { - name: "CS461x Gameport", - id_table: cs461x_pci_tbl, - probe: cs461x_pci_probe, - remove: __devexit_p(cs461x_pci_remove), + .name = "CS461x Gameport", + .id_table = cs461x_pci_tbl, + .probe = cs461x_pci_probe, + .remove = __devexit_p(cs461x_pci_remove), }; int __init cs461x_init(void) diff -Nru a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c --- a/drivers/input/gameport/emu10k1-gp.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/gameport/emu10k1-gp.c Fri Jul 26 19:58:51 2002 @@ -87,9 +87,9 @@ emu->gameport.io = ioport; emu->gameport.name = pdev->name; emu->gameport.phys = emu->phys; - emu->gameport.idbus = BUS_PCI; - emu->gameport.idvendor = pdev->vendor; - emu->gameport.idproduct = pdev->device; + emu->gameport.id.bustype = BUS_PCI; + emu->gameport.id.vendor = pdev->vendor; + emu->gameport.id.product = pdev->device; pci_set_drvdata(pdev, emu); @@ -110,10 +110,10 @@ } static struct pci_driver emu_driver = { - name: "Emu10k1 Gameport", - id_table: emu_tbl, - probe: emu_probe, - remove: __devexit_p(emu_remove), + .name = "Emu10k1 Gameport", + .id_table = emu_tbl, + .probe = emu_probe, + .remove = __devexit_p(emu_remove), }; int __init emu_init(void) diff -Nru a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c --- a/drivers/input/gameport/fm801-gp.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/gameport/fm801-gp.c Fri Jul 26 19:58:51 2002 @@ -105,9 +105,9 @@ gp->gameport.phys = gp->phys; gp->gameport.name = gp->name; - gp->gameport.idbus = BUS_PCI; - gp->gameport.idvendor = pci->vendor; - gp->gameport.idproduct = pci->device; + gp->gameport.id.bustype = BUS_PCI; + gp->gameport.id.vendor = pci->vendor; + gp->gameport.id.product = pci->device; pci_set_drvdata(pci, gp); @@ -137,10 +137,10 @@ }; static struct pci_driver fm801_gp_driver = { - name: "FM801 GP", - id_table: fm801_gp_id_table, - probe: fm801_gp_probe, - remove: fm801_gp_remove, + .name = "FM801 GP", + .id_table = fm801_gp_id_table, + .probe = fm801_gp_probe, + .remove = fm801_gp_remove, }; int __init fm801_gp_init(void) diff -Nru a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c --- a/drivers/input/gameport/gameport.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/gameport/gameport.c Fri Jul 26 19:58:51 2002 @@ -94,13 +94,12 @@ tx = 1 << 30; for(i = 0; i < 50; i++) { - save_flags(flags); /* Yes, all CPUs */ - cli(); + local_irq_save(flags); GET_TIME(t1); for(t = 0; t < 50; t++) gameport_read(gameport); GET_TIME(t2); GET_TIME(t3); - restore_flags(flags); + local_irq_restore(flags); udelay(i * 10); if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; } diff -Nru a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c --- a/drivers/input/gameport/lightning.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/gameport/lightning.c Fri Jul 26 19:58:51 2002 @@ -259,7 +259,7 @@ gameport->name = l4_name; gameport->phys = l4->phys; - gameport->idbus = BUS_ISA; + gameport->id.bustype = BUS_ISA; if (!i && !j) gameport->io = L4_PORT; diff -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c --- a/drivers/input/gameport/ns558.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/gameport/ns558.c Fri Jul 26 19:58:51 2002 @@ -144,7 +144,7 @@ port->gameport.io = io & (-1 << i); port->gameport.phys = port->phys; port->gameport.name = port->name; - port->gameport.idbus = BUS_ISA; + port->gameport.id.bustype = BUS_ISA; sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i)); sprintf(port->name, "NS558 ISA"); @@ -163,8 +163,8 @@ #ifdef __ISAPNP__ #define NS558_DEVICE(a,b,c,d)\ - card_vendor: ISAPNP_ANY_ID, card_device: ISAPNP_ANY_ID,\ - vendor: ISAPNP_VENDOR(a,b,c), function: ISAPNP_DEVICE(d) + .card_vendor = ISAPNP_ANY_ID, card_device: ISAPNP_ANY_ID,\ + .vendor = ISAPNP_VENDOR(a,b,c), function: ISAPNP_DEVICE(d) static struct isapnp_device_id pnp_devids[] = { { NS558_DEVICE('@','P','@',0x0001) }, /* ALS 100 */ @@ -232,10 +232,10 @@ port->gameport.io = ioport; port->gameport.phys = port->phys; port->gameport.name = port->name; - port->gameport.idbus = BUS_ISAPNP; - port->gameport.idvendor = dev->vendor; - port->gameport.idproduct = dev->device; - port->gameport.idversion = 0x100; + port->gameport.id.bustype = BUS_ISAPNP; + port->gameport.id.vendor = dev->vendor; + port->gameport.id.product = dev->device; + port->gameport.id.version = 0x100; sprintf(port->phys, "isapnp%d.%d/gameport0", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); sprintf(port->name, "%s", dev->name[0] ? dev->name : "NS558 PnP Gameport"); diff -Nru a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c --- a/drivers/input/gameport/vortex.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/gameport/vortex.c Fri Jul 26 19:58:51 2002 @@ -129,9 +129,9 @@ vortex->gameport.name = dev->name; vortex->gameport.phys = vortex->phys; - vortex->gameport.idbus = BUS_PCI; - vortex->gameport.idvendor = dev->vendor; - vortex->gameport.idproduct = dev->device; + vortex->gameport.id.bustype = BUS_PCI; + vortex->gameport.id.vendor = dev->vendor; + vortex->gameport.id.product = dev->device; for (i = 0; i < 6; i++) if (~pci_resource_flags(dev, i) & IORESOURCE_IO) @@ -165,10 +165,10 @@ { 0 }}; static struct pci_driver vortex_driver = { - name: "vortex", - id_table: vortex_id_table, - probe: vortex_probe, - remove: vortex_remove, + .name = "vortex", + .id_table = vortex_id_table, + .probe = vortex_probe, + .remove = vortex_remove, }; int __init vortex_init(void) diff -Nru a/drivers/input/input.c b/drivers/input/input.c --- a/drivers/input/input.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/input.c Fri Jul 26 19:58:51 2002 @@ -72,16 +72,9 @@ { struct input_handle *handle = dev->handle; -/* - * Wake up the device if it is sleeping. - */ if (dev->pm_dev) pm_access(dev->pm_dev); -/* - * Filter non-events, and bad input values out. - */ - if (type > EV_MAX || !test_bit(type, dev->evbit)) return; @@ -89,6 +82,19 @@ switch (type) { + case EV_SYN: + switch (code) { + case SYN_CONFIG: + if (dev->event) dev->event(dev, type, code, value); + break; + + case SYN_REPORT: + if (dev->sync) return; + dev->sync = 1; + break; + } + break; + case EV_KEY: if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) @@ -185,9 +191,8 @@ break; } -/* - * Distribute the event to handler modules. - */ + if (type != EV_SYN) + dev->sync = 0; while (handle) { if (handle->open) @@ -200,6 +205,7 @@ { struct input_dev *dev = (void *) data; input_event(dev, EV_KEY, dev->repeat_key, 2); + input_sync(dev); mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); } @@ -290,19 +296,19 @@ for (; id->flags || id->driver_info; id++) { if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) - if (id->idbus != dev->idbus) + if (id->id.bustype != dev->id.bustype) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) - if (id->idvendor != dev->idvendor) + if (id->id.vendor != dev->id.vendor) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) - if (id->idproduct != dev->idproduct) + if (id->id.product != dev->id.product) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) - if (id->idversion != dev->idversion) + if (id->id.version != dev->id.version) continue; MATCH_BIT(evbit, EV_MAX); @@ -395,7 +401,7 @@ envp[i++] = scratch; scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", - dev->idbus, dev->idvendor, dev->idproduct, dev->idversion) + 1; + dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; if (dev->name) { envp[i++] = scratch; @@ -439,6 +445,12 @@ struct input_device_id *id; /* + * Add the EV_SYN capability. + */ + + set_bit(EV_SYN, dev->evbit); + +/* * Initialize repeat timer to default values. */ @@ -650,8 +662,8 @@ } static struct file_operations input_fops = { - owner: THIS_MODULE, - open: input_open_file, + .owner = THIS_MODULE, + .open = input_open_file, }; devfs_handle_t input_register_minor(char *name, int minor, int minor_base) @@ -710,7 +722,7 @@ while (dev) { len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", - dev->idbus, dev->idvendor, dev->idproduct, dev->idversion); + dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c --- a/drivers/input/joydev.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joydev.c Fri Jul 26 19:58:51 2002 @@ -402,14 +402,14 @@ } static struct file_operations joydev_fops = { - owner: THIS_MODULE, - read: joydev_read, - write: joydev_write, - poll: joydev_poll, - open: joydev_open, - release: joydev_release, - ioctl: joydev_ioctl, - fasync: joydev_fasync, + .owner = THIS_MODULE, + .read = joydev_read, + .write = joydev_write, + .poll = joydev_poll, + .open = joydev_open, + .release = joydev_release, + .ioctl = joydev_ioctl, + .fasync = joydev_fasync, }; static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) @@ -505,19 +505,19 @@ static struct input_device_id joydev_ids[] = { { - flags: INPUT_DEVICE_ID_MATCH_EVBIT, - evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, - absbit: { BIT(ABS_X) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) }, }, { - flags: INPUT_DEVICE_ID_MATCH_EVBIT, - evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, - absbit: { BIT(ABS_WHEEL) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, + .absbit = { BIT(ABS_WHEEL) }, }, { - flags: INPUT_DEVICE_ID_MATCH_EVBIT, - evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, - absbit: { BIT(ABS_THROTTLE) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, + .absbit = { BIT(ABS_THROTTLE) }, }, { }, /* Terminating entry */ }; @@ -525,13 +525,13 @@ MODULE_DEVICE_TABLE(input, joydev_ids); static struct input_handler joydev_handler = { - event: joydev_event, - connect: joydev_connect, - disconnect: joydev_disconnect, - fops: &joydev_fops, - minor: JOYDEV_MINOR_BASE, - name: "joydev", - id_table: joydev_ids, + .event = joydev_event, + .connect = joydev_connect, + .disconnect = joydev_disconnect, + .fops = &joydev_fops, + .minor = JOYDEV_MINOR_BASE, + .name = "joydev", + .id_table = joydev_ids, }; static int __init joydev_init(void) diff -Nru a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help --- a/drivers/input/joystick/Config.help Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/Config.help Fri Jul 26 19:58:50 2002 @@ -67,6 +67,15 @@ The module will be called grip.o. If you want to compile it as a module, say M here and read . +CONFIG_JOYSTICK_GRIP_MP + Say Y here if you have the original Gravis GrIP MultiPort, a hub + that connects to the gameport and you connect gamepads to it. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called grip_mp.o. If you want to compile it as a + module, say M here and read . + CONFIG_JOYSTICK_GUILLEMOT Say Y here if you have a Guillemot joystick using a digital protocol over the PC gameport. diff -Nru a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in --- a/drivers/input/joystick/Config.in Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/Config.in Fri Jul 26 19:58:52 2002 @@ -10,6 +10,7 @@ dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT +dep_tristate ' Gravis GrIP MultiPort' CONFIG_JOYSTICK_GRIP_MP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT diff -Nru a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile --- a/drivers/input/joystick/Makefile Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/Makefile Fri Jul 26 19:58:52 2002 @@ -13,6 +13,7 @@ obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o obj-$(CONFIG_JOYSTICK_GRIP) += grip.o +obj-$(CONFIG_JOYSTICK_GRIP_MP) += grip_mp.o obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o diff -Nru a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c --- a/drivers/input/joystick/a3d.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/a3d.c Fri Jul 26 19:58:50 2002 @@ -130,6 +130,8 @@ input_report_key(dev, BTN_LEFT, data[3] & 2); input_report_key(dev, BTN_MIDDLE, data[3] & 4); + input_sync(dev); + a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; @@ -165,6 +167,8 @@ input_report_key(dev, BTN_TOP, data[8] & 4); input_report_key(dev, BTN_PINKIE, data[7] & 1); + input_sync(dev); + return; } } @@ -336,10 +340,10 @@ a3d->adc.name = a3d_names[a3d->mode]; a3d->adc.phys = a3d->adcphys; - a3d->adc.idbus = BUS_GAMEPORT; - a3d->adc.idvendor = GAMEPORT_ID_VENDOR_MADCATZ; - a3d->adc.idproduct = a3d->mode; - a3d->adc.idversion = 0x0100; + a3d->adc.id.bustype = BUS_GAMEPORT; + a3d->adc.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ; + a3d->adc.id.product = a3d->mode; + a3d->adc.id.version = 0x0100; a3d_read(a3d, data); @@ -353,10 +357,10 @@ a3d->dev.name = a3d_names[a3d->mode]; a3d->dev.phys = a3d->phys; - a3d->dev.idbus = BUS_GAMEPORT; - a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ; - a3d->dev.idproduct = a3d->mode; - a3d->dev.idversion = 0x0100; + a3d->dev.id.bustype = BUS_GAMEPORT; + a3d->dev.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ; + a3d->dev.id.product = a3d->mode; + a3d->dev.id.version = 0x0100; input_register_device(&a3d->dev); printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys); @@ -378,8 +382,8 @@ } static struct gameport_dev a3d_dev = { - connect: a3d_connect, - disconnect: a3d_disconnect, + .connect = a3d_connect, + .disconnect = a3d_disconnect, }; int __init a3d_init(void) diff -Nru a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c --- a/drivers/input/joystick/adi.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/adi.c Fri Jul 26 19:58:51 2002 @@ -249,6 +249,8 @@ for (i = 63; i < adi->buttons; i++) input_report_key(dev, *key++, adi_get_bits(adi, 1)); + + input_sync(dev); return 0; } @@ -416,10 +418,10 @@ adi->dev.name = adi->name; adi->dev.phys = adi->phys; - adi->dev.idbus = BUS_GAMEPORT; - adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH; - adi->dev.idproduct = adi->id; - adi->dev.idversion = 0x0100; + adi->dev.id.bustype = BUS_GAMEPORT; + adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; + adi->dev.id.product = adi->id; + adi->dev.id.version = 0x0100; adi->dev.private = port; adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -541,8 +543,8 @@ */ static struct gameport_dev adi_dev = { - connect: adi_connect, - disconnect: adi_disconnect, + .connect = adi_connect, + .disconnect = adi_disconnect, }; int __init adi_init(void) diff -Nru a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c --- a/drivers/input/joystick/amijoy.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/amijoy.c Fri Jul 26 19:58:52 2002 @@ -67,6 +67,8 @@ input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); data = ~(data ^ (data << 1)); input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); + + input_sync(amijoy_dev + i); } } @@ -134,10 +136,10 @@ amijoy->dev[i].name = amijoy_name; amijoy->dev[i].phys = amijoy_phys[i]; - amijoy->dev[i].idbus = BUS_AMIGA; - amijoy->dev[i].idvendor = 0x0001; - amijoy->dev[i].idproduct = 0x0003; - amijoy->dev[i].version = 0x0100; + amijoy->dev[i].id.bustype = BUS_AMIGA; + amijoy->dev[i].id.vendor = 0x0001; + amijoy->dev[i].id.product = 0x0003; + amijoy->dev[i].id.version = 0x0100; amijoy_dev[i].private = amijoy_used + i; diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c --- a/drivers/input/joystick/analog.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/analog.c Fri Jul 26 19:58:51 2002 @@ -215,6 +215,8 @@ input_report_abs(dev, analog_hats[j++], ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1)); } + + input_sync(dev); } /* @@ -368,8 +370,7 @@ unsigned int i, t, tx, t1, t2, t3; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); GET_TIME(t1); #ifdef FAKE_TIME analog_faketime += 830; @@ -377,19 +378,18 @@ udelay(1000); GET_TIME(t2); GET_TIME(t3); - restore_flags(flags); + local_irq_restore(flags); port->speed = DELTA(t1, t2) - DELTA(t2, t3); tx = ~0; for (i = 0; i < 50; i++) { - save_flags(flags); - cli(); + local_irq_save(flags); GET_TIME(t1); for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } GET_TIME(t3); - restore_flags(flags); + local_irq_restore(flags); udelay(i); t = DELTA(t1, t2) - DELTA(t2, t3); if (t < tx) tx = t; @@ -436,10 +436,10 @@ analog->dev.name = analog->name; analog->dev.phys = analog->phys; - analog->dev.idbus = BUS_GAMEPORT; - analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG; - analog->dev.idproduct = analog->mask >> 4; - analog->dev.idversion = 0x0100; + analog->dev.id.bustype = BUS_GAMEPORT; + analog->dev.id.vendor = GAMEPORT_ID_VENDOR_ANALOG; + analog->dev.id.product = analog->mask >> 4; + analog->dev.id.version = 0x0100; analog->dev.open = analog_open; analog->dev.close = analog_close; @@ -737,8 +737,8 @@ */ static struct gameport_dev analog_dev = { - connect: analog_connect, - disconnect: analog_disconnect, + .connect = analog_connect, + .disconnect = analog_disconnect, }; #ifndef MODULE diff -Nru a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c --- a/drivers/input/joystick/cobra.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/cobra.c Fri Jul 26 19:58:51 2002 @@ -136,6 +136,8 @@ for (j = 0; cobra_btn[j]; j++) input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); + input_sync(dev); + } mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); @@ -199,10 +201,10 @@ cobra->dev[i].name = cobra_name; cobra->dev[i].phys = cobra->phys[i]; - cobra->dev[i].idbus = BUS_GAMEPORT; - cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE; - cobra->dev[i].idproduct = 0x0008; - cobra->dev[i].idversion = 0x0100; + cobra->dev[i].id.bustype = BUS_GAMEPORT; + cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; + cobra->dev[i].id.product = 0x0008; + cobra->dev[i].id.version = 0x0100; cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); @@ -235,8 +237,8 @@ } static struct gameport_dev cobra_dev = { - connect: cobra_connect, - disconnect: cobra_disconnect, + .connect = cobra_connect, + .disconnect = cobra_disconnect, }; int __init cobra_init(void) diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c --- a/drivers/input/joystick/db9.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/db9.c Fri Jul 26 19:58:51 2002 @@ -266,6 +266,8 @@ break; } + input_sync(dev); + mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); } @@ -351,10 +353,10 @@ db9->dev[i].name = db9_name[db9->mode]; db9->dev[i].phys = db9->phys[i]; - db9->dev[i].idbus = BUS_PARPORT; - db9->dev[i].idvendor = 0x0002; - db9->dev[i].idproduct = config[1]; - db9->dev[i].idversion = 0x0100; + db9->dev[i].id.bustype = BUS_PARPORT; + db9->dev[i].id.vendor = 0x0002; + db9->dev[i].id.product = config[1]; + db9->dev[i].id.version = 0x0100; db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); @@ -373,21 +375,21 @@ } #ifndef MODULE -int __init db9_setup(char *str) +static int __init db9_setup(char *str) { int i, ints[3]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1]; return 1; } -int __init db9_setup_2(char *str) +static int __init db9_setup_2(char *str) { int i, ints[3]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1]; return 1; } -int __init db9_setup_3(char *str) +static int __init db9_setup_3(char *str) { int i, ints[3]; get_options(str, ARRAY_SIZE(ints), ints); diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c --- a/drivers/input/joystick/gamecon.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/gamecon.c Fri Jul 26 19:58:51 2002 @@ -328,6 +328,8 @@ for (j = 0; j < 10; j++) input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); + + input_sync(dev + i); } } } @@ -356,6 +358,8 @@ if (s & gc->pads[GC_SNES]) for (j = 0; j < 8; j++) input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); + + input_sync(dev + i); } } @@ -379,6 +383,8 @@ if (s & gc->pads[GC_MULTI2]) input_report_key(dev + i, BTN_THUMB, s & data[5]); + + input_sync(dev + i); } } @@ -398,6 +404,7 @@ input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04); input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02); + input_sync(dev + i); case GC_PSX_NEGCON: case GC_PSX_ANALOG: @@ -414,6 +421,8 @@ input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_sync(dev + i); + break; case GC_PSX_NORMAL: @@ -427,6 +436,8 @@ input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_sync(dev + i); + break; } } @@ -593,10 +604,10 @@ gc->dev[i].name = gc_names[config[i + 1]]; gc->dev[i].phys = gc->phys[i]; - gc->dev[i].idbus = BUS_PARPORT; - gc->dev[i].idvendor = 0x0001; - gc->dev[i].idproduct = config[i + 1]; - gc->dev[i].idversion = 0x0100; + gc->dev[i].id.bustype = BUS_PARPORT; + gc->dev[i].id.vendor = 0x0001; + gc->dev[i].id.product = config[i + 1]; + gc->dev[i].id.version = 0x0100; } parport_release(gc->pd); @@ -617,21 +628,21 @@ } #ifndef MODULE -int __init gc_setup(char *str) +static int __init gc_setup(char *str) { int i, ints[7]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1]; return 1; } -int __init gc_setup_2(char *str) +static int __init gc_setup_2(char *str) { int i, ints[7]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1]; return 1; } -int __init gc_setup_3(char *str) +static int __init gc_setup_3(char *str) { int i, ints[7]; get_options(str, ARRAY_SIZE(ints), ints); diff -Nru a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c --- a/drivers/input/joystick/gf2k.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/gf2k.c Fri Jul 26 19:58:50 2002 @@ -197,6 +197,8 @@ for (i = 0; i < gf2k_pads[gf2k->id]; i++) input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1); + + input_sync(dev); } /* @@ -295,10 +297,10 @@ gf2k->dev.name = gf2k_names[gf2k->id]; gf2k->dev.phys = gf2k->phys; - gf2k->dev.idbus = BUS_GAMEPORT; - gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS; - gf2k->dev.idproduct = gf2k->id; - gf2k->dev.idversion = 0x0100; + gf2k->dev.id.bustype = BUS_GAMEPORT; + gf2k->dev.id.vendor = GAMEPORT_ID_VENDOR_GENIUS; + gf2k->dev.id.product = gf2k->id; + gf2k->dev.id.version = 0x0100; for (i = 0; i < gf2k_axes[gf2k->id]; i++) set_bit(gf2k_abs[i], gf2k->dev.absbit); @@ -343,8 +345,8 @@ } static struct gameport_dev gf2k_dev = { - connect: gf2k_connect, - disconnect: gf2k_disconnect, + .connect = gf2k_connect, + .disconnect = gf2k_disconnect, }; int __init gf2k_init(void) diff -Nru a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c --- a/drivers/input/joystick/grip.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/grip.c Fri Jul 26 19:58:51 2002 @@ -276,6 +276,8 @@ } + + input_sync(dev); } mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME); @@ -350,10 +352,10 @@ grip->dev[i].name = grip_name[grip->mode[i]]; grip->dev[i].phys = grip->phys[i]; - grip->dev[i].idbus = BUS_GAMEPORT; - grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS; - grip->dev[i].idproduct = grip->mode[i]; - grip->dev[i].idversion = 0x0100; + grip->dev[i].id.bustype = BUS_GAMEPORT; + grip->dev[i].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; + grip->dev[i].id.product = grip->mode[i]; + grip->dev[i].id.version = 0x0100; grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -408,8 +410,8 @@ } static struct gameport_dev grip_dev = { - connect: grip_connect, - disconnect: grip_disconnect, + .connect = grip_connect, + .disconnect = grip_disconnect, }; int __init grip_init(void) diff -Nru a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/joystick/grip_mp.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,676 @@ +/* + * $Id: grip_mp.c,v 1.9 2002/07/20 19:28:45 bonnland Exp $ + * + * Driver for the Gravis Grip Multiport, a gamepad "hub" that + * connects up to four 9-pin digital gamepads/joysticks. + * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. + * + * Thanks to Chris Gassib for helpful advice. + * + * Copyright (c) 2002 Brian Bonnlander, Bill Soudan + * Copyright (c) 1998-2000 Vojtech Pavlik + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Brian Bonnlander"); +MODULE_DESCRIPTION("Gravis Grip Multiport driver"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +EXPORT_NO_SYMBOLS; + +#ifdef GRIP_DEBUG +#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif + +/* + * Grip multiport state + */ + +struct grip_mp { + struct gameport *gameport; + struct timer_list timer; + struct input_dev dev[4]; + int mode[4]; + int registered[4]; + int used; + int reads; + int bads; + + /* individual gamepad states */ + int buttons[4]; + int xaxes[4]; + int yaxes[4]; + int dirty[4]; /* has the state been updated? */ +}; + +/* + * Multiport packet interpretation + */ + +#define PACKET_FULL 0x80000000 /* packet is full */ +#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */ +#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */ +#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */ +#define PACKET_MP_DONE 0x02000000 /* multiport done sending */ + +/* + * Packet status code interpretation + */ + +#define IO_GOT_PACKET 0x0100 /* Got a packet */ +#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */ +#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */ +#define IO_DONE 0x1000 /* Multiport is done sending packets */ +#define IO_RETRY 0x4000 /* Try again later to get packet */ +#define IO_RESET 0x8000 /* Force multiport to resend all packets */ + +/* + * Gamepad configuration data. Other 9-pin digital joystick devices + * may work with the multiport, so this may not be an exhaustive list! + * Commodore 64 joystick remains untested. + */ + +#define GRIP_INIT_DELAY 2000 /* 2 ms */ +#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */ + +#define GRIP_MODE_NONE 0 +#define GRIP_MODE_RESET 1 +#define GRIP_MODE_GP 2 +#define GRIP_MODE_C64 3 + +static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; +static int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; + +static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; +static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; + +static int *grip_abs[] = { 0, 0, grip_abs_gp, grip_abs_c64 }; +static int *grip_btn[] = { 0, 0, grip_btn_gp, grip_btn_c64 }; + +static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; + +static const int init_seq[] = { + 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, + 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 }; + +/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ + +static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; + +/* + * Returns whether an odd or even number of bits are on in pkt. + */ + +static int bit_parity(u32 pkt) +{ + int x = pkt ^ (pkt >> 16); + x ^= x >> 8; + x ^= x >> 4; + x ^= x >> 2; + x ^= x >> 1; + return x & 1; +} + +/* + * Poll gameport; return true if all bits set in 'onbits' are on and + * all bits set in 'offbits' are off. + */ + +static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data) +{ + int i, nloops; + + nloops = gameport_time(gp, u_sec); + for (i = 0; i < nloops; i++) { + *data = gameport_read(gp); + if ((*data & onbits) == onbits && + (~(*data) & offbits) == offbits) + return 1; + } + dbg("gameport timed out after %d microseconds.\n", u_sec); + return 0; +} + +/* + * Gets a 28-bit packet from the multiport. + * + * After getting a packet successfully, commands encoded by sendcode may + * be sent to the multiport. + * + * The multiport clock value is reflected in gameport bit B4. + * + * Returns a packet status code indicating whether packet is valid, the transfer + * mode, and any error conditions. + * + * sendflags: current I/O status + * sendcode: data to send to the multiport if sendflags is nonzero + */ + +static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) +{ + u8 raw_data; /* raw data from gameport */ + u8 data_mask; /* packet data bits from raw_data */ + u32 pkt; /* packet temporary storage */ + int bits_per_read; /* num packet bits per gameport read */ + int portvals = 0; /* used for port value sanity check */ + int i; + + /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */ + + *packet = 0; + raw_data = gameport_read(gameport); + if (raw_data & 1) + return IO_RETRY; + + for (i = 0; i < 64; i++) { + raw_data = gameport_read(gameport); + portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */ + } + + if (portvals == 1) { /* B4, B5 off */ + raw_data = gameport_read(gameport); + portvals = raw_data & 0xf0; + + if (raw_data & 0x31) + return IO_RESET; + gameport_trigger(gameport); + + if (!poll_until(0x10, 0, 308, gameport, &raw_data)) + return IO_RESET; + } else + return IO_RETRY; + + /* Determine packet transfer mode and prepare for packet construction. */ + + if (raw_data & 0x20) { /* 3 data bits/read */ + portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */ + + if (portvals != 0xb) + return 0; + data_mask = 7; + bits_per_read = 3; + pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28; + } else { /* 1 data bit/read */ + data_mask = 1; + bits_per_read = 1; + pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28; + } + + /* Construct a packet. Final data bits must be zero. */ + + while (1) { + if (!poll_until(0, 0x10, 77, gameport, &raw_data)) + return IO_RESET; + raw_data = (raw_data >> 5) & data_mask; + + if (pkt & PACKET_FULL) + break; + pkt = (pkt << bits_per_read) | raw_data; + + if (!poll_until(0x10, 0, 77, gameport, &raw_data)) + return IO_RESET; + } + + if (raw_data) + return IO_RESET; + + /* If 3 bits/read used, drop from 30 bits to 28. */ + + if (bits_per_read == 3) { + pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff); + pkt = (pkt >> 2) | 0xf0000000; + } + + if (bit_parity(pkt) == 1) + return IO_RESET; + + /* Acknowledge packet receipt */ + + if (!poll_until(0x30, 0, 77, gameport, &raw_data)) + return IO_RESET; + + raw_data = gameport_read(gameport); + + if (raw_data & 1) + return IO_RESET; + + gameport_trigger(gameport); + + if (!poll_until(0, 0x20, 77, gameport, &raw_data)) + return IO_RESET; + + /* Return if we just wanted the packet or multiport wants to send more */ + + *packet = pkt; + if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE))) + return IO_GOT_PACKET; + + if (pkt & PACKET_MP_MORE) + return IO_GOT_PACKET | IO_RETRY; + + /* Multiport is done sending packets and is ready to receive data */ + + if (!poll_until(0x20, 0, 77, gameport, &raw_data)) + return IO_GOT_PACKET | IO_RESET; + + raw_data = gameport_read(gameport); + if (raw_data & 1) + return IO_GOT_PACKET | IO_RESET; + + /* Trigger gameport based on bits in sendcode */ + + gameport_trigger(gameport); + do { + if (!poll_until(0x20, 0x10, 116, gameport, &raw_data)) + return IO_GOT_PACKET | IO_RESET; + + if (!poll_until(0x30, 0, 193, gameport, &raw_data)) + return IO_GOT_PACKET | IO_RESET; + + if (raw_data & 1) + return IO_GOT_PACKET | IO_RESET; + + if (sendcode & 1) + gameport_trigger(gameport); + + sendcode >>= 1; + } while (sendcode); + + return IO_GOT_PACKET | IO_MODE_FAST; +} + +/* + * Disables and restores interrupts for mp_io(), which does the actual I/O. + */ + +static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) +{ + int status; + unsigned long flags; + + local_irq_save(flags); + status = mp_io(gameport, sendflags, sendcode, packet); + local_irq_restore(flags); + + return status; +} + +/* + * Puts multiport into digital mode. Multiport LED turns green. + * + * Returns true if a valid digital packet was received, false otherwise. + */ + +static int dig_mode_start(struct gameport *gameport, u32 *packet) +{ + int i, seq_len = sizeof(init_seq)/sizeof(int); + int flags, tries = 0, bads = 0; + + for (i = 0; i < seq_len; i++) { /* Send magic sequence */ + if (init_seq[i]) + gameport_trigger(gameport); + udelay(GRIP_INIT_DELAY); + } + + for (i = 0; i < 16; i++) /* Wait for multiport to settle */ + udelay(GRIP_INIT_DELAY); + + while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */ + + flags = multiport_io(gameport, IO_RESET, 0x27, packet); + + if (flags & IO_MODE_FAST) + return 1; + + if (flags & IO_RETRY) + tries++; + else + bads++; + } + return 0; +} + +/* + * Packet structure: B0-B15 => gamepad state + * B16-B20 => gamepad device type + * B21-B24 => multiport slot index (1-4) + * + * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist. + * + * Returns the packet status. + */ + +static int get_and_decode_packet(struct grip_mp *grip, int flags) +{ + u32 packet; + int joytype = 0; + int slot = 0; + static void register_slot(int i, struct grip_mp *grip); + + /* Get a packet and check for validity */ + + flags &= IO_RESET | IO_RETRY; + flags = multiport_io(grip->gameport, flags, 0, &packet); + grip->reads++; + + if (packet & PACKET_MP_DONE) + flags |= IO_DONE; + + if (flags && !(flags & IO_GOT_PACKET)) { + grip->bads++; + return flags; + } + + /* Ignore non-gamepad packets, e.g. multiport hardware version */ + + slot = ((packet >> 21) & 0xf) - 1; + if ((slot < 0) || (slot > 3)) + return flags; + + /* + * Handle "reset" packets, which occur at startup, and when gamepads + * are removed or plugged in. May contain configuration of a new gamepad. + */ + + joytype = (packet >> 16) & 0x1f; + if (!joytype) { + + if (grip->registered[slot]) { + printk(KERN_INFO "grip_mp: removing %s, slot %d\n", + grip_name[grip->mode[slot]], slot); + input_unregister_device(grip->dev + slot); + grip->registered[slot] = 0; + } + dbg("Reset: grip multiport slot %d\n", slot); + grip->mode[slot] = GRIP_MODE_RESET; + flags |= IO_SLOT_CHANGE; + return flags; + } + + /* Interpret a grip pad packet */ + + if (joytype == 0x1f) { + + int dir = (packet >> 8) & 0xf; /* eight way directional value */ + grip->buttons[slot] = (~packet) & 0xff; + grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1; + grip->xaxes[slot] = (axis_map[dir] & 3) - 1; + grip->dirty[slot] = 1; + + if (grip->mode[slot] == GRIP_MODE_RESET) + flags |= IO_SLOT_CHANGE; + + grip->mode[slot] = GRIP_MODE_GP; + + if (!grip->registered[slot]) { + dbg("New Grip pad in multiport slot %d.\n", slot); + register_slot(slot, grip); + } + return flags; + } + + /* Handle non-grip device codes. For now, just print diagnostics. */ + + { + static int strange_code = 0; + if (strange_code != joytype) { + printk(KERN_INFO "Possible non-grip pad/joystick detected.\n"); + printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet); + strange_code = joytype; + } + } + return flags; +} + +/* + * Returns true if all multiport slot states appear valid. + */ + +static int slots_valid(struct grip_mp *grip) +{ + int flags, slot, invalid = 0, active = 0; + + flags = get_and_decode_packet(grip, 0); + if (!(flags & IO_GOT_PACKET)) + return 0; + + for (slot = 0; slot < 4; slot++) { + if (grip->mode[slot] == GRIP_MODE_RESET) + invalid = 1; + if (grip->mode[slot] != GRIP_MODE_NONE) + active = 1; + } + + /* Return true if no active slot but multiport sent all its data */ + if (!active) + return (flags & IO_DONE) ? 1 : 0; + + /* Return false if invalid device code received */ + return invalid ? 0 : 1; +} + +/* + * Returns whether the multiport was placed into digital mode and + * able to communicate its state successfully. + */ + +static int multiport_init(struct grip_mp *grip) +{ + int dig_mode, initialized = 0, tries = 0; + u32 packet; + + dig_mode = dig_mode_start(grip->gameport, &packet); + while (!dig_mode && tries < 4) { + dig_mode = dig_mode_start(grip->gameport, &packet); + tries++; + } + + if (dig_mode) + dbg("multiport_init(): digital mode achieved.\n"); + else { + dbg("multiport_init(): unable to achieve digital mode.\n"); + return 0; + } + + /* Get packets, store multiport state, and check state's validity */ + for (tries = 0; tries < 4096; tries++) { + if ( slots_valid(grip) ) { + initialized = 1; + break; + } + } + dbg("multiport_init(): initialized == %d\n", initialized); + return initialized; +} + +/* + * Reports joystick state to the linux input layer. + */ + +static void report_slot(struct grip_mp *grip, int slot) +{ + struct input_dev *dev = &(grip->dev[slot]); + int i, buttons = grip->buttons[slot]; + + /* Store button states with linux input driver */ + + for (i = 0; i < 8; i++) + input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1); + + /* Store axis states with linux driver */ + + input_report_abs(dev, ABS_X, grip->xaxes[slot]); + input_report_abs(dev, ABS_Y, grip->yaxes[slot]); + + /* Tell the receiver of the events to process them */ + + input_sync(dev); + + grip->dirty[slot] = 0; +} + +/* + * Get the multiport state. + */ + +static void get_and_report_mp_state(struct grip_mp *grip) +{ + int i, npkts, flags; + + for (npkts = 0; npkts < 4; npkts++) { + flags = IO_RETRY; + for (i = 0; i < 32; i++) { + flags = get_and_decode_packet(grip, flags); + if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY)) + break; + } + if (flags & IO_DONE) + break; + } + + for (i = 0; i < 4; i++) + if (grip->dirty[i]) + report_slot(grip, i); +} + +/* + * Called when a joystick device file is opened + */ + +static int grip_open(struct input_dev *dev) +{ + struct grip_mp *grip = dev->private; + if (!grip->used++) + mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME); + return 0; +} + +/* + * Called when a joystick device file is closed + */ + +static void grip_close(struct input_dev *dev) +{ + struct grip_mp *grip = dev->private; + if (!--grip->used) + del_timer(&grip->timer); +} + +/* + * Tell the linux input layer about a newly plugged-in gamepad. + */ + +static void register_slot(int slot, struct grip_mp *grip) +{ + int j, t; + + grip->dev[slot].private = grip; + grip->dev[slot].open = grip_open; + grip->dev[slot].close = grip_close; + grip->dev[slot].name = grip_name[grip->mode[slot]]; + grip->dev[slot].id.bustype = BUS_GAMEPORT; + grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; + grip->dev[slot].id.product = 0x0100 + grip->mode[slot]; + grip->dev[slot].id.version = 0x0100; + grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) { + set_bit(t, grip->dev[slot].absbit); + grip->dev[slot].absmin[t] = -1; + grip->dev[slot].absmax[t] = 1; + } + + for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++) + if (t > 0) + set_bit(t, grip->dev[slot].keybit); + + input_register_device(grip->dev + slot); + grip->registered[slot] = 1; + + if (grip->dirty[slot]) /* report initial state, if any */ + report_slot(grip, slot); + + printk(KERN_INFO "grip_mp: added %s, slot %d\n", + grip_name[grip->mode[slot]], slot); +} + +/* + * Repeatedly polls the multiport and generates events. + */ + +static void grip_timer(unsigned long private) +{ + struct grip_mp *grip = (void*) private; + get_and_report_mp_state(grip); + mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME); +} + +static void grip_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct grip_mp *grip; + + if (!(grip = kmalloc(sizeof(struct grip_mp), GFP_KERNEL))) + return; + memset(grip, 0, sizeof(struct grip_mp)); + gameport->private = grip; + grip->gameport = gameport; + init_timer(&grip->timer); + grip->timer.data = (long) grip; + grip->timer.function = grip_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + if (!multiport_init(grip)) + goto fail2; + if (!grip->mode[0] && !grip->mode[1] && /* nothing plugged in */ + !grip->mode[2] && !grip->mode[3]) + goto fail2; + return; + +fail2: gameport_close(gameport); +fail1: kfree(grip); +} + +static void grip_disconnect(struct gameport *gameport) +{ + int i; + + struct grip_mp *grip = gameport->private; + for (i = 0; i < 4; i++) + if (grip->registered[i]) + input_unregister_device(grip->dev + i); + gameport_close(gameport); + kfree(grip); +} + +static struct gameport_dev grip_dev = { + .connect = grip_connect, + .disconnect = grip_disconnect, +}; + +static int grip_init(void) +{ + gameport_register_device(&grip_dev); + return 0; +} + +static void grip_exit(void) +{ + gameport_unregister_device(&grip_dev); +} + +module_init(grip_init); +module_exit(grip_exit); diff -Nru a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c --- a/drivers/input/joystick/guillemot.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/guillemot.c Fri Jul 26 19:58:51 2002 @@ -147,6 +147,8 @@ input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); } + input_sync(dev); + mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); } @@ -222,10 +224,10 @@ guillemot->dev.name = guillemot_type[i].name; guillemot->dev.phys = guillemot->phys; - guillemot->dev.idbus = BUS_GAMEPORT; - guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT; - guillemot->dev.idproduct = guillemot_type[i].id; - guillemot->dev.idversion = (int)data[14] << 8 | data[15]; + guillemot->dev.id.bustype = BUS_GAMEPORT; + guillemot->dev.id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; + guillemot->dev.id.product = guillemot_type[i].id; + guillemot->dev.id.version = (int)data[14] << 8 | data[15]; guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -265,8 +267,8 @@ } static struct gameport_dev guillemot_dev = { - connect: guillemot_connect, - disconnect: guillemot_disconnect, + .connect = guillemot_connect, + .disconnect = guillemot_disconnect, }; int __init guillemot_init(void) diff -Nru a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c --- a/drivers/input/joystick/iforce/iforce-main.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/iforce/iforce-main.c Fri Jul 26 19:58:51 2002 @@ -352,7 +352,7 @@ * Input device fields. */ - iforce->dev.idbus = BUS_USB; + iforce->dev.id.bustype = BUS_USB; iforce->dev.private = iforce; iforce->dev.name = "Unknown I-Force device"; iforce->dev.open = iforce_open; @@ -392,12 +392,12 @@ */ if (!iforce_get_id_packet(iforce, "M")) - iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; + iforce->dev.id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); if (!iforce_get_id_packet(iforce, "P")) - iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; + iforce->dev.id.product = (iforce->edata[2] << 8) | iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); @@ -438,8 +438,8 @@ */ for (i = 0; iforce_device[i].idvendor; i++) - if (iforce_device[i].idvendor == iforce->dev.idvendor && - iforce_device[i].idproduct == iforce->dev.idproduct) + if (iforce_device[i].idvendor == iforce->dev.id.vendor && + iforce_device[i].idproduct == iforce->dev.id.product) break; iforce->type = iforce_device + i; diff -Nru a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c --- a/drivers/input/joystick/iforce/iforce-packets.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/iforce/iforce-packets.c Fri Jul 26 19:58:50 2002 @@ -214,10 +214,13 @@ } } + input_sync(dev); + break; case 0x02: /* status report */ input_report_key(dev, BTN_DEAD, data[0] & 0x02); + input_sync(dev); /* Check if an effect was just started or stopped */ i = data[1] & 0x7f; diff -Nru a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c --- a/drivers/input/joystick/iforce/iforce-serio.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/iforce/iforce-serio.c Fri Jul 26 19:58:50 2002 @@ -159,8 +159,8 @@ } struct serio_dev iforce_serio_dev = { - write_wakeup: iforce_serio_write_wakeup, - interrupt: iforce_serio_irq, - connect: iforce_serio_connect, - disconnect: iforce_serio_disconnect, + .write_wakeup = iforce_serio_write_wakeup, + .interrupt = iforce_serio_irq, + .connect = iforce_serio_connect, + .disconnect = iforce_serio_disconnect, }; diff -Nru a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c --- a/drivers/input/joystick/iforce/iforce-usb.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/iforce/iforce-usb.c Fri Jul 26 19:58:52 2002 @@ -206,9 +206,9 @@ MODULE_DEVICE_TABLE (usb, iforce_usb_ids); struct usb_driver iforce_usb_driver = { - owner: THIS_MODULE, - name: "iforce", - probe: iforce_usb_probe, - disconnect: iforce_usb_disconnect, - id_table: iforce_usb_ids, + .owner = THIS_MODULE, + .name = "iforce", + .probe = iforce_usb_probe, + .disconnect = iforce_usb_disconnect, + .id_table = iforce_usb_ids, }; diff -Nru a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c --- a/drivers/input/joystick/interact.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/interact.c Fri Jul 26 19:58:50 2002 @@ -176,6 +176,8 @@ } } + input_sync(dev); + mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME); } @@ -254,10 +256,10 @@ interact->dev.name = interact_type[i].name; interact->dev.phys = interact->phys; - interact->dev.idbus = BUS_GAMEPORT; - interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT; - interact->dev.idproduct = interact_type[i].id; - interact->dev.idversion = 0x0100; + interact->dev.id.bustype = BUS_GAMEPORT; + interact->dev.id.vendor = GAMEPORT_ID_VENDOR_INTERACT; + interact->dev.id.product = interact_type[i].id; + interact->dev.id.version = 0x0100; interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -293,8 +295,8 @@ } static struct gameport_dev interact_dev = { - connect: interact_connect, - disconnect: interact_disconnect, + .connect = interact_connect, + .disconnect = interact_disconnect, }; int __init interact_init(void) diff -Nru a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c --- a/drivers/input/joystick/joydump.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/joydump.c Fri Jul 26 19:58:51 2002 @@ -133,8 +133,8 @@ } static struct gameport_dev joydump_dev = { - connect: joydump_connect, - disconnect: joydump_disconnect, + .connect = joydump_connect, + .disconnect = joydump_disconnect, }; static int __init joydump_init(void) diff -Nru a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c --- a/drivers/input/joystick/magellan.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/magellan.c Fri Jul 26 19:58:50 2002 @@ -107,6 +107,8 @@ for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1); break; } + + input_sync(dev); } static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags) @@ -170,10 +172,10 @@ magellan->dev.private = magellan; magellan->dev.name = magellan_name; magellan->dev.phys = magellan->phys; - magellan->dev.idbus = BUS_RS232; - magellan->dev.idvendor = SERIO_MAGELLAN; - magellan->dev.idproduct = 0x0001; - magellan->dev.idversion = 0x0100; + magellan->dev.id.bustype = BUS_RS232; + magellan->dev.id.vendor = SERIO_MAGELLAN; + magellan->dev.id.product = 0x0001; + magellan->dev.id.version = 0x0100; serio->private = magellan; @@ -192,9 +194,9 @@ */ static struct serio_dev magellan_dev = { - interrupt: magellan_interrupt, - connect: magellan_connect, - disconnect: magellan_disconnect, + .interrupt = magellan_interrupt, + .connect = magellan_connect, + .disconnect = magellan_disconnect, }; /* diff -Nru a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c --- a/drivers/input/joystick/sidewinder.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/sidewinder.c Fri Jul 26 19:58:52 2002 @@ -323,6 +323,8 @@ input_report_key(dev, BTN_BASE4, !GB(38,1)); input_report_key(dev, BTN_BASE5, !GB(37,1)); + input_sync(dev); + return 0; case SW_ID_GP: @@ -336,6 +338,8 @@ for (j = 0; j < 10; j++) input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); + + input_sync(dev + i); } return 0; @@ -356,6 +360,8 @@ for (j = 0; j < 9; j++) input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1)); + input_sync(dev); + return 0; case SW_ID_FSP: @@ -377,6 +383,8 @@ input_report_key(dev, BTN_MODE, GB(38,1)); input_report_key(dev, BTN_SELECT, GB(39,1)); + input_sync(dev); + return 0; case SW_ID_FFW: @@ -390,6 +398,8 @@ for (j = 0; j < 8; j++) input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1)); + input_sync(dev); + return 0; } @@ -701,10 +711,10 @@ sw->dev[i].name = sw->name; sw->dev[i].phys = sw->phys[i]; - sw->dev[i].idbus = BUS_GAMEPORT; - sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT; - sw->dev[i].idproduct = sw->type; - sw->dev[i].idversion = 0x0100; + sw->dev[i].id.bustype = BUS_GAMEPORT; + sw->dev[i].id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; + sw->dev[i].id.product = sw->type; + sw->dev[i].id.version = 0x0100; sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -743,8 +753,8 @@ } static struct gameport_dev sw_dev = { - connect: sw_connect, - disconnect: sw_disconnect, + .connect = sw_connect, + .disconnect = sw_disconnect, }; int __init sw_init(void) diff -Nru a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c --- a/drivers/input/joystick/spaceball.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/spaceball.c Fri Jul 26 19:58:50 2002 @@ -137,6 +137,8 @@ printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1); break; } + + input_sync(dev); } /* @@ -240,10 +242,10 @@ spaceball->dev.name = spaceball_names[id]; spaceball->dev.phys = spaceball->phys; - spaceball->dev.idbus = BUS_RS232; - spaceball->dev.idvendor = SERIO_SPACEBALL; - spaceball->dev.idproduct = id; - spaceball->dev.idversion = 0x0100; + spaceball->dev.id.bustype = BUS_RS232; + spaceball->dev.id.vendor = SERIO_SPACEBALL; + spaceball->dev.id.product = id; + spaceball->dev.id.version = 0x0100; serio->private = spaceball; @@ -263,9 +265,9 @@ */ static struct serio_dev spaceball_dev = { - interrupt: spaceball_interrupt, - connect: spaceball_connect, - disconnect: spaceball_disconnect, + .interrupt = spaceball_interrupt, + .connect = spaceball_connect, + .disconnect = spaceball_disconnect, }; /* diff -Nru a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c --- a/drivers/input/joystick/spaceorb.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/spaceorb.c Fri Jul 26 19:58:51 2002 @@ -124,6 +124,8 @@ printk("]\n"); break; } + + input_sync(dev); } static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags) @@ -187,10 +189,10 @@ spaceorb->dev.name = spaceorb_name; spaceorb->dev.phys = spaceorb->phys; - spaceorb->dev.idbus = BUS_RS232; - spaceorb->dev.idvendor = SERIO_SPACEORB; - spaceorb->dev.idproduct = 0x0001; - spaceorb->dev.idversion = 0x0100; + spaceorb->dev.id.bustype = BUS_RS232; + spaceorb->dev.id.vendor = SERIO_SPACEORB; + spaceorb->dev.id.product = 0x0001; + spaceorb->dev.id.version = 0x0100; serio->private = spaceorb; @@ -207,9 +209,9 @@ */ static struct serio_dev spaceorb_dev = { - interrupt: spaceorb_interrupt, - connect: spaceorb_connect, - disconnect: spaceorb_disconnect, + .interrupt = spaceorb_interrupt, + .connect = spaceorb_connect, + .disconnect = spaceorb_disconnect, }; /* diff -Nru a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c --- a/drivers/input/joystick/stinger.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/stinger.c Fri Jul 26 19:58:50 2002 @@ -85,6 +85,8 @@ input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6)); input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F)); + input_sync(dev); + return; } @@ -152,10 +154,10 @@ stinger->dev.name = stinger_name; stinger->dev.phys = stinger->phys; - stinger->dev.idbus = BUS_RS232; - stinger->dev.idvendor = SERIO_STINGER; - stinger->dev.idproduct = 0x0001; - stinger->dev.idversion = 0x0100; + stinger->dev.id.bustype = BUS_RS232; + stinger->dev.id.vendor = SERIO_STINGER; + stinger->dev.id.product = 0x0001; + stinger->dev.id.version = 0x0100; for (i = 0; i < 2; i++) { stinger->dev.absmax[ABS_X+i] = 64; @@ -182,9 +184,9 @@ */ static struct serio_dev stinger_dev = { - interrupt: stinger_interrupt, - connect: stinger_connect, - disconnect: stinger_disconnect, + .interrupt = stinger_interrupt, + .connect = stinger_connect, + .disconnect = stinger_disconnect, }; /* diff -Nru a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c --- a/drivers/input/joystick/tmdc.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/joystick/tmdc.c Fri Jul 26 19:58:51 2002 @@ -214,6 +214,8 @@ ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); l += tmdc->btnc[j][k]; } + + input_sync(dev); } tmdc->bads += bad; @@ -312,10 +314,10 @@ tmdc->dev[j].name = tmdc->name[j]; tmdc->dev[j].phys = tmdc->phys[j]; - tmdc->dev[j].idbus = BUS_GAMEPORT; - tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; - tmdc->dev[j].idproduct = models[m].id; - tmdc->dev[j].idversion = 0x0100; + tmdc->dev[j].id.bustype = BUS_GAMEPORT; + tmdc->dev[j].id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; + tmdc->dev[j].id.product = models[m].id; + tmdc->dev[j].id.version = 0x0100; tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -361,8 +363,8 @@ } static struct gameport_dev tmdc_dev = { - connect: tmdc_connect, - disconnect: tmdc_disconnect, + .connect = tmdc_connect, + .disconnect = tmdc_disconnect, }; int __init tmdc_init(void) diff -Nru a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c --- a/drivers/input/joystick/turbografx.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/turbografx.c Fri Jul 26 19:58:52 2002 @@ -101,6 +101,8 @@ input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 )); input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP )); input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 )); + + input_sync(dev); } mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); @@ -179,10 +181,10 @@ tgfx->dev[i].name = tgfx_name; tgfx->dev[i].phys = tgfx->phys[i]; - tgfx->dev[i].idbus = BUS_PARPORT; - tgfx->dev[i].idvendor = 0x0003; - tgfx->dev[i].idproduct = config[i+1]; - tgfx->dev[i].idversion = 0x0100; + tgfx->dev[i].id.bustype = BUS_PARPORT; + tgfx->dev[i].id.vendor = 0x0003; + tgfx->dev[i].id.product = config[i+1]; + tgfx->dev[i].id.version = 0x0100; tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); @@ -208,21 +210,21 @@ } #ifndef MODULE -int __init tgfx_setup(char *str) +static int __init tgfx_setup(char *str) { int i, ints[9]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1]; return 1; } -int __init tgfx_setup_2(char *str) +static int __init tgfx_setup_2(char *str) { int i, ints[9]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1]; return 1; } -int __init tgfx_setup_3(char *str) +static int __init tgfx_setup_3(char *str) { int i, ints[9]; get_options(str, ARRAY_SIZE(ints), ints); diff -Nru a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c --- a/drivers/input/joystick/twidjoy.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/joystick/twidjoy.c Fri Jul 26 19:58:50 2002 @@ -127,6 +127,8 @@ input_report_abs(dev, ABS_X, -abs_x); input_report_abs(dev, ABS_Y, +abs_y); + + input_sync(dev); } return; @@ -198,10 +200,10 @@ twidjoy->dev.name = twidjoy_name; twidjoy->dev.phys = twidjoy->phys; - twidjoy->dev.idbus = BUS_RS232; - twidjoy->dev.idvendor = SERIO_TWIDJOY; - twidjoy->dev.idproduct = 0x0001; - twidjoy->dev.idversion = 0x0100; + twidjoy->dev.id.bustype = BUS_RS232; + twidjoy->dev.id.vendor = SERIO_TWIDJOY; + twidjoy->dev.id.product = 0x0001; + twidjoy->dev.id.version = 0x0100; twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); @@ -240,9 +242,9 @@ */ static struct serio_dev twidjoy_dev = { - interrupt: twidjoy_interrupt, - connect: twidjoy_connect, - disconnect: twidjoy_disconnect, + .interrupt = twidjoy_interrupt, + .connect = twidjoy_connect, + .disconnect = twidjoy_disconnect, }; /* diff -Nru a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c --- a/drivers/input/joystick/warrior.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/joystick/warrior.c Fri Jul 26 19:58:52 2002 @@ -76,18 +76,19 @@ input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1); input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1); input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1); - return; + break; case 3: /* XY-axis info->data */ input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5))); input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); - return; + break; case 5: /* Throttle, spinner, hat info->data */ input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0)); input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0)); input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5)); - return; + break; } + input_sync(dev); } /* @@ -156,10 +157,10 @@ warrior->dev.name = warrior_name; warrior->dev.phys = warrior->phys; - warrior->dev.idbus = BUS_RS232; - warrior->dev.idvendor = SERIO_WARRIOR; - warrior->dev.idproduct = 0x0001; - warrior->dev.idversion = 0x0100; + warrior->dev.id.bustype = BUS_RS232; + warrior->dev.id.vendor = SERIO_WARRIOR; + warrior->dev.id.product = 0x0001; + warrior->dev.id.version = 0x0100; for (i = 0; i < 2; i++) { warrior->dev.absmax[ABS_X+i] = -64; @@ -194,9 +195,9 @@ */ static struct serio_dev warrior_dev = { - interrupt: warrior_interrupt, - connect: warrior_connect, - disconnect: warrior_disconnect, + .interrupt = warrior_interrupt, + .connect = warrior_connect, + .disconnect = warrior_disconnect, }; /* diff -Nru a/drivers/input/keybdev.c b/drivers/input/keybdev.c --- a/drivers/input/keybdev.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/keybdev.c Fri Jul 26 19:58:52 2002 @@ -72,26 +72,6 @@ #ifdef CONFIG_MAC_EMUMOUSEBTN extern int mac_hid_mouse_emulate_buttons(int, int, int); #endif /* CONFIG_MAC_EMUMOUSEBTN */ -#ifdef CONFIG_MAC_ADBKEYCODES -extern int mac_hid_keyboard_sends_linux_keycodes(void); -#else -#define mac_hid_keyboard_sends_linux_keycodes() 0 -#endif /* CONFIG_MAC_ADBKEYCODES */ -#if defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_ADB_KEYBOARD) -static unsigned char mac_keycodes[256] = { - 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, - 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117, - 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 55, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102 }; -#endif /* CONFIG_MAC_ADBKEYCODES || CONFIG_ADB_KEYBOARD */ static int emulate_raw(unsigned int keycode, int down) { @@ -99,15 +79,6 @@ if (mac_hid_mouse_emulate_buttons(1, keycode, down)) return 0; #endif /* CONFIG_MAC_EMUMOUSEBTN */ -#if defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_ADB_KEYBOARD) - if (!mac_hid_keyboard_sends_linux_keycodes()) { - if (keycode > 255 || !mac_keycodes[keycode]) - return -1; - - handle_scancode((mac_keycodes[keycode] & 0x7f), down); - return 0; - } -#endif /* CONFIG_MAC_ADBKEYCODES || CONFIG_ADB_KEYBOARD */ if (keycode > 255 || !x86_keycodes[keycode]) return -1; @@ -161,11 +132,10 @@ struct input_handle *handle; for (handle = keybdev_handler.handle; handle; handle = handle->hnext) { - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01)); input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02)); input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04)); - + input_sync(handle->dev); } } @@ -226,8 +196,8 @@ static struct input_device_id keybdev_ids[] = { { - flags: INPUT_DEVICE_ID_MATCH_EVBIT, - evbit: { BIT(EV_KEY) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT(EV_KEY) }, }, { }, /* Terminating entry */ }; @@ -235,11 +205,11 @@ MODULE_DEVICE_TABLE(input, keybdev_ids); static struct input_handler keybdev_handler = { - event: keybdev_event, - connect: keybdev_connect, - disconnect: keybdev_disconnect, - name: "keybdev", - id_table: keybdev_ids, + .event = keybdev_event, + .connect = keybdev_connect, + .disconnect = keybdev_disconnect, + .name = "keybdev", + .id_table = keybdev_ids, }; static int __init keybdev_init(void) diff -Nru a/drivers/input/keyboard/Config.help b/drivers/input/keyboard/Config.help --- a/drivers/input/keyboard/Config.help Fri Jul 26 19:58:51 2002 +++ b/drivers/input/keyboard/Config.help Fri Jul 26 19:58:51 2002 @@ -7,7 +7,8 @@ CONFIG_KEYBOARD_ATKBD Say Y here if you want to use the standard AT keyboard. Usually you'll need this, unless you have a different type keyboard (USB, - ADB or other). + ADB or other). This also works for AT keyboards connected over + a PS/2 to serial converter. If unsure, say Y. @@ -24,15 +25,6 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called sunkbd.o. If you want to compile it as a - module, say M here and read . - -CONFIG_KEYBOARD_PS2SERKBD - Say Y here if you want to use a PS/2 to Serial converter with a - keyboard attached to it. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called ps2serkbd.o. If you want to compile it as a module, say M here and read . CONFIG_KEYBOARD_XTKBD diff -Nru a/drivers/input/keyboard/Config.in b/drivers/input/keyboard/Config.in --- a/drivers/input/keyboard/Config.in Fri Jul 26 19:58:52 2002 +++ b/drivers/input/keyboard/Config.in Fri Jul 26 19:58:52 2002 @@ -6,7 +6,6 @@ dep_tristate ' AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO dep_tristate ' Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO -dep_tristate ' PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO dep_tristate ' XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO dep_tristate ' Newton keyboard' CONFIG_KEYBOARD_NEWTON $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile --- a/drivers/input/keyboard/Makefile Fri Jul 26 19:58:51 2002 +++ b/drivers/input/keyboard/Makefile Fri Jul 26 19:58:51 2002 @@ -6,7 +6,6 @@ obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o -obj-$(CONFIG_KEYBOARD_PS2SERKBD) += ps2serkbd.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o diff -Nru a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c --- a/drivers/input/keyboard/amikbd.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/keyboard/amikbd.c Fri Jul 26 19:58:51 2002 @@ -88,10 +88,12 @@ if (scancode == KEY_CAPS) { /* CapsLock is a toggle switch key on Amiga */ input_report_key(&amikbd_dev, scancode, 1); input_report_key(&amikbd_dev, scancode, 0); + input_sync(&amikbd_dev); return; } input_report_key(&amikbd_dev, scancode, down); + input_sync(&amikbd_dev); return; } @@ -121,10 +123,10 @@ amikbd_dev.name = amikbd_name; amikbd_dev.phys = amikbd_phys; - amikbd_dev.idbus = BUS_AMIGA; - amikbd_dev.idvendor = 0x0001; - amikbd_dev.idproduct = 0x0001; - amikbd_dev.idversion = 0x0100; + amikbd_dev.id.bustype = BUS_AMIGA; + amikbd_dev.id.vendor = 0x0001; + amikbd_dev.id.product = 0x0001; + amikbd_dev.id.version = 0x0100; input_register_device(&amikbd_dev); diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c --- a/drivers/input/keyboard/atkbd.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/keyboard/atkbd.c Fri Jul 26 19:58:52 2002 @@ -98,6 +98,7 @@ #define ATKBD_CMD_ENABLE 0x00f4 #define ATKBD_CMD_RESET_DIS 0x00f5 #define ATKBD_CMD_SETALL_MB 0x00f8 +#define ATKBD_CMD_RESEND 0x00fe #define ATKBD_CMD_EX_ENABLE 0x10ea #define ATKBD_CMD_EX_SETLEDS 0x20eb @@ -128,6 +129,7 @@ signed char ack; unsigned char emul; unsigned short id; + unsigned char write; }; /* @@ -141,9 +143,16 @@ int code = data; #ifdef ATKBD_DEBUG - printk(KERN_DEBUG "atkbd.c: Received %02x\n", data); + printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); #endif + /* Interface error. Request that the keyboard resend. */ + if ((flags & (SERIO_FRAME | SERIO_PARITY)) && atkbd->write) { + printk("atkbd.c: frame/parity error: %02x\n", flags); + serio_write(serio, ATKBD_CMD_RESEND); + return; + } + switch (code) { case ATKBD_RET_ACK: atkbd->ack = 1; @@ -187,6 +196,7 @@ break; default: input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release); + input_sync(&atkbd->dev); } atkbd->release = 0; @@ -256,7 +266,7 @@ struct atkbd *atkbd = dev->private; char param[2]; - if (!atkbd->serio->write) + if (!atkbd->write) return -1; switch (type) { @@ -440,15 +450,19 @@ struct atkbd *atkbd; int i; - if ((serio->type & SERIO_TYPE) != SERIO_8042) - return; + if ((serio->type & SERIO_TYPE) != SERIO_8042 && + (((serio->type & SERIO_TYPE) != SERIO_RS232) || (serio->type & SERIO_PROTO) != SERIO_PS2SER)) + return; if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) return; memset(atkbd, 0, sizeof(struct atkbd)); - if (serio->write) { + if ((serio->type & SERIO_TYPE) == SERIO_8042 && serio->write) + atkbd->write = 1; + + if (atkbd->write) { atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); @@ -466,7 +480,7 @@ return; } - if (serio->write) { + if (atkbd->write) { if (atkbd_probe(atkbd)) { serio_close(serio); @@ -496,10 +510,10 @@ atkbd->dev.name = atkbd->name; atkbd->dev.phys = atkbd->phys; - atkbd->dev.idbus = BUS_I8042; - atkbd->dev.idvendor = 0x0001; - atkbd->dev.idproduct = atkbd->set; - atkbd->dev.idversion = atkbd->id; + atkbd->dev.id.bustype = BUS_I8042; + atkbd->dev.id.vendor = 0x0001; + atkbd->dev.id.product = atkbd->set; + atkbd->dev.id.version = atkbd->id; for (i = 0; i < 512; i++) if (atkbd->keycode[i] && atkbd->keycode[i] <= 250) @@ -509,25 +523,27 @@ printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); - if (serio->write) + if (atkbd->write) atkbd_initialize(atkbd); } static struct serio_dev atkbd_dev = { - interrupt: atkbd_interrupt, - connect: atkbd_connect, - disconnect: atkbd_disconnect + .interrupt = atkbd_interrupt, + .connect = atkbd_connect, + .disconnect = atkbd_disconnect }; -/* - * Module init and exit. - */ - -void __init atkbd_setup(char *str, int *ints) +#ifndef MODULE +static int __init atkbd_setup(char *str) { - if (!ints[0]) atkbd_set = ints[1]; + int ints[4]; + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) atkbd_set = ints[1]; + return 1; } +__setup("atkbd_set=", atkbd_setup); +#endif int __init atkbd_init(void) { diff -Nru a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c --- a/drivers/input/keyboard/maple_keyb.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/keyboard/maple_keyb.c Fri Jul 26 19:58:51 2002 @@ -76,6 +76,8 @@ } } + input_sync(dev); + memcpy(kbd->old, kbd->new, 8); } @@ -132,7 +134,7 @@ kbd->dev.event = NULL; kbd->dev.name = dev->product_name; - kbd->dev.idbus = BUS_MAPLE; + kbd->dev.id.bustype = BUS_MAPLE; input_register_device(&kbd->dev); @@ -160,10 +162,10 @@ static struct maple_driver dc_kbd_driver = { - function: MAPLE_FUNC_KEYBOARD, - name: "Dreamcast keyboard", - connect: dc_kbd_connect, - disconnect: dc_kbd_disconnect, + .function = MAPLE_FUNC_KEYBOARD, + .name = "Dreamcast keyboard", + .connect = dc_kbd_connect, + .disconnect = dc_kbd_disconnect, }; diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c --- a/drivers/input/keyboard/newtonkbd.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/keyboard/newtonkbd.c Fri Jul 26 19:58:50 2002 @@ -72,6 +72,8 @@ else if (data == 0xe7) /* end of init sequence */ printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); + + input_sync(&nkbd->dev); } void nkbd_connect(struct serio *serio, struct serio_dev *dev) @@ -110,10 +112,10 @@ nkbd->dev.name = nkbd_name; nkbd->dev.phys = nkbd->phys; - nkbd->dev.idbus = BUS_RS232; - nkbd->dev.idvendor = SERIO_NEWTON; - nkbd->dev.idproduct = 0x0001; - nkbd->dev.idversion = 0x0100; + nkbd->dev.id.bustype = BUS_RS232; + nkbd->dev.id.vendor = SERIO_NEWTON; + nkbd->dev.id.product = 0x0001; + nkbd->dev.id.version = 0x0100; input_register_device(&nkbd->dev); @@ -129,9 +131,9 @@ } struct serio_dev nkbd_dev = { - interrupt: nkbd_interrupt, - connect: nkbd_connect, - disconnect: nkbd_disconnect + .interrupt = nkbd_interrupt, + .connect = nkbd_connect, + .disconnect = nkbd_disconnect }; int __init nkbd_init(void) diff -Nru a/drivers/input/keyboard/ps2serkbd.c b/drivers/input/keyboard/ps2serkbd.c --- a/drivers/input/keyboard/ps2serkbd.c Fri Jul 26 19:58:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,298 +0,0 @@ -/* - * based on: sunkbd.c and ps2serkbd.c - * - * $Id: ps2serkbd.c,v 1.5 2001/09/25 10:12:07 vojtech Exp $ - */ - -/* - * PS/2 keyboard via adapter at serial port driver for Linux - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define ATKBD_CMD_SETLEDS 0x10ed -#define ATKBD_CMD_GSCANSET 0x11f0 -#define ATKBD_CMD_SSCANSET 0x10f0 -#define ATKBD_CMD_GETID 0x02f2 -#define ATKBD_CMD_ENABLE 0x00f4 -#define ATKBD_CMD_RESET_DIS 0x00f5 -#define ATKBD_CMD_SETALL_MB 0x00f8 -#define ATKBD_CMD_EX_ENABLE 0x10ea -#define ATKBD_CMD_EX_SETLEDS 0x20eb - -#define ATKBD_RET_ACK 0xfa -#define ATKBD_RET_NAK 0xfe - -#define ATKBD_KEY_UNKNOWN 0 -#define ATKBD_KEY_BAT 251 -#define ATKBD_KEY_EMUL0 252 -#define ATKBD_KEY_EMUL1 253 -#define ATKBD_KEY_RELEASE 254 -#define ATKBD_KEY_NULL 255 - -static unsigned char ps2serkbd_set2_keycode[512] = { - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, - 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, - 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, - 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, - 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, - 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123, - 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, - 252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, - 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, - 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125, - 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127, - 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142, - 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138, - 0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0, - 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112, - 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 -}; - -/* - * Per-keyboard data. - */ - -struct ps2serkbd { - unsigned char keycode[512]; - struct input_dev dev; - struct serio *serio; - char name[64]; - char phys[32]; - struct tq_struct tq; - unsigned char cmdbuf[4]; - unsigned char cmdcnt; - unsigned char set; - char release; - char ack; - char emul; - char error; - unsigned short id; -}; - -/* - * ps2serkbd_interrupt() is called by the low level driver when a character - * is received. - */ - -static void ps2serkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) -{ - static int event_count=0; - struct ps2serkbd* ps2serkbd = serio->private; - int code=data; - -#if 0 - printk(KERN_WARNING "ps2serkbd.c(%8d): (scancode %#x)\n", event_count, data); -#endif - event_count++; - - switch (code) { - case ATKBD_RET_ACK: - ps2serkbd->ack = 1; - return; - case ATKBD_RET_NAK: - ps2serkbd->ack = -1; - return; - } - - if (ps2serkbd->cmdcnt) { - ps2serkbd->cmdbuf[--ps2serkbd->cmdcnt] = code; - return; - } - - switch (ps2serkbd->keycode[code]) { - case ATKBD_KEY_BAT: - queue_task(&ps2serkbd->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); - return; - case ATKBD_KEY_EMUL0: - ps2serkbd->emul = 1; - return; - case ATKBD_KEY_EMUL1: - ps2serkbd->emul = 2; - return; - case ATKBD_KEY_RELEASE: - ps2serkbd->release = 1; - return; - } - - if (ps2serkbd->emul) { - if (--ps2serkbd->emul) return; - code |= 0x100; - } - - switch (ps2serkbd->keycode[code]) { - case ATKBD_KEY_NULL: - break; - case ATKBD_KEY_UNKNOWN: - printk(KERN_WARNING "ps2serkbd.c: Unknown key (set %d, scancode %#x) %s.\n", - ps2serkbd->set, code, ps2serkbd->release ? "released" : "pressed"); - break; - default: - input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release); - } - - ps2serkbd->release = 0; -} - -/* - * ps2serkbd_event() handles events from the input module. - */ - -static int ps2serkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - switch (type) { - - case EV_LED: - - return 0; - } - - return -1; -} - -static int ps2serkbd_initialize(struct ps2serkbd *ps2serkbd) -{ - return 0; -} - -static void ps2serkbd_reinit(void *data) -{ -} - - -static void ps2serkbd_connect(struct serio *serio, struct serio_dev *dev) -{ - struct ps2serkbd *ps2serkbd; - int i; - - if ((serio->type & SERIO_TYPE) != SERIO_RS232) - return; - - if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_PS2SER) - return; - - - if (!(ps2serkbd = kmalloc(sizeof(struct ps2serkbd), GFP_KERNEL))) - return; - - memset(ps2serkbd, 0, sizeof(struct ps2serkbd)); - - ps2serkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - ps2serkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - - ps2serkbd->serio = serio; - - ps2serkbd->dev.keycode = ps2serkbd->keycode; - ps2serkbd->dev.event = ps2serkbd_event; - ps2serkbd->dev.private = ps2serkbd; - - ps2serkbd->tq.routine = ps2serkbd_reinit; - ps2serkbd->tq.data = ps2serkbd; - - serio->private = ps2serkbd; - - if (serio_open(serio, dev)) { - kfree(ps2serkbd); - return; - } - - if (ps2serkbd_initialize(ps2serkbd) < 0) { - serio_close(serio); - kfree(ps2serkbd); - return; - } - - ps2serkbd->set = 4; - - if (ps2serkbd->set == 4) { - ps2serkbd->dev.ledbit[0] |= 0; - sprintf(ps2serkbd->name, "AT Set 2 Extended keyboard\n"); - } - memcpy(ps2serkbd->keycode, ps2serkbd_set2_keycode, sizeof(ps2serkbd->keycode)); - - sprintf(ps2serkbd->phys, "%s/input0", serio->phys); - - ps2serkbd->dev.name = ps2serkbd->name; - ps2serkbd->dev.phys = ps2serkbd->phys; - ps2serkbd->dev.idbus = BUS_RS232; - ps2serkbd->dev.idvendor = SERIO_PS2SER; - ps2serkbd->dev.idproduct = ps2serkbd->set; - ps2serkbd->dev.idversion = ps2serkbd->id; - - for (i = 0; i < 512; i++) - if (ps2serkbd->keycode[i] && ps2serkbd->keycode[i] <= 250) - set_bit(ps2serkbd->keycode[i], ps2serkbd->dev.keybit); - - input_register_device(&ps2serkbd->dev); -} - -/* - * ps2serkbd_disconnect() unregisters and closes behind us. - */ - -static void ps2serkbd_disconnect(struct serio *serio) -{ - struct ps2serkbd *ps2serkbd = serio->private; - input_unregister_device(&ps2serkbd->dev); - serio_close(serio); - kfree(ps2serkbd); -} - -static struct serio_dev ps2serkbd_dev = { -interrupt: - ps2serkbd_interrupt, -connect: - ps2serkbd_connect, -disconnect: - ps2serkbd_disconnect -}; - -/* - * The functions for insering/removing us as a module. - */ - -int __init ps2serkbd_init(void) -{ - serio_register_device(&ps2serkbd_dev); - return 0; -} - -void __exit ps2serkbd_exit(void) -{ - serio_unregister_device(&ps2serkbd_dev); -} - -module_init(ps2serkbd_init); -module_exit(ps2serkbd_exit); diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c --- a/drivers/input/keyboard/sunkbd.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/keyboard/sunkbd.c Fri Jul 26 19:58:50 2002 @@ -121,6 +121,7 @@ default: if (sunkbd->keycode[data & SUNKBD_KEY]) { input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); + input_sync(&sunkbd->dev); } else { printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); @@ -271,10 +272,10 @@ sunkbd->dev.name = sunkbd->name; sunkbd->dev.phys = sunkbd->phys; - sunkbd->dev.idbus = BUS_RS232; - sunkbd->dev.idvendor = SERIO_SUNKBD; - sunkbd->dev.idproduct = sunkbd->type; - sunkbd->dev.idversion = 0x0100; + sunkbd->dev.id.bustype = BUS_RS232; + sunkbd->dev.id.vendor = SERIO_SUNKBD; + sunkbd->dev.id.product = sunkbd->type; + sunkbd->dev.id.version = 0x0100; input_register_device(&sunkbd->dev); @@ -294,9 +295,9 @@ } static struct serio_dev sunkbd_dev = { - interrupt: sunkbd_interrupt, - connect: sunkbd_connect, - disconnect: sunkbd_disconnect + .interrupt = sunkbd_interrupt, + .connect = sunkbd_connect, + .disconnect = sunkbd_disconnect }; /* diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c --- a/drivers/input/keyboard/xtkbd.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/keyboard/xtkbd.c Fri Jul 26 19:58:50 2002 @@ -75,6 +75,7 @@ if (xtkbd->keycode[data & XTKBD_KEY]) { input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); + input_sync(&xtkbd->dev); } else { printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); @@ -118,10 +119,10 @@ xtkbd->dev.name = xtkbd_name; xtkbd->dev.phys = xtkbd->phys; - xtkbd->dev.idbus = BUS_XTKBD; - xtkbd->dev.idvendor = 0x0001; - xtkbd->dev.idproduct = 0x0001; - xtkbd->dev.idversion = 0x0100; + xtkbd->dev.id.bustype = BUS_XTKBD; + xtkbd->dev.id.vendor = 0x0001; + xtkbd->dev.id.product = 0x0001; + xtkbd->dev.id.version = 0x0100; input_register_device(&xtkbd->dev); @@ -137,9 +138,9 @@ } struct serio_dev xtkbd_dev = { - interrupt: xtkbd_interrupt, - connect: xtkbd_connect, - disconnect: xtkbd_disconnect + .interrupt = xtkbd_interrupt, + .connect = xtkbd_connect, + .disconnect = xtkbd_disconnect }; int __init xtkbd_init(void) diff -Nru a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c --- a/drivers/input/mouse/amimouse.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/mouse/amimouse.c Fri Jul 26 19:58:50 2002 @@ -68,6 +68,8 @@ input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100); input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400); + + input_sync(&amimouse_dev); } static int amimouse_open(struct input_dev *dev) @@ -110,10 +112,10 @@ amimouse_dev.name = amimouse_name; amimouse_dev.phys = amimouse_phys; - amimouse_dev.idbus = BUS_AMIGA; - amimouse_dev.idvendor = 0x0001; - amimouse_dev.idproduct = 0x0002; - amimouse_dev.idversion = 0x0100; + amimouse_dev.id.bustype = BUS_AMIGA; + amimouse_dev.id.vendor = 0x0001; + amimouse_dev.id.product = 0x0002; + amimouse_dev.id.version = 0x0100; input_register_device(&amimouse_dev); diff -Nru a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c --- a/drivers/input/mouse/inport.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mouse/inport.c Fri Jul 26 19:58:51 2002 @@ -108,17 +108,13 @@ } static struct input_dev inport_dev = { - evbit: { BIT(EV_KEY) | BIT(EV_REL) }, - keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - relbit: { BIT(REL_X) | BIT(REL_Y) }, - open: inport_open, - close: inport_close, - name: INPORT_NAME, - phys: "isa023c/input0", - idbus: BUS_ISA, - idvendor: INPORT_VENDOR, - idproduct: 0x0001, - idversion: 0x0100, + .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, + .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + .relbit = { BIT(REL_X) | BIT(REL_Y) }, + .open = inport_open, + .close = inport_close, + .name = INPORT_NAME, + .phys = "isa023c/input0", }; static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -143,6 +139,8 @@ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + + input_sync(&inport_dev); } #ifndef MODULE @@ -176,6 +174,11 @@ request_region(INPORT_BASE, INPORT_EXTENT, "inport"); input_register_device(&inport_dev); + inport_dev.id.bustype =BUS_ISA; + inport_dev.id.vendor =INPORT_VENDOR; + inport_dev.id.product =0x0001; + inport_dev.id.version =0x0100; + printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq); diff -Nru a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c --- a/drivers/input/mouse/logibm.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mouse/logibm.c Fri Jul 26 19:58:51 2002 @@ -98,17 +98,13 @@ } static struct input_dev logibm_dev = { - evbit: { BIT(EV_KEY) | BIT(EV_REL) }, - keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - relbit: { BIT(REL_X) | BIT(REL_Y) }, - open: logibm_open, - close: logibm_close, - name: "Logitech bus mouse", - phys: "isa023c/input0", - idbus: BUS_ISA, - idvendor: 0x0003, - idproduct: 0x0001, - idversion: 0x0100, + .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, + .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + .relbit = { BIT(REL_X) | BIT(REL_Y) }, + .open = logibm_open, + .close = logibm_close, + .name = "Logitech bus mouse", + .phys = "isa023c/input0", }; static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -125,13 +121,16 @@ outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT); buttons = inb(LOGIBM_DATA_PORT); dy |= (buttons & 0xf) << 4; - buttons = ~buttons; + buttons = ~buttons >> 5; input_report_rel(&logibm_dev, REL_X, dx); - input_report_rel(&logibm_dev, REL_Y, 255 - dy); - input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 1); - input_report_key(&logibm_dev, BTN_LEFT, buttons & 2); - input_report_key(&logibm_dev, BTN_RIGHT, buttons & 4); + input_report_rel(&logibm_dev, REL_Y, dy); + input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1); + input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2); + input_report_key(&logibm_dev, BTN_LEFT, buttons & 4); + input_sync(&logibm_dev); + + outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); } #ifndef MODULE @@ -147,7 +146,7 @@ static int __init logibm_init(void) { - if (request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { + if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE); return -EBUSY; } @@ -166,6 +165,10 @@ outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); input_register_device(&logibm_dev); + logibm_dev.id.bustype = BUS_ISA; + logibm_dev.id.vendor = 0x0003; + logibm_dev.id.product = 0x0001; + logibm_dev.id.version = 0x0100; printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); diff -Nru a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c --- a/drivers/input/mouse/maplemouse.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mouse/maplemouse.c Fri Jul 26 19:58:51 2002 @@ -40,6 +40,7 @@ input_report_rel(dev, REL_X, relx); input_report_rel(dev, REL_Y, rely); input_report_rel(dev, REL_WHEEL, relz); + input_sync(dev); } @@ -107,10 +108,10 @@ static struct maple_driver dc_mouse_driver = { - function: MAPLE_FUNC_MOUSE, - name: "Dreamcast mouse", - connect: dc_mouse_connect, - disconnect: dc_mouse_disconnect, + .function = MAPLE_FUNC_MOUSE, + .name = "Dreamcast mouse", + .connect = dc_mouse_connect, + .disconnect = dc_mouse_disconnect, }; diff -Nru a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c --- a/drivers/input/mouse/pc110pad.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mouse/pc110pad.c Fri Jul 26 19:58:51 2002 @@ -78,6 +78,7 @@ pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); input_report_abs(&pc110pad_dev, ABS_Y, pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); + input_sync(&pc110pad_dev); pc110pad_count = 0; } @@ -90,19 +91,14 @@ static int pc110pad_open(struct input_dev *dev) { - unsigned long flags; - if (pc110pad_used++) return 0; - save_flags(flags); - cli(); pc110pad_interrupt(0,0,0); pc110pad_interrupt(0,0,0); pc110pad_interrupt(0,0,0); outb(PC110PAD_ON, pc110pad_io + 2); pc110pad_count = 0; - restore_flags(flags); return 0; } @@ -136,10 +132,10 @@ pc110pad_dev.name = pc110pad_name; pc110pad_dev.phys = pc110pad_phys; - pc110pad_dev.idbus = BUS_ISA; - pc110pad_dev.idvendor = 0x0003; - pc110pad_dev.idproduct = 0x0001; - pc110pad_dev.idversion = 0x0100; + pc110pad_dev.id.bustype = BUS_ISA; + pc110pad_dev.id.vendor = 0x0003; + pc110pad_dev.id.product = 0x0001; + pc110pad_dev.id.version = 0x0100; input_register_device(&pc110pad_dev); diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c --- a/drivers/input/mouse/psmouse.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mouse/psmouse.c Fri Jul 26 19:58:51 2002 @@ -102,7 +102,7 @@ case 1: /* Mouse extra info */ input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, - (int) (packet[2] & 7) - (int) (packet[2] & 8)); + (int) (packet[2] & 8) - (int) (packet[2] & 7)); input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); @@ -111,7 +111,7 @@ case 3: /* TouchPad extra info */ input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, - (int) ((packet[2] >> 4) & 7) - (int) ((packet[2] >> 4) & 8)); + (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); packet[0] = packet[2] | 0x08; break; @@ -135,14 +135,14 @@ */ if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS) - input_report_rel(dev, REL_WHEEL, (signed char) packet[3]); + input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); /* * Scroll wheel and buttons on IntelliMouse Explorer */ if (psmouse->type == PSMOUSE_IMEX) { - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 7) - (int) (packet[2] & 8)); + input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); } @@ -167,6 +167,7 @@ input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); + input_sync(dev); } /* @@ -600,10 +601,10 @@ psmouse->dev.name = psmouse->devname; psmouse->dev.phys = psmouse->phys; - psmouse->dev.idbus = BUS_I8042; - psmouse->dev.idvendor = psmouse->type; - psmouse->dev.idproduct = 0x0002; - psmouse->dev.idversion = 0x0100; + psmouse->dev.id.bustype = BUS_I8042; + psmouse->dev.id.vendor = psmouse->type; + psmouse->dev.id.product = 0x0002; + psmouse->dev.id.version = 0x0100; input_register_device(&psmouse->dev); @@ -613,9 +614,9 @@ } static struct serio_dev psmouse_dev = { - interrupt: psmouse_interrupt, - connect: psmouse_connect, - disconnect: psmouse_disconnect + .interrupt = psmouse_interrupt, + .connect = psmouse_connect, + .disconnect = psmouse_disconnect }; int __init psmouse_init(void) diff -Nru a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c --- a/drivers/input/mouse/rpcmouse.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mouse/rpcmouse.c Fri Jul 26 19:58:51 2002 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -35,15 +36,11 @@ static short rpcmouse_lastx, rpcmouse_lasty; static struct input_dev rpcmouse_dev = { - evbit: { BIT(EV_KEY) | BIT(EV_REL) }, - keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - relbit: { BIT(REL_X) | BIT(REL_Y) }, - name: "Acorn RiscPC Mouse", - phys: "rpcmouse/input0", - idbus: BUS_HOST, - idvendor: 0x0005, - idproduct: 0x0001, - idversion: 0x0100, + .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, + .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + .relbit = { BIT(REL_X) | BIT(REL_Y) }, + .name = "Acorn RiscPC Mouse", + .phys = "rpcmouse/input0", }; static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) @@ -63,9 +60,11 @@ input_report_rel(&rpcmouse_dev, REL_X, dx); input_report_rel(&rpcmouse_dev, REL_Y, dy); - input_report_key(&rpcmouse_dev, BTN_LEFT, buttons & 0x10); - input_report_key(&rpcmouse_dev, BTN_MIDDLE, buttons & 0x20); - input_report_key(&rpcmouse_dev, BTN_RIGHT, buttons & 0x40); + input_report_key(&rpcmouse_dev, BTN_LEFT, b & 0x10); + input_report_key(&rpcmouse_dev, BTN_MIDDLE, b & 0x20); + input_report_key(&rpcmouse_dev, BTN_RIGHT, b & 0x40); + + input_sync(&rpcmouse_dev); } static int __init rpcmouse_init(void) @@ -79,6 +78,11 @@ } input_register_device(&rpcmouse_dev); + rpcmouse.id.bustype =BUS_HOST, + rpcmouse.id.vendor =0x0005, + rpcmouse.id.product =0x0001, + rpcmouse.id.version =0x0100, + printk(KERN_INFO "input: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE); return 0; diff -Nru a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c --- a/drivers/input/mouse/sermouse.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/mouse/sermouse.c Fri Jul 26 19:58:50 2002 @@ -89,6 +89,8 @@ break; } + input_sync(dev); + if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1))) sermouse->count = 0; } @@ -188,6 +190,8 @@ break; } + input_sync(dev); + sermouse->count++; } @@ -263,10 +267,10 @@ sermouse->dev.name = sermouse_protocols[sermouse->type]; sermouse->dev.phys = sermouse->phys; - sermouse->dev.idbus = BUS_RS232; - sermouse->dev.idvendor = sermouse->type; - sermouse->dev.idproduct = c; - sermouse->dev.idversion = 0x0100; + sermouse->dev.id.bustype = BUS_RS232; + sermouse->dev.id.vendor = sermouse->type; + sermouse->dev.id.product = c; + sermouse->dev.id.version = 0x0100; if (serio_open(serio, dev)) { kfree(sermouse); @@ -279,9 +283,9 @@ } static struct serio_dev sermouse_dev = { - interrupt: sermouse_interrupt, - connect: sermouse_connect, - disconnect: sermouse_disconnect + .interrupt = sermouse_interrupt, + .connect = sermouse_connect, + .disconnect = sermouse_disconnect }; int __init sermouse_init(void) diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c --- a/drivers/input/mousedev.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/mousedev.c Fri Jul 26 19:58:51 2002 @@ -94,9 +94,10 @@ struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; struct mousedev **mousedev = mousedevs; struct mousedev_list *list; - int index, size; + int index, size, wake; while (*mousedev) { + wake = 0; list = (*mousedev)->list; while (list) { switch (type) { @@ -158,16 +159,20 @@ case 2: return; } break; - } - - list->ready = 1; - - kill_fasync(&list->fasync, SIGIO, POLL_IN); + case EV_SYN: + switch (code) { + case SYN_REPORT: + list->ready = 1; + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake = 1; + break; + } + } list = list->next; } - - wake_up_interruptible(&((*mousedev)->wait)); + if (wake) + wake_up_interruptible(&((*mousedev)->wait)); mousedev++; } } @@ -414,13 +419,13 @@ } struct file_operations mousedev_fops = { - owner: THIS_MODULE, - read: mousedev_read, - write: mousedev_write, - poll: mousedev_poll, - open: mousedev_open, - release: mousedev_release, - fasync: mousedev_fasync, + .owner = THIS_MODULE, + .read = mousedev_read, + .write = mousedev_write, + .poll = mousedev_poll, + .open = mousedev_open, + .release = mousedev_release, + .fasync = mousedev_fasync, }; static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) @@ -477,17 +482,17 @@ static struct input_device_id mousedev_ids[] = { { - flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, - evbit: { BIT(EV_KEY) | BIT(EV_REL) }, - keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, - relbit: { BIT(REL_X) | BIT(REL_Y) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, + .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, + .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, + .relbit = { BIT(REL_X) | BIT(REL_Y) }, }, /* A mouse like device, at least one button, two relative axes */ { - flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, - evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, - keybit: { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, - absbit: { BIT(ABS_X) | BIT(ABS_Y) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, + .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, }, /* A tablet like device, at least touch detection, two absolute axes */ { }, /* Terminating entry */ @@ -496,13 +501,13 @@ MODULE_DEVICE_TABLE(input, mousedev_ids); static struct input_handler mousedev_handler = { - event: mousedev_event, - connect: mousedev_connect, - disconnect: mousedev_disconnect, - fops: &mousedev_fops, - minor: MOUSEDEV_MINOR_BASE, - name: "mousedev", - id_table: mousedev_ids, + .event = mousedev_event, + .connect = mousedev_connect, + .disconnect = mousedev_disconnect, + .fops = &mousedev_fops, + .minor = MOUSEDEV_MINOR_BASE, + .name = "mousedev", + .id_table = mousedev_ids, }; #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX diff -Nru a/drivers/input/power.c b/drivers/input/power.c --- a/drivers/input/power.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/power.c Fri Jul 26 19:58:52 2002 @@ -136,18 +136,18 @@ static struct input_device_id power_ids[] = { { - flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - evbit: { BIT(EV_KEY) }, - keybit: { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT(EV_KEY) }, + .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } }, { - flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - evbit: { BIT(EV_KEY) }, - keybit: { [LONG(KEY_POWER)] = BIT(KEY_POWER) } + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT(EV_KEY) }, + .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) } }, { - flags: INPUT_DEVICE_ID_MATCH_EVBIT, - evbit: { BIT(EV_PWR) }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT(EV_PWR) }, }, { }, /* Terminating entry */ }; @@ -155,11 +155,11 @@ MODULE_DEVICE_TABLE(input, power_ids); static struct input_handler power_handler = { - event: power_event, - connect: power_connect, - disconnect: power_disconnect, - name: "power", - id_table: power_ids, + .event = power_event, + .connect = power_connect, + .disconnect = power_disconnect, + .name = "power", + .id_table = power_ids, }; static int __init power_init(void) diff -Nru a/drivers/input/serio/Config.in b/drivers/input/serio/Config.in --- a/drivers/input/serio/Config.in Fri Jul 26 19:58:52 2002 +++ b/drivers/input/serio/Config.in Fri Jul 26 19:58:52 2002 @@ -12,9 +12,17 @@ fi dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO -dep_tristate ' Q40 keyboard controller' CONFIG_SERIO_Q40KBD $CONFIG_SERIO +if [ "$CONFIG_Q40" = "y" ]; then + dep_tristate ' Q40 keyboard controller' CONFIG_SERIO_Q40KBD $CONFIG_SERIO +fi dep_tristate ' Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_tristate ' Acorn RiscPC keyboard controller' CONFIG_SERIO_ACORN $CONFIG_SERIO +fi +if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + dep_tristate ' AMBA KMI keyboard controller' CONFIG_SERIO_AMBAKMI $CONFIG_SERIO +fi +if [ "$CONFIG_SA1111" = "y" ]; then + dep_tristate ' Intel SA1111 keyboard controller' CONFIG_SERIO_SA1111 $CONFIG_SERIO fi diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile --- a/drivers/input/serio/Makefile Fri Jul 26 19:58:50 2002 +++ b/drivers/input/serio/Makefile Fri Jul 26 19:58:50 2002 @@ -14,6 +14,8 @@ obj-$(CONFIG_SERIO_SERPORT) += serport.o obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o +obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o +obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o # The global Rules.make. diff -Nru a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/ambakmi.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,158 @@ +/* + * linux/drivers/input/serio/amba_kmi.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2002 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern struct pt_regs *kbd_pt_regs; + +#define KMI_BASE (kmi->base) + +struct amba_kmi_port { + struct serio io; + struct amba_kmi_port *next; + unsigned long base; + unsigned int irq; + unsigned int divisor; + char name[32]; + char phys[16]; +}; + +static void amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct amba_kmi_port *kmi = dev_id; + unsigned int status = __raw_readb(KMIIR); + + kbd_pt_regs = regs; + + while (status & KMIIR_RXINTR) { + serio_interrupt(&kmi->io, __raw_readb(KMIDATA), 0); + status = __raw_readb(KMIIR); + } +} + +static int amba_kmi_write(struct serio *io, unsigned char val) +{ + struct amba_kmi_port *kmi = io->driver; + unsigned int timeleft = 10000; /* timeout in 100ms */ + + while ((__raw_readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) + udelay(10); + + if (timeleft) + __raw_writeb(val, KMIDATA); + + return timeleft ? 0 : SERIO_TIMEOUT; +} + +static int amba_kmi_open(struct serio *io) +{ + struct amba_kmi_port *kmi = io->driver; + int ret; + + __raw_writeb(kmi->divisor, KMICLKDIV); + __raw_writeb(KMICR_EN, KMICR); + + ret = request_irq(kmi->irq, amba_kmi_int, 0, kmi->phys, kmi); + if (ret) { + printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); + __raw_writeb(0, KMICR); + return ret; + } + + __raw_writeb(KMICR_EN | KMICR_RXINTREN, KMICR); + + return 0; +} + +static void amba_kmi_close(struct serio *io) +{ + struct amba_kmi_port *kmi = io->driver; + + free_irq(kmi->irq, kmi); + + __raw_writeb(0, KMICR); +} + +static struct amba_kmi_port *list; + +static int __init amba_kmi_init_one(char *type, unsigned long base, int irq, int nr) +{ + struct amba_kmi_port *kmi; + + kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); + if (!kmi) + return -ENOMEM; + + memset(kmi, 0, sizeof(struct amba_kmi_port)); + + kmi->io.type = SERIO_8042; + kmi->io.write = amba_kmi_write; + kmi->io.open = amba_kmi_open; + kmi->io.close = amba_kmi_close; + kmi->io.name = kmi->name; + kmi->io.phys = kmi->phys; + kmi->io.driver = kmi; + + kmi->base = base; + kmi->irq = irq; + kmi->divisor = 24 / 8 - 1; + + kmi->next = list; + list = kmi; + + snprintf(kmi->name, sizeof(kmi->name), "AMBA KMI PS/2 %s port", type); + snprintf(kmi->phys, sizeof(kmi->phys), "amba/serio%d", nr); + + serio_register_port(&kmi->io); + return 0; +} + +static int __init amba_kmi_init(void) +{ + amba_kmi_init_one("keyboard", IO_ADDRESS(KMI0_BASE), IRQ_KMIINT0, 0); + amba_kmi_init_one("mouse", IO_ADDRESS(KMI1_BASE), IRQ_KMIINT1, 1); + return 0; +} + +static void __exit amba_kmi_exit(void) +{ + struct amba_kmi_port *kmi, *next; + + kmi = list; + while (kmi) { + next = kmi->next; + + serio_unregister_port(&kmi->io); + kfree(kmi); + + kmi = next; + } +} + +module_init(amba_kmi_init); +module_exit(amba_kmi_exit); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("AMBA KMI controller driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c --- a/drivers/input/serio/ct82c710.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/serio/ct82c710.c Fri Jul 26 19:58:50 2002 @@ -141,12 +141,12 @@ static struct serio ct82c710_port = { - type: SERIO_8042, - name: ct82c710_name, - phys: ct82c710_phys, - write: ct82c710_write, - open: ct82c710_open, - close: ct82c710_close, + .type = SERIO_8042, + .name = ct82c710_name, + .phys = ct82c710_phys, + .write = ct82c710_write, + .open = ct82c710_open, + .close = ct82c710_close, }; /* diff -Nru a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h --- a/drivers/input/serio/i8042-ppcio.h Fri Jul 26 19:58:51 2002 +++ b/drivers/input/serio/i8042-ppcio.h Fri Jul 26 19:58:51 2002 @@ -18,6 +18,9 @@ extern void *kb_cs; extern void *kb_data; +#define I8042_COMMAND_REG (*(int *)kb_cs) +#define I8042_DATA_REG (*(int *)kb_data) + static inline int i8042_read_data(void) { return readb(kb_data); @@ -56,6 +59,9 @@ #define I8042_KBD_PHYS_DESC "spruceps2/serio0" #define I8042_AUX_PHYS_DESC "spruceps2/serio1" + +#define I8042_COMMAND_REG 0xff810000 +#define I8042_DATA_REG 0xff810001 static inline int i8042_read_data(void) { diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/serio/i8042.c Fri Jul 26 19:58:50 2002 @@ -31,11 +31,13 @@ MODULE_PARM(i8042_unlock, "1i"); MODULE_PARM(i8042_reset, "1i"); MODULE_PARM(i8042_direct, "1i"); +MODULE_PARM(i8042_restore_ctr, "1i"); static int i8042_noaux; static int i8042_unlock; static int i8042_reset; static int i8042_direct; +static int i8042_restore_ctr; spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED; @@ -111,8 +113,9 @@ while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) #ifdef I8042_DEBUG_IO - printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n", - i8042_read_data(), (int) (jiffies - i8042_start)); + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush, %s) [%d]\n", + i8042_read_data(), i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd", + (int) (jiffies - i8042_start)); #else i8042_read_data(); #endif @@ -123,11 +126,11 @@ } /* - * i8042_command() executes a command on the i8042. It also sends the input parameter(s) - * of the commands to it, and receives the output value(s). The parameters are to be - * stored in the param array, and the output is placed into the same array. The number - * of the parameters and output values is encoded in bits 8-11 of the command - * number. + * i8042_command() executes a command on the i8042. It also sends the input + * parameter(s) of the commands to it, and receives the output value(s). The + * parameters are to be stored in the param array, and the output is placed + * into the same array. The number of the parameters and output values is + * encoded in bits 8-11 of the command number. */ static int i8042_command(unsigned char *param, int command) @@ -182,9 +185,6 @@ /* * i8042_kbd_write() sends a byte out through the keyboard interface. - * It also automatically refreshes the CTR value, since some i8042's - * trash their CTR after attempting to send data to an nonexistent - * device. */ static int i8042_kbd_write(struct serio *port, unsigned char c) @@ -222,11 +222,12 @@ retval = i8042_command(&c, I8042_CMD_AUX_SEND); /* - * Here we restore the CTR value. I don't know why, but i8042's in half-AT - * mode tend to trash their CTR when doing the AUX_SEND command. + * Here we restore the CTR value if requested. I don't know why, but i8042's in + * half-AT mode tend to trash their CTR when doing the AUX_SEND command. */ - retval |= i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR); + if (i8042_restore_ctr) + retval |= i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR); /* * Make sure the interrupt happens and the character is received even @@ -240,16 +241,14 @@ /* * i8042_open() is called when a port is open by the higher layer. - * It allocates an interrupt and enables the port. + * It allocates the interrupt and enables in in the chip. */ static int i8042_open(struct serio *port) { struct i8042_values *values = port->driver; -/* - * Allocate the interrupt - */ + i8042_flush(); if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) { printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name); @@ -258,10 +257,6 @@ return -1; } -/* - * Enable the interrupt. - */ - i8042_ctr |= values->irqen; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { @@ -269,22 +264,21 @@ return -1; } + i8042_interrupt(0, NULL, NULL); + return 0; } /* - * i8042_close() frees the interrupt, and disables the interface when the - * upper layer doesn't need it anymore. + * i8042_close() frees the interrupt, so that it can possibly be used + * by another driver. We never know - if the user doesn't have a mouse, + * the BIOS could have used the AUX interupt for PCI. */ static void i8042_close(struct serio *port) { struct i8042_values *values = port->driver; -/* - * Disable the interrupt. - */ - i8042_ctr &= ~values->irqen; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { @@ -292,11 +286,9 @@ return; } -/* - * Free the interrupt - */ - free_irq(values->irq, NULL); + + i8042_flush(); } /* @@ -304,41 +296,41 @@ */ static struct i8042_values i8042_kbd_values = { - irq: I8042_KBD_IRQ, - irqen: I8042_CTR_KBDINT, - disable: I8042_CTR_KBDDIS, - name: "KBD", - exists: 0, + .irq = I8042_KBD_IRQ, + .irqen = I8042_CTR_KBDINT, + .disable = I8042_CTR_KBDDIS, + .name = "KBD", + .exists = 0, }; static struct serio i8042_kbd_port = { - type: SERIO_8042, - write: i8042_kbd_write, - open: i8042_open, - close: i8042_close, - driver: &i8042_kbd_values, - name: "i8042 Kbd Port", - phys: I8042_KBD_PHYS_DESC, + .type = SERIO_8042, + .write = i8042_kbd_write, + .open = i8042_open, + .close = i8042_close, + .driver = &i8042_kbd_values, + .name = "i8042 Kbd Port", + .phys = I8042_KBD_PHYS_DESC, }; static struct i8042_values i8042_aux_values = { - irq: I8042_AUX_IRQ, - irqen: I8042_CTR_AUXINT, - disable: I8042_CTR_AUXDIS, - name: "AUX", - exists: 0, + .irq = I8042_AUX_IRQ, + .irqen = I8042_CTR_AUXINT, + .disable = I8042_CTR_AUXDIS, + .name = "AUX", + .exists = 0, }; static struct serio i8042_aux_port = { - type: SERIO_8042, - write: i8042_aux_write, - open: i8042_open, - close: i8042_close, - driver: &i8042_aux_values, - name: "i8042 Aux Port", - phys: I8042_AUX_PHYS_DESC, + .type = SERIO_8042, + .write = i8042_aux_write, + .open = i8042_open, + .close = i8042_close, + .driver = &i8042_aux_values, + .name = "i8042 Aux Port", + .phys = I8042_AUX_PHYS_DESC, }; /* @@ -362,7 +354,7 @@ ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); #ifdef I8042_DEBUG_IO - printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s, %d) [%d]\n", + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt, %s, %d) [%d]\n", data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, (int) (jiffies - i8042_start)); #endif @@ -391,23 +383,14 @@ /* * i8042_controller init initializes the i8042 controller, and, - * most importantly, sets it into non-xlated mode. + * most importantly, sets it into non-xlated mode if that's + * desired. */ static int __init i8042_controller_init(void) { /* - * Check the i/o region before we touch it. - */ -#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) - if (check_region(I8042_DATA_REG, 16)) { - printk(KERN_ERR "i8042.c: %#x port already in use!\n", I8042_DATA_REG); - return -1; - } -#endif - -/* * Test the i8042. We need to know if it thinks it's working correctly * before doing anything else. */ @@ -431,7 +414,7 @@ } /* - * Read the CTR. + * Save the CTR for restoral on unload / reboot. */ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { @@ -439,14 +422,10 @@ return -1; } -/* - * Save the CTR for restoral on unload / reboot. - */ - i8042_initial_ctr = i8042_ctr; /* - * Disable both interfaces and their interrupts. + * Disable the keyboard interface and interrupt. */ i8042_ctr |= I8042_CTR_KBDDIS; @@ -625,7 +604,16 @@ static int __init i8042_port_register(struct i8042_values *values, struct serio *port) { values->exists = 1; + + i8042_ctr &= ~values->disable; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n"); + return -1; + } + serio_register_port(port); + printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n", values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq); @@ -638,45 +626,45 @@ mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); } -static void __init i8042_start_polling(void) +#ifndef MODULE +static int __init i8042_setup_reset(char *str) { - i8042_ctr &= ~I8042_CTR_KBDDIS; - if (i8042_aux_values.exists) - i8042_ctr &= ~I8042_CTR_AUXDIS; - - if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { - printk(KERN_WARNING "i8042.c: Can't write CTR while starting polling.\n"); - return; - } - - i8042_timer.function = i8042_timer_func; - mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); + i8042_reset = 1; + return 1; } - -static void __exit i8042_stop_polling(void) +static int __init i8042_setup_noaux(char *str) { - del_timer(&i8042_timer); + i8042_noaux = 1; + return 1; } - -/* - * Module init and cleanup functions. - */ - -void __init i8042_setup(char *str, int *ints) +static int __init i8042_setup_unlock(char *str) { - if (!strcmp(str, "i8042_reset=1")) - i8042_reset = 1; - if (!strcmp(str, "i8042_noaux=1")) - i8042_noaux = 1; - if (!strcmp(str, "i8042_unlock=1")) - i8042_unlock = 1; - if (!strcmp(str, "i8042_direct=1")) - i8042_direct = 1; + i8042_unlock = 1; + return 1; +} +static int __init i8042_setup_direct(char *str) +{ + i8042_direct = 1; + return 1; } +static int __init i8042_setup_restore_ctr(char *str) +{ + i8042_restore_ctr = 1; + return 1; +} + +__setup("i8042_reset", i8042_setup_reset); +__setup("i8042_noaux", i8042_setup_noaux); +__setup("i8042_unlock", i8042_setup_unlock); +__setup("i8042_direct", i8042_setup_direct); +__setup("i8042_restore_ctr", i8042_setup_restore_ctr); +#endif /* - * Reset the 8042 back to original mode. + * We need to reset the 8042 back to original mode on system shutdown, + * because otherwise BIOSes will be confused. */ + static int i8042_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { @@ -698,18 +686,23 @@ i8042_start = jiffies; #endif +#if !defined(__i386__) && !defined(__x86_64__) + i8042_reset = 1; +#endif + if (!i8042_platform_init()) return -EBUSY; if (i8042_controller_init()) return -ENODEV; - - i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port)) i8042_port_register(&i8042_aux_values, &i8042_aux_port); - i8042_start_polling(); + i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + + i8042_timer.function = i8042_timer_func; + mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); register_reboot_notifier(&i8042_notifier); @@ -720,7 +713,7 @@ { unregister_reboot_notifier(&i8042_notifier); - i8042_stop_polling(); + del_timer(&i8042_timer); if (i8042_kbd_values.exists) serio_unregister_port(&i8042_kbd_port); @@ -735,3 +728,5 @@ module_init(i8042_init); module_exit(i8042_exit); + + diff -Nru a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c --- a/drivers/input/serio/parkbd.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/serio/parkbd.c Fri Jul 26 19:58:50 2002 @@ -97,11 +97,11 @@ static struct serio parkbd_port = { - write: parkbd_write, - open: parkbd_open, - close: parkbd_close, - name: parkbd_name, - phys: parkbd_phys, + .write = parkbd_write, + .open = parkbd_open, + .close = parkbd_close, + .name = parkbd_name, + .phys = parkbd_phys, }; static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) diff -Nru a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c --- a/drivers/input/serio/q40kbd.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/serio/q40kbd.c Fri Jul 26 19:58:51 2002 @@ -49,10 +49,10 @@ static struct serio q40kbd_port = { - type: SERIO_8042, - write: NULL, - name: "Q40 PS/2 kbd port", - phys: "isa0060/serio0", + .type = SERIO_8042, + .write = NULL, + .name = "Q40 PS/2 kbd port", + .phys = "isa0060/serio0", }; static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c --- a/drivers/input/serio/rpckbd.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/serio/rpckbd.c Fri Jul 26 19:58:50 2002 @@ -47,25 +47,30 @@ static inline void rpckbd_write(unsigned char val) { - while(!(inb(IOMD_KCTRL) & (1 << 7))); - outb(val, IOMD_KARTTX); + while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) + cpu_relax(); + + iomd_writeb(val, IOMD_KARTTX); } static struct serio rpckbd_port = { - type: SERIO_8042, - write: rpckbd_write, - name: "RiscPC PS/2 kbd port", - phys: "rpckbd/serio0", + .type = SERIO_8042, + .write = rpckbd_write, + .name = "RiscPC PS/2 kbd port", + .phys = "rpckbd/serio0", }; static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) { + unsigned int byte; kbd_pt_regs = regs; - while (inb(IOMD_KCTRL) & (1 << 5)) - serio_interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0); + while (iomd_readb(IOMD_KCTRL) & (1 << 5)) { + byte = iomd_readb(IOMD_KARTRX); + serio_interrupt(&rpckbd_port, byte, 0); + } } static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs) @@ -74,13 +79,10 @@ static int __init rpckbd_init(void) { - unsigned long flags; - /* Reset the keyboard state machine. */ - outb(0, IOMD_KCTRL); - outb(8, IOMD_KCTRL); - - save_flags_cli(flags); + iomd_writeb(0, IOMD_KCTRL); + iomd_writeb(8, IOMD_KCTRL); + iomd_readb(IOMD_KARTRX); if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) { printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n") @@ -93,14 +95,7 @@ return -EBUSY; } - disable_irq(IRQ_KEYBOARDTX); - (void)IOMD_KARTRX; - - restore_flags(flags); - register_serio_port(&rpckbd_port); - printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX); - return 0; } diff -Nru a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/sa1111ps2.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,286 @@ +/* + * linux/drivers/input/serio/sa1111ps2.c + * + * Copyright (C) 2002 Russell King + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern struct pt_regs *kbd_pt_regs; + +struct ps2if { + struct serio io; + struct resource *res; + unsigned long base; + unsigned int irq; + unsigned int skpcr_mask; +}; + +/* + * Read all bytes waiting in the PS2 port. There should be + * at the most one, but we loop for safety. If there was a + * framing error, we have to manually clear the status. + */ +static void ps2_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ps2if *sa = dev_id; + unsigned int scancode, flag, status; + + kbd_pt_regs = regs; + + status = sa1111_readl(sa->base + SA1111_PS2STAT); + while (status & PS2STAT_RXF) { + if (status & PS2STAT_STP) + sa1111_writel(PS2STAT_STP, sa->base + SA1111_PS2STAT); + + flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) | + (status & PS2STAT_RXP ? 0 : SERIO_PARITY); + + scancode = sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff; + + if (hweight8(scancode) & 1) + flag ^= SERIO_PARITY; + + serio_interrupt(&sa->io, scancode, flag); + + status = sa1111_readl(sa->base + SA1111_PS2STAT); + } +} + +/* + * Write a byte to the PS2 port. We have to wait for the + * port to indicate that the transmitter is empty. + */ +static int ps2_write(struct serio *io, unsigned char val) +{ + struct ps2if *sa = io->driver; + unsigned int timeleft = 10000; /* timeout in 100ms */ + + while ((sa1111_readl(sa->base + SA1111_PS2STAT) & PS2STAT_TXE) == 0 && + timeleft--) + udelay(10); + + if (timeleft) + sa1111_writel(val, sa->base + SA1111_PS2DATA); + + return timeleft ? 0 : SERIO_TIMEOUT; +} + +static int ps2_open(struct serio *io) +{ + struct ps2if *sa = io->driver; + int ret; + + sa1111_enable_device(sa->skpcr_mask); + + ret = request_irq(sa->irq, ps2_int, 0, "ps2", sa); + if (ret) { + printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", + sa->irq, ret); + return ret; + } + + sa1111_writel(PS2CR_ENA, sa->base + SA1111_PS2CR); + + return 0; +} + +static void ps2_close(struct serio *io) +{ + struct ps2if *sa = io->driver; + + sa1111_writel(0, sa->base + SA1111_PS2CR); + + free_irq(sa->irq, sa); + + sa1111_disable_device(sa->skpcr_mask); +} + +/* + * Clear the input buffer. + */ +static void __init ps2_clear_input(struct ps2if *sa) +{ + int maxread = 100; + + while (maxread--) { + if ((sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff) == 0xff) + break; + } +} + +static inline unsigned int +ps2_test_one(struct ps2if *sa, unsigned int mask) +{ + unsigned int val; + + sa1111_writel(PS2CR_ENA | mask, sa->base + SA1111_PS2CR); + + udelay(2); + + val = sa1111_readl(sa->base + SA1111_PS2STAT); + return val & (PS2STAT_KBC | PS2STAT_KBD); +} + +/* + * Test the keyboard interface. We basically check to make sure that + * we can drive each line to the keyboard independently of each other. + */ +static int __init ps2_test(struct ps2if *sa) +{ + unsigned int stat; + int ret = 0; + + stat = ps2_test_one(sa, PS2CR_FKC); + if (stat != PS2STAT_KBD) { + printk("Keyboard interface test failed[1]: %02x\n", stat); + ret = -ENODEV; + } + + stat = ps2_test_one(sa, 0); + if (stat != (PS2STAT_KBC | PS2STAT_KBD)) { + printk("Keyboard interface test failed[2]: %02x\n", stat); + ret = -ENODEV; + } + + stat = ps2_test_one(sa, PS2CR_FKD); + if (stat != PS2STAT_KBC) { + printk("Keyboard interface test failed[3]: %02x\n", stat); + ret = -ENODEV; + } + + sa1111_writel(0, sa->base + SA1111_PS2CR); + + return ret; +} + +/* + * Initialise one PS/2 port. + */ +static int __init ps2_init_one(struct sa1111_device *dev, struct ps2if *sa) +{ + int ret; + + /* + * Request the physical region for this PS2 port. + */ + sa->res = request_mem_region(_SA1111(sa->base), 512, "ps2"); + if (!sa->res) + return -EBUSY; + + /* + * Convert the chip offset to virtual address. + */ + sa->base += (unsigned long)dev->base; + + sa1111_enable_device(sa->skpcr_mask); + + /* Incoming clock is 8MHz */ + sa1111_writel(0, sa->base + SA1111_PS2CLKDIV); + sa1111_writel(127, sa->base + SA1111_PS2PRECNT); + + /* + * Flush any pending input. + */ + ps2_clear_input(sa); + + /* + * Test the keyboard interface. + */ + ret = ps2_test(sa); + if (ret) + goto out; + + /* + * Flush any pending input. + */ + ps2_clear_input(sa); + sa1111_disable_device(sa->skpcr_mask); + + serio_register_port(&sa->io); + return 0; + + out: + sa1111_disable_device(sa->skpcr_mask); + release_resource(sa->res); + return ret; +} + +/* + * Remove one PS/2 port. + */ +static void __exit ps2_remove_one(struct ps2if *sa) +{ + serio_unregister_port(&sa->io); + release_resource(sa->res); +} + +static struct ps2if ps2_kbd_port = +{ + io: { + type: SERIO_8042, + write: ps2_write, + open: ps2_open, + close: ps2_close, + name: "SA1111 PS/2 kbd port", + phys: "sa1111/serio0", + driver: &ps2_kbd_port, + }, + base: SA1111_KBD, + irq: IRQ_TPRXINT, + skpcr_mask: SKPCR_PTCLKEN, +}; + +static struct ps2if ps2_mse_port = +{ + io: { + type: SERIO_8042, + write: ps2_write, + open: ps2_open, + close: ps2_close, + name: "SA1111 PS/2 mouse port", + phys: "sa1111/serio1", + driver: &ps2_mse_port, + }, + base: SA1111_MSE, + irq: IRQ_MSRXINT, + skpcr_mask: SKPCR_PMCLKEN, +}; + +static int __init ps2_init(void) +{ + int ret = -ENODEV; + + if (sa1111) { + ret = ps2_init_one(sa1111, &ps2_kbd_port); + } + + return ret; +} + +static void __exit ps2_exit(void) +{ + ps2_remove_one(&ps2_kbd_port); +} + +module_init(ps2_init); +module_exit(ps2_exit); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("SA1111 PS2 controller driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c --- a/drivers/input/serio/serio.c Fri Jul 26 19:58:50 2002 +++ b/drivers/input/serio/serio.c Fri Jul 26 19:58:50 2002 @@ -42,6 +42,7 @@ MODULE_DESCRIPTION("Serio abstraction core"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_register_device); diff -Nru a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c --- a/drivers/input/serio/serport.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/serio/serport.c Fri Jul 26 19:58:51 2002 @@ -216,14 +216,14 @@ */ static struct tty_ldisc serport_ldisc = { - name: "input", - open: serport_ldisc_open, - close: serport_ldisc_close, - read: serport_ldisc_read, - ioctl: serport_ldisc_ioctl, - receive_buf: serport_ldisc_receive, - receive_room: serport_ldisc_room, - write_wakeup: serport_ldisc_write_wakeup + .name = "input", + .open = serport_ldisc_open, + .close = serport_ldisc_close, + .read = serport_ldisc_read, + .ioctl = serport_ldisc_ioctl, + .receive_buf = serport_ldisc_receive, + .receive_room = serport_ldisc_room, + .write_wakeup = serport_ldisc_write_wakeup }; /* diff -Nru a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c --- a/drivers/input/touchscreen/gunze.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/touchscreen/gunze.c Fri Jul 26 19:58:51 2002 @@ -74,6 +74,7 @@ input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4); input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3); input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T'); + input_sync(dev); } static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags) @@ -134,10 +135,10 @@ gunze->dev.private = gunze; gunze->dev.name = gunze_name; gunze->dev.phys = gunze->phys; - gunze->dev.idbus = BUS_RS232; - gunze->dev.idvendor = SERIO_GUNZE; - gunze->dev.idproduct = 0x0051; - gunze->dev.idversion = 0x0100; + gunze->dev.id.bustype = BUS_RS232; + gunze->dev.id.vendor = SERIO_GUNZE; + gunze->dev.id.product = 0x0051; + gunze->dev.id.version = 0x0100; if (serio_open(serio, dev)) { kfree(gunze); @@ -154,9 +155,9 @@ */ static struct serio_dev gunze_dev = { - interrupt: gunze_interrupt, - connect: gunze_connect, - disconnect: gunze_disconnect, + .interrupt = gunze_interrupt, + .connect = gunze_connect, + .disconnect = gunze_disconnect, }; /* diff -Nru a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c --- a/drivers/input/touchscreen/h3600_ts_input.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/touchscreen/h3600_ts_input.c Fri Jul 26 19:58:52 2002 @@ -109,6 +109,7 @@ struct input_dev *dev = (struct input_dev *) dev_id; input_report_key(dev, KEY_ENTER, down); + input_sync(dev); } static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) @@ -122,6 +123,7 @@ */ input_report_key(dev, KEY_SUSPEND, 1); input_report_key(dev, KEY_SUSPEND, down); + input_sync(dev); } #ifdef CONFIG_PM @@ -267,6 +269,8 @@ /* Send a non input event elsewhere */ break; } + + input_sync(dev); } /* @@ -418,10 +422,10 @@ ts->dev.private = ts; ts->dev.name = h3600_name; ts->dev.phys = ts->phys; - ts->dev.idbus = BUS_RS232; - ts->dev.idvendor = SERIO_H3600; - ts->dev.idproduct = 0x0666; /* FIXME !!! We can ask the hardware */ - ts->dev.idversion = 0x0100; + ts->dev.id.bustype = BUS_RS232; + ts->dev.id.vendor = SERIO_H3600; + ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ + ts->dev.id.version = 0x0100; if (serio_open(serio, dev)) { free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); @@ -461,9 +465,9 @@ */ static struct serio_dev h3600ts_dev = { - interrupt: h3600ts_interrupt, - connect: h3600ts_connect, - disconnect: h3600ts_disconnect, + .interrupt = h3600ts_interrupt, + .connect = h3600ts_connect, + .disconnect = h3600ts_disconnect, }; /* diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c --- a/drivers/input/tsdev.c Fri Jul 26 19:58:51 2002 +++ b/drivers/input/tsdev.c Fri Jul 26 19:58:51 2002 @@ -218,13 +218,13 @@ } struct file_operations tsdev_fops = { - owner: THIS_MODULE, - open: tsdev_open, - release: tsdev_release, - read: tsdev_read, - poll: tsdev_poll, - fasync: tsdev_fasync, - ioctl: tsdev_ioctl, + .owner = THIS_MODULE, + .open = tsdev_open, + .release = tsdev_release, + .read = tsdev_read, + .poll = tsdev_poll, + .fasync = tsdev_fasync, + .ioctl = tsdev_ioctl, }; static void tsdev_event(struct input_handle *handle, unsigned int type, @@ -411,13 +411,13 @@ MODULE_DEVICE_TABLE(input, tsdev_ids); static struct input_handler tsdev_handler = { - event: tsdev_event, - connect: tsdev_connect, - disconnect: tsdev_disconnect, - fops: &tsdev_fops, - minor: TSDEV_MINOR_BASE, - name: "tsdev", - id_table: tsdev_ids, + .event = tsdev_event, + .connect = tsdev_connect, + .disconnect = tsdev_disconnect, + .fops = &tsdev_fops, + .minor = TSDEV_MINOR_BASE, + .name = "tsdev", + .id_table = tsdev_ids, }; static int __init tsdev_init(void) diff -Nru a/drivers/input/uinput.c b/drivers/input/uinput.c --- a/drivers/input/uinput.c Fri Jul 26 19:58:52 2002 +++ b/drivers/input/uinput.c Fri Jul 26 19:58:52 2002 @@ -162,10 +162,10 @@ strncpy(dev->name, user_dev.name, size); dev->name[size] = '\0'; - dev->idbus = user_dev.idbus; - dev->idvendor = user_dev.idvendor; - dev->idproduct = user_dev.idproduct; - dev->idversion = user_dev.idversion; + dev->id.bustype = user_dev.id.bustype; + dev->id.vendor = user_dev.id.vendor; + dev->id.product = user_dev.id.product; + dev->id.version = user_dev.id.version; dev->ff_effects_max = user_dev.ff_effects_max; size = sizeof(unsigned long) * NBITS(ABS_MAX + 1); @@ -351,34 +351,24 @@ } struct file_operations uinput_fops = { - owner: THIS_MODULE, - open: uinput_open, - release: uinput_close, - read: uinput_read, - write: uinput_write, - poll: uinput_poll, -// fasync: uinput_fasync, - ioctl: uinput_ioctl, + .owner = THIS_MODULE, + .open = uinput_open, + .release = uinput_close, + .read = uinput_read, + .write = uinput_write, + .poll = uinput_poll, + .ioctl = uinput_ioctl, }; static struct miscdevice uinput_misc = { - fops: &uinput_fops, - minor: UINPUT_MINOR, - name: UINPUT_NAME, + .fops = &uinput_fops, + .minor = UINPUT_MINOR, + .name = UINPUT_NAME, }; static int __init uinput_init(void) { - int retval; - - retval = misc_register(&uinput_misc); - - if (!retval) { - printk(KERN_INFO "%s: User level driver support for input subsystem loaded\n", UINPUT_NAME); - printk(KERN_INFO "%s: Aristeu Sergio Rozanski Filho \n", UINPUT_NAME); - } - - return retval; + return misc_register(&uinput_misc); } static void __exit uinput_exit(void) diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c --- a/drivers/macintosh/adbhid.c Fri Jul 26 19:58:51 2002 +++ b/drivers/macintosh/adbhid.c Fri Jul 26 19:58:51 2002 @@ -163,6 +163,8 @@ else printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, up_flag ? "released" : "pressed"); + + input_sync(&adbhid[id]->input); } static void @@ -259,6 +261,8 @@ ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); input_report_rel(&adbhid[id]->input, REL_Y, ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); + + input_sync(&adbhid[id]->input); } static void @@ -363,6 +367,8 @@ } break; } + + input_sync(&adbhid[id]->input); } static struct adb_request led_request; @@ -479,10 +485,10 @@ adbhid[id]->input.private = adbhid[id]; adbhid[id]->input.name = adbhid[id]->name; adbhid[id]->input.phys = adbhid[id]->phys; - adbhid[id]->input.idbus = BUS_ADB; - adbhid[id]->input.idvendor = 0x0001; - adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; - adbhid[id]->input.idversion = 0x0100; + adbhid[id]->input.id.bustype = BUS_ADB; + adbhid[id]->input.id.vendor = 0x0001; + adbhid[id]->input.id.product = (id << 12) | (default_id << 8) | original_handler_id; + adbhid[id]->input.id.version = 0x0100; switch (default_id) { case ADB_KEYBOARD: @@ -607,7 +613,7 @@ int cur_handler_id, int mk) { if (adbhid[id]) { - if (adbhid[id]->input.idproduct != + if (adbhid[id]->input.id.product != ((id << 12)|(default_id << 8)|org_handler_id)) { adbhid_input_unregister(id); adbhid_input_register(id, default_id, org_handler_id, diff -Nru a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c --- a/drivers/macintosh/mac_hid.c Fri Jul 26 19:58:52 2002 +++ b/drivers/macintosh/mac_hid.c Fri Jul 26 19:58:52 2002 @@ -162,6 +162,7 @@ input_report_key(&emumousebtn, keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, down); + input_sync(&emumousebtn); return 1; } mouse_last_keycode = down ? keycode : 0; @@ -181,10 +182,10 @@ emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); - emumousebtn.idbus = BUS_ADB; - emumousebtn.idvendor = 0x0001; - emumousebtn.idproduct = 0x0001; - emumousebtn.idversion = 0x0100; + emumousebtn.id.bustype = BUS_ADB; + emumousebtn.id.vendor = 0x0001; + emumousebtn.id.product = 0x0001; + emumousebtn.id.version = 0x0100; input_register_device(&emumousebtn); diff -Nru a/drivers/md/xor.c b/drivers/md/xor.c --- a/drivers/md/xor.c Fri Jul 26 19:58:51 2002 +++ b/drivers/md/xor.c Fri Jul 26 19:58:51 2002 @@ -109,7 +109,6 @@ b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE; printk(KERN_INFO "raid5: measuring checksumming speed\n"); - sti(); #define xor_speed(templ) do_xor_speed((templ), b1, b2) diff -Nru a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c --- a/drivers/media/radio/miropcm20-rds-core.c Fri Jul 26 19:58:52 2002 +++ b/drivers/media/radio/miropcm20-rds-core.c Fri Jul 26 19:58:52 2002 @@ -15,8 +15,9 @@ #define _NO_VERSION_ -/* #include */ #include +#include +#include #include #include #include diff -Nru a/drivers/media/video/Config.in b/drivers/media/video/Config.in --- a/drivers/media/video/Config.in Fri Jul 26 19:58:51 2002 +++ b/drivers/media/video/Config.in Fri Jul 26 19:58:51 2002 @@ -5,7 +5,6 @@ comment 'Video For Linux' bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS -dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C comment 'Video Adapters' if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then diff -Nru a/drivers/media/video/Makefile b/drivers/media/video/Makefile --- a/drivers/media/video/Makefile Fri Jul 26 19:58:51 2002 +++ b/drivers/media/video/Makefile Fri Jul 26 19:58:51 2002 @@ -5,7 +5,7 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := i2c-old.o videodev.o bttv-if.o cpia.o video-buf.o +export-objs := videodev.o bttv-if.o cpia.o video-buf.o bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o @@ -13,21 +13,19 @@ obj-$(CONFIG_VIDEO_DEV) += videodev.o -obj-$(CONFIG_BUS_I2C) += i2c-old.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ tda7432.o tda9875.o tuner.o video-buf.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o -obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o -obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o +obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o obj-$(CONFIG_VIDEO_W9966) += w9966.o obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_PLANB) += planb.o obj-$(CONFIG_VIDEO_VINO) += vino.o diff -Nru a/drivers/media/video/i2c-old.c b/drivers/media/video/i2c-old.c --- a/drivers/media/video/i2c-old.c Fri Jul 26 19:58:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,450 +0,0 @@ -/* - * Generic i2c interface for linux - * - * (c) 1998 Gerd Knorr - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REGPRINT(x) if (verbose) (x) -#define I2C_DEBUG(x) if (i2c_debug) (x) - -static int scan = 0; -static int verbose = 0; -static int i2c_debug = 0; - -#if LINUX_VERSION_CODE >= 0x020117 -MODULE_PARM(scan,"i"); -MODULE_PARM(verbose,"i"); -MODULE_PARM(i2c_debug,"i"); -#endif - -/* ----------------------------------------------------------------------- */ - -static struct i2c_bus *busses[I2C_BUS_MAX]; -static struct i2c_driver *drivers[I2C_DRIVER_MAX]; -static int bus_count = 0, driver_count = 0; - -#ifdef CONFIG_VIDEO_BUZ -extern int saa7111_init(void); -extern int saa7185_init(void); -#endif -#ifdef CONFIG_VIDEO_LML33 -extern int bt819_init(void); -extern int bt856_init(void); -#endif - -int i2c_init(void) -{ - printk(KERN_INFO "i2c: initialized%s\n", - scan ? " (i2c bus scan enabled)" : ""); - /* anything to do here ? */ -#ifdef CONFIG_VIDEO_BUZ - saa7111_init(); - saa7185_init(); -#endif -#ifdef CONFIG_VIDEO_LML33 - bt819_init(); - bt856_init(); -#endif - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver) -{ - struct i2c_device *device; - int i,j,ack=1; - unsigned char addr; - LOCK_FLAGS; - - /* probe for device */ - LOCK_I2C_BUS(bus); - for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,addr,0); - i2c_stop(bus); - if (!ack) - break; - } - UNLOCK_I2C_BUS(bus); - if (ack) - return; - - /* got answer */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (NULL == driver->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - return; - - for (j = 0; j < I2C_DEVICE_MAX; j++) - if (NULL == bus->devices[j]) - break; - if (I2C_DEVICE_MAX == j) - return; - - if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL))) - return; - device->bus = bus; - device->driver = driver; - device->addr = addr; - - /* Attach */ - - if (driver->attach(device)!=0) - { - kfree(device); - return; - } - driver->devices[i] = device; - driver->devcount++; - bus->devices[j] = device; - bus->devcount++; - - if (bus->attach_inform) - bus->attach_inform(bus,driver->id); - REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name)); -} - -static void i2c_detach_device(struct i2c_device *device) -{ - int i; - - if (device->bus->detach_inform) - device->bus->detach_inform(device->bus,device->driver->id); - device->driver->detach(device); - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->driver->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", - device->name); - return; - } - device->driver->devices[i] = NULL; - device->driver->devcount--; - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->bus->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", - device->name); - return; - } - device->bus->devices[i] = NULL; - device->bus->devcount--; - - REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name)); - kfree(device); -} - -/* ----------------------------------------------------------------------- */ - -int i2c_register_bus(struct i2c_bus *bus) -{ - int i,ack; - LOCK_FLAGS; - - memset(bus->devices,0,sizeof(bus->devices)); - bus->devcount = 0; - - for (i = 0; i < I2C_BUS_MAX; i++) - if (NULL == busses[i]) - break; - if (I2C_BUS_MAX == i) - return -ENOMEM; - - busses[i] = bus; - bus_count++; - REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); - - MOD_INC_USE_COUNT; - - if (scan) - { - /* scan whole i2c bus */ - LOCK_I2C_BUS(bus); - for (i = 0; i < 256; i+=2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,i,0); - i2c_stop(bus); - if (!ack) - { - printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", - bus->name,i); - } - } - UNLOCK_I2C_BUS(bus); - } - - /* probe available drivers */ - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (drivers[i]) - i2c_attach_device(bus,drivers[i]); - return 0; -} - -int i2c_unregister_bus(struct i2c_bus *bus) -{ - int i; - - /* detach devices */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (bus->devices[i]) - i2c_detach_device(bus->devices[i]); - - for (i = 0; i < I2C_BUS_MAX; i++) - if (bus == busses[i]) - break; - if (I2C_BUS_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", - bus->name); - return -ENODEV; - } - - MOD_DEC_USE_COUNT; - - busses[i] = NULL; - bus_count--; - REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int i2c_register_driver(struct i2c_driver *driver) -{ - int i; - - memset(driver->devices,0,sizeof(driver->devices)); - driver->devcount = 0; - - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (NULL == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) - return -ENOMEM; - - drivers[i] = driver; - driver_count++; - - MOD_INC_USE_COUNT; - - REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); - - /* Probe available busses */ - for (i = 0; i < I2C_BUS_MAX; i++) - if (busses[i]) - i2c_attach_device(busses[i],driver); - - return 0; -} - -int i2c_unregister_driver(struct i2c_driver *driver) -{ - int i; - - /* detach devices */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (driver->devices[i]) - i2c_detach_device(driver->devices[i]); - - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (driver == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", - driver->name); - return -ENODEV; - } - - MOD_DEC_USE_COUNT; - - drivers[i] = NULL; - driver_count--; - REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int i2c_control_device(struct i2c_bus *bus, int id, - unsigned int cmd, void *arg) -{ - int i; - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (bus->devices[i] && bus->devices[i]->driver->id == id) - break; - if (i == I2C_DEVICE_MAX) - return -ENODEV; - if (NULL == bus->devices[i]->driver->command) - return -ENODEV; - return bus->devices[i]->driver->command(bus->devices[i],cmd,arg); -} - -/* ----------------------------------------------------------------------- */ - -#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data)) -#define I2C_GET(bus) (bus->i2c_getdataline(bus)) - -void i2c_start(struct i2c_bus *bus) -{ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - I2C_SET(bus,1,0); - I2C_SET(bus,0,0); - I2C_DEBUG(printk("%s: < ",bus->name)); -} - -void i2c_stop(struct i2c_bus *bus) -{ - I2C_SET(bus,0,0); - I2C_SET(bus,1,0); - I2C_SET(bus,1,1); - I2C_DEBUG(printk(">\n")); -} - -void i2c_one(struct i2c_bus *bus) -{ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - I2C_SET(bus,0,1); -} - -void i2c_zero(struct i2c_bus *bus) -{ - I2C_SET(bus,0,0); - I2C_SET(bus,1,0); - I2C_SET(bus,0,0); -} - -int i2c_ack(struct i2c_bus *bus) -{ - int ack; - - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - ack = I2C_GET(bus); - I2C_SET(bus,0,1); - return ack; -} - -int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) -{ - int i, ack; - - I2C_SET(bus,0,0); - for (i=7; i>=0; i--) - (data&(1<=0; i--) - { - I2C_SET(bus,1,1); - if (I2C_GET(bus)) - data |= (1<i2c_read) - return bus->i2c_read(bus, addr); - - i2c_start(bus); - i2c_sendbyte(bus,addr,0); - ret = i2c_readbyte(bus,1); - i2c_stop(bus); - return ret; -} - -int i2c_write(struct i2c_bus *bus, unsigned char addr, - unsigned char data1, unsigned char data2, int both) -{ - int ack; - - if (bus->i2c_write) - return bus->i2c_write(bus, addr, data1, data2, both); - - i2c_start(bus); - i2c_sendbyte(bus,addr,0); - ack = i2c_sendbyte(bus,data1,0); - if (both) - ack = i2c_sendbyte(bus,data2,0); - i2c_stop(bus); - return ack ? -1 : 0 ; -} - -/* ----------------------------------------------------------------------- */ - -#ifdef MODULE - -#if LINUX_VERSION_CODE >= 0x020100 -EXPORT_SYMBOL(i2c_register_bus); -EXPORT_SYMBOL(i2c_unregister_bus); -EXPORT_SYMBOL(i2c_register_driver); -EXPORT_SYMBOL(i2c_unregister_driver); -EXPORT_SYMBOL(i2c_control_device); -EXPORT_SYMBOL(i2c_start); -EXPORT_SYMBOL(i2c_stop); -EXPORT_SYMBOL(i2c_one); -EXPORT_SYMBOL(i2c_zero); -EXPORT_SYMBOL(i2c_ack); -EXPORT_SYMBOL(i2c_sendbyte); -EXPORT_SYMBOL(i2c_readbyte); -EXPORT_SYMBOL(i2c_read); -EXPORT_SYMBOL(i2c_write); -#endif - -int init_module(void) -{ - return i2c_init(); -} - -void cleanup_module(void) -{ -} -#endif -MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/video/i2c-parport.c b/drivers/media/video/i2c-parport.c --- a/drivers/media/video/i2c-parport.c Fri Jul 26 19:58:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,152 +0,0 @@ -/* - * I2C driver for parallel port - * - * Author: Phil Blundell - * - * 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 driver implements a simple I2C protocol by bit-twiddling some - * signals on the parallel port. Since the outputs on the parallel port - * aren't open collector, three lines rather than two are used: - * - * D0 clock out - * D1 data out - * BUSY data in - */ - -#include -#include -#include -#include -#include -#include - -#define I2C_DELAY 10 - -static int debug = 0; - -struct parport_i2c_bus -{ - struct i2c_bus i2c; - struct parport_i2c_bus *next; -}; - -static struct parport_i2c_bus *bus_list; - -static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED; - -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus, int clk, int data) -{ - struct parport *p = bus->data; - parport_write_data(p, (clk?1:0) | (data?2:0)); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct parport *p = bus->data; - return (parport_read_status(p) & PARPORT_STATUS_BUSY) ? 0 : 1; -} - -static struct i2c_bus parport_i2c_bus_template = -{ - "...", - I2C_BUSID_PARPORT, - NULL, - - SPIN_LOCK_UNLOCKED, - - NULL, - NULL, - - i2c_setlines, - i2c_getdataline, - NULL, - NULL, -}; - -static void i2c_parport_attach(struct parport *port) -{ - struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), - GFP_KERNEL); - if (!b) { - printk(KERN_ERR "i2c_parport: Memory allocation failed. Not attaching.\n"); - return; - } - b->i2c = parport_i2c_bus_template; - b->i2c.data = parport_get_port (port); - strncpy(b->i2c.name, port->name, 32); - spin_lock(&bus_list_lock); - b->next = bus_list; - bus_list = b; - spin_unlock(&bus_list_lock); - i2c_register_bus(&b->i2c); - if (debug) - printk(KERN_DEBUG "i2c: attached to %s\n", port->name); -} - -static void i2c_parport_detach(struct parport *port) -{ - struct parport_i2c_bus *b, *old_b = NULL; - spin_lock(&bus_list_lock); - b = bus_list; - while (b) - { - if (b->i2c.data == port) - { - if (old_b) - old_b->next = b->next; - else - bus_list = b->next; - i2c_unregister_bus(&b->i2c); - kfree(b); - break; - } - old_b = b; - b = b->next; - } - spin_unlock(&bus_list_lock); - if (debug) - printk(KERN_DEBUG "i2c: detached from %s\n", port->name); -} - -static struct parport_driver parport_i2c_driver = -{ - "i2c", - i2c_parport_attach, - i2c_parport_detach -}; - -#ifdef MODULE -int init_module(void) -#else -int __init i2c_parport_init(void) -#endif -{ - printk("I2C: driver for parallel port v0.1 philb@gnu.org\n"); - parport_register_driver(&parport_i2c_driver); - return 0; -} - -#ifdef MODULE -MODULE_PARM(debug, "i"); - -void cleanup_module(void) -{ - struct parport_i2c_bus *b = bus_list; - while (b) - { - struct parport_i2c_bus *next = b->next; - i2c_unregister_bus(&b->i2c); - kfree(b); - b = next; - } - parport_unregister_driver(&parport_i2c_driver); -} -#endif -MODULE_LICENSE("GPL"); diff -Nru a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c --- a/drivers/message/i2o/i2o_config.c Fri Jul 26 19:58:52 2002 +++ b/drivers/message/i2o/i2o_config.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /* * I2O Configuration Interface Driver * - * (C) Copyright 1999 Red Hat Software + * (C) Copyright 1999-2002 Red Hat * * Written by Alan Cox, Building Number Three Ltd * @@ -16,17 +16,17 @@ * - Fixed ioctl_swdl() * Modified 10/04/1999 by Taneli Vähäkangas * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() - * Modified 11/18/199 by Deepak Saxena + * Modified 11/18/1999 by Deepak Saxena * - Added event managmenet support * + * 2.4 rewrite ported to 2.5 - Alan Cox + * * 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. */ -#error Please convert me to Documentation/DMA-mapping.txt - #include #include #include @@ -47,7 +47,7 @@ static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; -#define MODINC(x,y) (x = x++ % y) +#define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct i2o_cfg_info { @@ -279,7 +279,14 @@ if(c) { foo[i] = 1; - i2o_unlock_controller(c); + if(pci_set_dma_mask(c->pdev, 0xffffffff)) + { + printk(KERN_WARNING "i2o_config : No suitable DMA available on controller %d\n", i); + i2o_unlock_controller(c); + continue; + } + + i2o_unlock_controller(c); } else { @@ -445,11 +452,12 @@ struct i2o_controller *c; u8 *res = NULL; void *query = NULL; + dma_addr_t query_phys, res_phys; int ret = 0; int token; u32 len; u32 reslen; - u32 msg[MSG_FRAME_SIZE/4]; + u32 msg[MSG_FRAME_SIZE]; if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html))) { @@ -475,7 +483,7 @@ if(kcmd.qlen) /* Check for post data */ { - query = kmalloc(kcmd.qlen, GFP_KERNEL); + query = pci_alloc_consistent(c->pdev, kcmd.qlen, &query_phys); if(!query) { i2o_unlock_controller(c); @@ -485,16 +493,16 @@ { i2o_unlock_controller(c); printk(KERN_INFO "i2o_config: could not get query\n"); - kfree(query); + pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); return -EFAULT; } } - res = kmalloc(65536, GFP_KERNEL); + res = pci_alloc_consistent(c->pdev, 65536, &res_phys); if(!res) { i2o_unlock_controller(c); - kfree(query); + pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); return -ENOMEM; } @@ -503,7 +511,7 @@ msg[3] = 0; msg[4] = kcmd.page; msg[5] = 0xD0000000|65536; - msg[6] = virt_to_bus(res); + msg[6] = res_phys; if(!kcmd.qlen) /* Check for post data */ msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; else @@ -511,7 +519,7 @@ msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; msg[5] = 0x50000000|65536; msg[7] = 0xD4000000|(kcmd.qlen); - msg[8] = virt_to_bus(query); + msg[8] = query_phys; } /* Wait for a considerable time till the Controller @@ -519,7 +527,7 @@ take more time to process this request if there are many devices connected to it. */ - token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res); + token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res, query_phys, res_phys, kcmd.qlen, 65536); if(token < 0) { printk(KERN_DEBUG "token = %#10x\n", token); @@ -527,10 +535,10 @@ if(token != -ETIMEDOUT) { - kfree(res); - if(kcmd.qlen) kfree(query); + pci_free_consistent(c->pdev, 65536, res, res_phys); + if(kcmd.qlen) + pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); } - return token; } i2o_unlock_controller(c); @@ -542,9 +550,9 @@ if(copy_to_user(kcmd.resbuf, res, len)) ret = -EFAULT; - kfree(res); - if(kcmd.qlen) - kfree(query); + pci_free_consistent(c->pdev, 65536, res, res_phys); + if(kcmd.qlen) + pci_free_consistent(c->pdev, kcmd.qlen, query, query_phys); return ret; } @@ -558,6 +566,7 @@ u32 msg[9]; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; + dma_addr_t buffer_phys; if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; @@ -580,7 +589,7 @@ if(!c) return -ENXIO; - buffer=kmalloc(fragsize, GFP_KERNEL); + buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); if (buffer==NULL) { i2o_unlock_controller(c); @@ -597,14 +606,14 @@ msg[5]= swlen; msg[6]= kxfer.sw_id; msg[7]= (0xD0000000 | fragsize); - msg[8]= virt_to_bus(buffer); + msg[8]= buffer_phys; // printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL); + status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); i2o_unlock_controller(c); if(status != -ETIMEDOUT) - kfree(buffer); + pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); if (status != I2O_POST_WAIT_OK) { @@ -626,7 +635,8 @@ u32 msg[9]; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; - + dma_addr_t buffer_phys; + if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; @@ -648,7 +658,7 @@ if(!c) return -ENXIO; - buffer=kmalloc(fragsize, GFP_KERNEL); + buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); if (buffer==NULL) { i2o_unlock_controller(c); @@ -663,22 +673,22 @@ msg[5]= swlen; msg[6]= kxfer.sw_id; msg[7]= (0xD0000000 | fragsize); - msg[8]= virt_to_bus(buffer); + msg[8]= buffer_phys; // printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL); + status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); i2o_unlock_controller(c); if (status != I2O_POST_WAIT_OK) { if(status != -ETIMEDOUT) - kfree(buffer); + pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); return status; } __copy_to_user(kxfer.buf, buffer, fragsize); - kfree(buffer); + pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); return 0; } @@ -849,6 +859,7 @@ struct i2o_cfg_info *p1, *p2; unsigned long flags; + lock_kernel(); p1 = p2 = NULL; spin_lock_irqsave(&i2o_config_lock, flags); @@ -871,6 +882,7 @@ p1 = p1->next; } spin_unlock_irqrestore(&i2o_config_lock, flags); + unlock_kernel(); return 0; } @@ -908,11 +920,7 @@ &config_fops }; -#ifdef MODULE -int init_module(void) -#else -int __init i2o_config_init(void) -#endif +static int __init i2o_config_init(void) { printk(KERN_INFO "I2O configuration manager v 0.04.\n"); printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); @@ -946,9 +954,7 @@ return 0; } -#ifdef MODULE - -void cleanup_module(void) +static void i2o_config_exit(void) { misc_deregister(&i2o_miscdev); @@ -958,8 +964,10 @@ i2o_remove_handler(&cfg_handler); } +EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Configuration"); MODULE_LICENSE("GPL"); -#endif +module_init(i2o_config_init); +module_exit(i2o_config_exit); diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c --- a/drivers/message/i2o/i2o_core.c Fri Jul 26 19:58:51 2002 +++ b/drivers/message/i2o/i2o_core.c Fri Jul 26 19:58:52 2002 @@ -1,7 +1,7 @@ /* * Core I2O structure management * - * (C) Copyright 1999 Red Hat Software + * (C) Copyright 1999-2002 Red Hat Software * * Written by Alan Cox, Building Number Three Ltd * @@ -19,11 +19,12 @@ * Auvo Häkkinen * Deepak Saxena * Boji T Kannanthanam + * + * Ported to Linux 2.5 by + * Alan Cox * */ -#error Please convert me to Documentation/DMA-mapping.txt - #include #include #include @@ -72,7 +73,7 @@ static int core_context; /* Initialization && shutdown functions */ -static void i2o_sys_init(void); +void i2o_sys_init(void); static void i2o_sys_shutdown(void); static int i2o_reset_controller(struct i2o_controller *); static int i2o_reboot_event(struct notifier_block *, unsigned long , void *); @@ -122,28 +123,6 @@ */ static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED; -#ifdef MODULE -/* - * Function table to send to bus specific layers - * See for explanation of this - */ -#ifdef CONFIG_I2O_PCI_MODULE -static struct i2o_core_func_table i2o_core_functions = -{ - i2o_install_controller, - i2o_activate_controller, - i2o_find_controller, - i2o_unlock_controller, - i2o_run_queue, - i2o_delete_controller -}; - -extern int i2o_pci_core_attach(struct i2o_core_func_table *); -extern void i2o_pci_core_detach(void); -#endif /* CONFIG_I2O_PCI_MODULE */ - -#endif /* MODULE */ - /* * Structures and definitions for synchronous message posting. * See i2o_post_wait() for description. @@ -156,11 +135,14 @@ wait_queue_head_t *wq; /* Wake up for caller (NULL for dead) */ struct i2o_post_wait_data *next; /* Chain */ void *mem[2]; /* Memory blocks to recover on failure path */ + dma_addr_t phys[2]; /* Physical address of blocks to recover */ + u32 size[2]; /* Size of blocks to recover */ }; + static struct i2o_post_wait_data *post_wait_queue; static u32 post_wait_id; // Unique ID for each post_wait static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED; -static void i2o_post_wait_complete(u32, int); +static void i2o_post_wait_complete(struct i2o_controller *, u32, int); /* OSM descriptor handler */ static struct i2o_handler i2o_core_handler = @@ -210,7 +192,7 @@ static DECLARE_MUTEX(evt_sem); static DECLARE_COMPLETION(evt_dead); -DECLARE_WAIT_QUEUE_HEAD(evt_wait); +static DECLARE_WAIT_QUEUE_HEAD(evt_wait); static struct notifier_block i2o_reboot_notifier = { @@ -269,7 +251,7 @@ else status = I2O_POST_WAIT_OK; - i2o_post_wait_complete(context, status); + i2o_post_wait_complete(c, context, status); return; } @@ -503,7 +485,7 @@ { if(i2o_controllers[i]==NULL) { - c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); + c->dlct = (i2o_lct*)pci_alloc_consistent(c->pdev, 8192, &c->dlct_phys); if(c->dlct==NULL) { up(&i2o_configuration_lock); @@ -613,13 +595,13 @@ kfree(c->page_frame); } if(c->hrt) - kfree(c->hrt); + pci_free_consistent(c->pdev, c->hrt_len, c->hrt, c->hrt_phys); if(c->lct) - kfree(c->lct); + pci_free_consistent(c->pdev, c->lct->table_size << 2, c->lct, c->lct_phys); if(c->status_block) - kfree(c->status_block); + pci_free_consistent(c->pdev, sizeof(i2o_status_block), c->status_block, c->status_block_phys); if(c->dlct) - kfree(c->dlct); + pci_free_consistent(c->pdev, 8192, c->dlct, c->dlct_phys); i2o_controllers[c->unit]=NULL; memcpy(name, c->name, strlen(c->name)+1); @@ -1145,15 +1127,17 @@ */ if(c->lct->table_size < c->dlct->table_size) { + dma_addr_t phys; tmp = c->lct; - c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL); + c->lct = pci_alloc_consistent(c->pdev, c->dlct->table_size<<2, &phys); if(!c->lct) { printk(KERN_ERR "%s: No memory for LCT!\n", c->name); c->lct = tmp; continue; } - kfree(tmp); + pci_free_consistent(tmp, c->lct->table_size << 2, c->lct, c->lct_phys); + c->lct_phys = phys; } memcpy(c->lct, c->dlct, c->dlct->table_size<<2); } @@ -1186,7 +1170,8 @@ { struct i2o_handler *i; /* Map the message from the page frame map to kernel virtual */ - m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); + /* m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); */ + m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; /* @@ -1665,6 +1650,7 @@ struct i2o_controller *iop; u32 m; u8 *status; + dma_addr_t status_phys; u32 *msg; long time; @@ -1681,8 +1667,8 @@ return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); - status=(void *)kmalloc(4, GFP_KERNEL); - if(status==NULL) { + status = pci_alloc_consistent(c->pdev, 4, &status_phys); + if(status == NULL) { printk(KERN_ERR "IOP reset failed - no free memory.\n"); return -ENOMEM; } @@ -1694,7 +1680,7 @@ msg[3]=0; msg[4]=0; msg[5]=0; - msg[6]=virt_to_bus(status); + msg[6]=status_phys; msg[7]=0; /* 64bit host FIXME */ i2o_post_message(c,m); @@ -1706,7 +1692,7 @@ if((jiffies-time)>=20*HZ) { printk(KERN_ERR "IOP reset timeout.\n"); - // Better to leak this for safety: kfree(status); + // Better to leak this for safety: - status; return -ETIMEDOUT; } schedule(); @@ -1762,7 +1748,7 @@ if (iop != c) i2o_enable_controller(iop); - kfree(status); + pci_free_consistent(c->pdev, 4, status, status_phys); return 0; } @@ -1787,7 +1773,7 @@ if (c->status_block == NULL) { c->status_block = (i2o_status_block *) - kmalloc(sizeof(i2o_status_block),GFP_KERNEL); + pci_alloc_consistent(c->pdev, sizeof(i2o_status_block), &c->status_block_phys); if (c->status_block == NULL) { printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", @@ -1810,7 +1796,7 @@ msg[3]=0; msg[4]=0; msg[5]=0; - msg[6]=virt_to_bus(c->status_block); + msg[6]=c->status_block_phys; msg[7]=0; /* 64bit host FIXME */ msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ @@ -1826,7 +1812,7 @@ printk(KERN_ERR "%s: Get status timeout.\n",c->name); return -ETIMEDOUT; } - schedule(); + yield(); barrier(); } @@ -1876,7 +1862,7 @@ do { if (c->hrt == NULL) { - c->hrt=kmalloc(size, GFP_KERNEL); + c->hrt=pci_alloc_consistent(c->pdev, size, &c->hrt_phys); if (c->hrt == NULL) { printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); return -ENOMEM; @@ -1887,9 +1873,9 @@ msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; msg[3]= 0; msg[4]= (0xD0000000 | size); /* Simple transaction */ - msg[5]= virt_to_bus(c->hrt); /* Dump it here */ + msg[5]= c->hrt_phys; /* Dump it here */ - ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL); + ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL, c->hrt_phys, 0, size, 0); if(ret == -ETIMEDOUT) { @@ -1907,8 +1893,9 @@ } if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) { - size = c->hrt->num_entries * c->hrt->entry_len << 2; - kfree(c->hrt); + int new_size = c->hrt->num_entries * c->hrt->entry_len << 2; + pci_free_consistent(c->pdev, size, c->hrt, c->hrt_phys); + size = new_size; c->hrt = NULL; } } while (c->hrt == NULL); @@ -1929,6 +1916,7 @@ static int i2o_systab_send(struct i2o_controller *iop) { u32 msg[12]; + dma_addr_t sys_tbl_phys; int ret; u32 *privbuf = kmalloc(16, GFP_KERNEL); if(privbuf == NULL) @@ -2009,17 +1997,23 @@ * Provide three SGL-elements: * System table (SysTab), Private memory space declaration and * Private i/o space declaration - * - * FIXME: provide these for controllers needing them + * + * Nasty one here. We can't use pci_alloc_consistent to send the + * same table to everyone. We have to go remap it for them all */ - msg[6] = 0x54000000 | sys_tbl_len; - msg[7] = virt_to_bus(sys_tbl); - msg[8] = 0x54000000 | 8; - msg[9] = virt_to_bus(privbuf); - msg[10] = 0xD4000000 | 8; - msg[11] = virt_to_bus(privbuf+2); + + sys_tbl_phys = pci_map_single(iop->pdev, sys_tbl, sys_tbl_len, PCI_DMA_TODEVICE); + msg[6] = 0x54000000 | sys_tbl_phys; + + msg[7] = sys_tbl_phys; + msg[8] = 0x54000000 | privbuf[1]; + msg[9] = privbuf[0]; + msg[10] = 0xD4000000 | privbuf[3]; + msg[11] = privbuf[2]; + + ret=i2o_post_wait(iop, msg, sizeof(msg), 120); - ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL); + pci_unmap_single(iop->pdev, sys_tbl_phys, sys_tbl_len, PCI_DMA_TODEVICE); if(ret==-ETIMEDOUT) { @@ -2045,7 +2039,7 @@ /* * Initialize I2O subsystem. */ -static void __init i2o_sys_init(void) +void __init i2o_sys_init(void) { struct i2o_controller *iop, *niop = NULL; @@ -2198,6 +2192,7 @@ int i2o_init_outbound_q(struct i2o_controller *c) { u8 *status; + dma_addr_t status_phys; u32 m; u32 *msg; u32 time; @@ -2208,7 +2203,7 @@ return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); - status = kmalloc(4,GFP_KERNEL); + status = pci_alloc_consistent(c->pdev, 4, &status_phys); if (status==NULL) { printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n", c->name); @@ -2221,11 +2216,10 @@ msg[2]= core_context; msg[3]= 0x0106; /* Transaction context */ msg[4]= 4096; /* Host page frame size */ - /* Frame size is in words. Pick 128, its what everyone elses uses and - other sizes break some adapters. */ - msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ + /* Frame size is in words. 256 bytes a frame for now */ + msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size in words and Initcode */ msg[6]= 0xD0000004; /* Simple SG LE, EOB */ - msg[7]= virt_to_bus(status); + msg[7]= status_phys; i2o_post_message(c,m); @@ -2241,20 +2235,20 @@ else printk(KERN_ERR "%s: Outbound queue initialize timeout.\n", c->name); - kfree(status); + pci_free_consistent(c->pdev, 4, status, status_phys); return -ETIMEDOUT; } - schedule(); + yield(); barrier(); } if(status[0] != I2O_CMD_COMPLETED) { printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name); - kfree(status); + pci_free_consistent(c->pdev, 4, status, status_phys); return -ETIMEDOUT; } - + pci_free_consistent(c->pdev, 4, status, status_phys); return 0; } @@ -2296,7 +2290,7 @@ for(i=0; i< NMBR_MSG_FRAMES; i++) { I2O_REPLY_WRITE32(c,m); mb(); - m += MSG_FRAME_SIZE; + m += (MSG_FRAME_SIZE << 2); } return 0; @@ -2312,7 +2306,7 @@ do { if (c->lct == NULL) { - c->lct = kmalloc(size, GFP_KERNEL); + c->lct = pci_alloc_consistent(c->pdev, size, &c->lct_phys); if(c->lct == NULL) { printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", c->name); @@ -2328,9 +2322,9 @@ msg[4] = 0xFFFFFFFF; /* All devices */ msg[5] = 0x00000000; /* Report now */ msg[6] = 0xD0000000|size; - msg[7] = virt_to_bus(c->lct); + msg[7] = c->lct_phys; - ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL); + ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL, c->lct_phys, 0, size, 0); if(ret == -ETIMEDOUT) { @@ -2346,8 +2340,9 @@ } if (c->lct->table_size << 2 > size) { - size = c->lct->table_size << 2; - kfree(c->lct); + int new_size = c->lct->table_size << 2; + pci_free_consistent(c->pdev, size, c->lct, c->lct_phys); + size = new_size; c->lct = NULL; } } while (c->lct == NULL); @@ -2375,7 +2370,7 @@ msg[4] = 0xFFFFFFFF; /* All devices */ msg[5] = c->dlct->change_ind+1; /* Next change */ msg[6] = 0xD0000000|8192; - msg[7] = virt_to_bus(c->dlct); + msg[7] = c->dlct_phys; return i2o_post_this(c, msg, sizeof(msg)); } @@ -2480,9 +2475,8 @@ sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? sys_tbl->iops[count].iop_capabilities = iop->status_block->iop_capabilities; - sys_tbl->iops[count].inbound_low = - (u32)virt_to_bus(iop->post_port); - sys_tbl->iops[count].inbound_high = 0; // TODO: 64-bit support + sys_tbl->iops[count].inbound_low = iop->post_port; + sys_tbl->iops[count].inbound_high = 0; // FIXME: 64-bit support count++; } @@ -2543,6 +2537,10 @@ * @timeout: time in seconds to wait * @mem1: attached memory buffer 1 * @mem2: attached memory buffer 2 + * @phys1: physical address of buffer 1 + * @phys2: physical address of buffer 2 + * @size1: size of buffer 1 + * @size2: size of buffer 2 * * This core API allows an OSM to post a message and then be told whether * or not the system received a successful reply. @@ -2557,9 +2555,10 @@ * Pass NULL for unneeded buffers. */ -int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2) +int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2, dma_addr_t phys1, dma_addr_t phys2, int size1, int size2) { DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); + DECLARE_WAITQUEUE(wait, current); int complete = 0; int status; unsigned long flags = 0; @@ -2576,6 +2575,11 @@ wait_data->complete = &complete; wait_data->mem[0] = mem1; wait_data->mem[1] = mem2; + wait_data->phys[0] = phys1; + wait_data->phys[1] = phys2; + wait_data->size[0] = size1; + wait_data->size[1] = size2; + /* * Queue the event with its unique id */ @@ -2600,12 +2604,19 @@ * complete will be zero. From the point post_this returns * the wait_data may have been deleted. */ + + add_wait_queue(&wq_i2o_post, &wait); + set_current_state(TASK_INTERRUPTIBLE); if ((status = i2o_post_this(c, msg, len))==0) { - sleep_on_timeout(&wq_i2o_post, HZ * timeout); + schedule_timeout(HZ * timeout); } else + { + remove_wait_queue(&wq_i2o_post, &wait); return -EIO; - + } + remove_wait_queue(&wq_i2o_post, &wait); + if(signal_pending(current)) status = -EINTR; @@ -2650,7 +2661,7 @@ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) { - return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL); + return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL, 0, 0, 0, 0); } /* @@ -2658,7 +2669,7 @@ * sleeping proccess. Called by core's reply handler. */ -static void i2o_post_wait_complete(u32 context, int status) +static void i2o_post_wait_complete(struct i2o_controller *c, u32 context, int status) { struct i2o_post_wait_data **p1, *q; unsigned long flags; @@ -2704,10 +2715,12 @@ /* * Free resources. Caller is dead */ + if(q->mem[0]) - kfree(q->mem[0]); + pci_free_consistent(c->pdev, q->size[0], q->mem[0], q->phys[0]); if(q->mem[1]) - kfree(q->mem[1]); + pci_free_consistent(c->pdev, q->size[1], q->mem[1], q->phys[1]); + printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n"); } kfree(q); @@ -2728,6 +2741,7 @@ * Note that the minimum sized reslist is 8 bytes and contains * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. */ + int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, void *oplist, int oplen, void *reslist, int reslen) { @@ -2738,17 +2752,18 @@ int i = 0; int wait_status; u32 *opmem, *resmem; + dma_addr_t opmem_phys, resmem_phys; /* Get DMAable memory */ - opmem = kmalloc(oplen, GFP_KERNEL); + opmem = pci_alloc_consistent(iop->pdev, oplen, &opmem_phys); if(opmem == NULL) return -ENOMEM; memcpy(opmem, oplist, oplen); - resmem = kmalloc(reslen, GFP_KERNEL); + resmem = pci_alloc_consistent(iop->pdev, reslen, &resmem_phys); if(resmem == NULL) { - kfree(opmem); + pci_free_consistent(iop->pdev, oplen, opmem, opmem_phys); return -ENOMEM; } @@ -2757,11 +2772,11 @@ msg[3] = 0; msg[4] = 0; msg[5] = 0x54000000 | oplen; /* OperationList */ - msg[6] = virt_to_bus(opmem); + msg[6] = opmem_phys; msg[7] = 0xD0000000 | reslen; /* ResultList */ - msg[8] = virt_to_bus(resmem); + msg[8] = resmem_phys; - wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem); + wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem, opmem_phys, resmem_phys, oplen, reslen); /* * This only looks like a memory leak - don't "fix" it. @@ -2769,15 +2784,13 @@ if(wait_status == -ETIMEDOUT) return wait_status; + memcpy(reslist, resmem, reslen); + pci_free_consistent(iop->pdev, reslen, resmem, resmem_phys); + pci_free_consistent(iop->pdev, oplen, opmem, opmem_phys); + /* Query failed */ if(wait_status != 0) - { - kfree(resmem); - kfree(opmem); - return wait_status; - } - - memcpy(reslist, resmem, reslen); + return wait_status; /* * Calculate number of bytes of Result LIST * We need to loop through each Result BLOCK and grab the length @@ -3407,8 +3420,9 @@ { if(i2o_quiesce_controller(c)) { - printk(KERN_WARNING "i2o: Could not quiesce %s." " - Verify setup on next system power up.\n", c->name); + printk(KERN_WARNING "i2o: Could not quiesce %s.\n" + "Verify setup on next system power up.\n", + c->name); } } @@ -3426,6 +3440,10 @@ EXPORT_SYMBOL(i2o_install_handler); EXPORT_SYMBOL(i2o_remove_handler); +EXPORT_SYMBOL(i2o_install_controller); +EXPORT_SYMBOL(i2o_delete_controller); +EXPORT_SYMBOL(i2o_run_queue); + EXPORT_SYMBOL(i2o_claim_device); EXPORT_SYMBOL(i2o_release_device); EXPORT_SYMBOL(i2o_device_notify_on); @@ -3450,37 +3468,27 @@ EXPORT_SYMBOL(i2o_get_class_name); -#ifdef MODULE +EXPORT_SYMBOL_GPL(i2o_sys_init); MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); MODULE_LICENSE("GPL"); - - -int init_module(void) +static int i2o_core_init(void) { printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); if (i2o_install_handler(&i2o_core_handler) < 0) { - printk(KERN_ERR - "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); + printk(KERN_ERR "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); return 0; } core_context = i2o_core_handler.context; /* - * Attach core to I2O PCI transport (and others as they are developed) - */ -#ifdef CONFIG_I2O_PCI_MODULE - if(i2o_pci_core_attach(&i2o_core_functions) < 0) - printk(KERN_INFO "i2o: No PCI I2O controllers found\n"); -#endif - - /* * Initialize event handling thread */ + init_MUTEX_LOCKED(&evt_sem); evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND); if(evt_pid < 0) @@ -3500,7 +3508,7 @@ return 0; } -void cleanup_module(void) +static void i2o_core_exit(void) { int stat; @@ -3521,73 +3529,10 @@ } printk("done.\n"); } - -#ifdef CONFIG_I2O_PCI_MODULE - i2o_pci_core_detach(); -#endif - i2o_remove_handler(&i2o_core_handler); - unregister_reboot_notifier(&i2o_reboot_notifier); } -#else - -extern int i2o_block_init(void); -extern int i2o_config_init(void); -extern int i2o_lan_init(void); -extern int i2o_pci_init(void); -extern int i2o_proc_init(void); -extern int i2o_scsi_init(void); - -int __init i2o_init(void) -{ - printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); - - if (i2o_install_handler(&i2o_core_handler) < 0) - { - printk(KERN_ERR - "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); - return 0; - } - - core_context = i2o_core_handler.context; +module_init(i2o_core_init); +module_exit(i2o_core_exit); - /* - * Initialize event handling thread - * We may not find any controllers, but still want this as - * down the road we may have hot pluggable controllers that - * need to be dealt with. - */ - init_MUTEX_LOCKED(&evt_sem); - if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0) - { - printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); - i2o_remove_handler(&i2o_core_handler); - return 0; - } - - -#ifdef CONFIG_I2O_PCI - i2o_pci_init(); -#endif - - if(i2o_num_controllers) - i2o_sys_init(); - - register_reboot_notifier(&i2o_reboot_notifier); - - i2o_config_init(); -#ifdef CONFIG_I2O_BLOCK - i2o_block_init(); -#endif -#ifdef CONFIG_I2O_LAN - i2o_lan_init(); -#endif -#ifdef CONFIG_I2O_PROC - i2o_proc_init(); -#endif - return 0; -} - -#endif diff -Nru a/drivers/message/i2o/i2o_pci.c b/drivers/message/i2o/i2o_pci.c --- a/drivers/message/i2o/i2o_pci.c Fri Jul 26 19:58:50 2002 +++ b/drivers/message/i2o/i2o_pci.c Fri Jul 26 19:58:50 2002 @@ -2,7 +2,7 @@ * Find I2O capable controllers on the PCI bus, and register/install * them with the I2O layer * - * (C) Copyright 1999 Red Hat Software + * (C) Copyright 1999-2002 Red Hat Software * * Written by Alan Cox, Building Number Three Ltd * Modified by Deepak Saxena @@ -13,8 +13,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * + * Ported to Linux 2.5 by Alan Cox + * * TODO: * Support polled I2O PCI controllers. + * Finish verifying 64bit/bigendian clean */ #include @@ -31,21 +34,17 @@ #include #endif // CONFIG_MTRR -#ifdef MODULE -/* - * Core function table - * See for an explanation - */ -static struct i2o_core_func_table *core; - -/* Core attach function */ -extern int i2o_pci_core_attach(struct i2o_core_func_table *); -extern void i2o_pci_core_detach(void); -#endif /* MODULE */ +static int dpt = 0; + -/* - * Free bus specific resources +/** + * i2o_pci_dispose - Free bus specific resources + * @c: I2O controller + * + * Disable interrupts and then free interrupt, I/O and mtrr resources + * used by this controller. Called by the I2O core on unload. */ + static void i2o_pci_dispose(struct i2o_controller *c) { I2O_IRQ_WRITE32(c,0xFFFFFFFF); @@ -61,9 +60,13 @@ #endif } -/* - * No real bus specific handling yet (note that later we will - * need to 'steal' PCI devices on i960 mainboards) +/** + * i2o_pci_bind - Bind controller and devices + * @c: i2o controller + * @dev: i2o device + * + * Bind a device driver to a controller. In the case of PCI all we need to do + * is module housekeeping. */ static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev) @@ -72,51 +75,83 @@ return 0; } +/** + * i2o_pci_unbind - Bind controller and devices + * @c: i2o controller + * @dev: i2o device + * + * Unbind a device driver from a controller. In the case of PCI all we need to do + * is module housekeeping. + */ + + static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev) { MOD_DEC_USE_COUNT; return 0; } -/* - * Bus specific enable/disable functions +/** + * i2o_pci_enable - Enable controller + * @c: controller + * + * Called by the I2O core code in order to enable bus specific + * resources for this controller. In our case that means unmasking the + * interrupt line. */ + static void i2o_pci_enable(struct i2o_controller *c) { I2O_IRQ_WRITE32(c, 0); c->enabled = 1; } +/** + * i2o_pci_disable - Enable controller + * @c: controller + * + * Called by the I2O core code in order to enable bus specific + * resources for this controller. In our case that means masking the + * interrupt line. + */ + static void i2o_pci_disable(struct i2o_controller *c) { I2O_IRQ_WRITE32(c, 0xFFFFFFFF); c->enabled = 0; } -/* - * Bus specific interrupt handler +/** + * i2o_pci_interrupt - Bus specific interrupt handler + * @irq: interrupt line + * @dev_id: cookie + * + * Handle an interrupt from a PCI based I2O controller. This turns out + * to be rather simple. We keep the controller pointer in the cookie. */ static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) { struct i2o_controller *c = dev_id; -#ifdef MODULE - core->run_queue(c); -#else i2o_run_queue(c); -#endif /* MODULE */ } -/* - * Install a PCI (or in theory AGP) i2o controller +/** + * i2o_pci_install - Install a PCI i2o controller + * @dev: PCI device of the I2O controller * - * TODO: Add support for polled controllers + * Install a PCI (or in theory AGP) i2o controller. Devices are + * initialized, configured and registered with the i2o core subsystem. Be + * very careful with ordering. There may be pending interrupts. + * + * To Do: Add support for polled controllers */ + int __init i2o_pci_install(struct pci_dev *dev) { struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller), GFP_KERNEL); - u8 *mem; + unsigned long mem; u32 memptr = 0; u32 size; @@ -150,8 +185,8 @@ /* Map the I2O controller */ printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size); - mem = ioremap(memptr, size); - if(mem==NULL) + mem = (unsigned long)ioremap(memptr, size); + if(mem==0) { printk(KERN_ERR "i2o: Unable to map controller.\n"); kfree(c); @@ -159,17 +194,16 @@ } c->bus.pci.irq = -1; - c->bus.pci.queue_buggy = 0; c->bus.pci.dpt = 0; c->bus.pci.short_req = 0; c->pdev = dev; - c->irq_mask = (volatile u32 *)(mem+0x34); - c->post_port = (volatile u32 *)(mem+0x40); - c->reply_port = (volatile u32 *)(mem+0x44); + c->irq_mask = mem+0x34; + c->post_port = mem+0x40; + c->reply_port = mem+0x44; c->mem_phys = memptr; - c->mem_offset = (u32)mem; + c->mem_offset = mem; c->destructor = i2o_pci_dispose; c->bind = i2o_pci_bind; @@ -186,14 +220,12 @@ if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630) { - c->bus.pci.short_req=1; + c->bus.pci.short_req = 1; printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n"); } if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) { - c->bus.pci.queue_buggy=1; - if (dev->subsystem_device == 0x0000) /* SX6000 ???? */ - c->bus.pci.queue_buggy=2; + c->bus.pci.promise = 1; printk(KERN_INFO "I2O: Promise workarounds activated.\n"); } @@ -211,10 +243,11 @@ #ifdef CONFIG_MTRR c->bus.pci.mtrr_reg0 = mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1); -/* -* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable -* since the region contains the Messaging unit which shouldn't be cached. -*/ + /* + * If it is an INTEL i960 I/O processor then set the first 64K to + * Uncacheable since the region contains the Messaging unit which + * shouldn't be cached. + */ c->bus.pci.mtrr_reg1 = -1; if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT) { @@ -232,17 +265,13 @@ I2O_IRQ_WRITE32(c,0xFFFFFFFF); -#ifdef MODULE - i = core->install(c); -#else i = i2o_install_controller(c); -#endif /* MODULE */ if(i<0) { printk(KERN_ERR "i2o: Unable to install controller.\n"); kfree(c); - iounmap(mem); + iounmap((void *)mem); return i; } @@ -256,12 +285,8 @@ printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", c->name, dev->irq); c->bus.pci.irq = -1; -#ifdef MODULE - core->delete(c); -#else i2o_delete_controller(c); -#endif /* MODULE */ - iounmap(mem); + iounmap((void *)mem); return -EBUSY; } } @@ -272,6 +297,19 @@ return 0; } +/** + * i2o_pci_scan - Scan the pci bus for controllers + * + * Scan the PCI devices on the system looking for any device which is a + * memory of the Intelligent, I2O class. We attempt to set up each such device + * and register it with the core. + * + * Returns the number of controllers registered + * + * Note; Do not change this to a hot plug interface. I2O 1.5 itself + * does not support hot plugging. + */ + int __init i2o_pci_scan(void) { struct pci_dev *dev; @@ -283,7 +321,7 @@ { if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) continue; - if(dev->vendor == PCI_VENDOR_ID_DPT) + if(dev->vendor == PCI_VENDOR_ID_DPT && !dpt) { if(dev->device == 0xA501 || dev->device == 0xA511) { @@ -300,6 +338,11 @@ continue; printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n", dev->bus->number, dev->devfn); + if(pci_set_dma_mask(dev, 0xffffffff)) + { + printk(KERN_WARNING "I2O controller on bus %d at %d : No suitable DMA available\n", dev->bus->number, dev->devfn); + continue; + } pci_set_master(dev); if(i2o_pci_install(dev)==0) count++; @@ -310,84 +353,43 @@ return count?count:-ENODEV; } -#ifdef I2O_HOTPLUG_SUPPORT -/* - * Activate a newly found PCI I2O controller - * Not used now, but will be needed in future for - * hot plug PCI support + +/** + * i2o_pci_core_attach - PCI initialisation for I2O + * + * Find any I2O controllers and if present initialise them and bring up + * the I2O subsystem. + * + * Returns 0 on success or an error code */ -static void i2o_pci_activate(i2o_controller * c) + +static int i2o_pci_core_attach(void) { - int i=0; - struct i2o_controller *c; - - if(c->type == I2O_TYPE_PCI) + printk(KERN_INFO "Linux I2O PCI support (c) 1999-2002 Red Hat.\n"); + if(i2o_pci_scan()>0) { - I2O_IRQ_WRITE32(c,0); -#ifdef MODULE - if(core->activate(c)) -#else - if(i2o_activate_controller(c)) -#endif /* MODULE */ - { - printk("%s: Failed to initialize.\n", c->name); -#ifdef MODULE - core->unlock(c); - core->delete(c); -#else - i2o_unlock_controller(c); - i2o_delete_controller(c); -#endif - continue; - } + i2o_sys_init(); + return 0; } + return -ENODEV; } -#endif // I2O_HOTPLUG_SUPPORT - -#ifdef MODULE - -int i2o_pci_core_attach(struct i2o_core_func_table *table) -{ - MOD_INC_USE_COUNT; - - core = table; - - return i2o_pci_scan(); -} - -void i2o_pci_core_detach(void) -{ - core = NULL; - - MOD_DEC_USE_COUNT; -} - -int init_module(void) -{ - printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); - - core = NULL; - return 0; +/** + * i2o_pci_core_detach - PCI unload for I2O + * + * Free up any resources not released when the controllers themselves were + * shutdown and unbound from the bus and drivers + */ -} - -void cleanup_module(void) +static void i2o_pci_core_detach(void) { } -EXPORT_SYMBOL(i2o_pci_core_attach); -EXPORT_SYMBOL(i2o_pci_core_detach); - -MODULE_AUTHOR("Red Hat Software"); +MODULE_AUTHOR("Red Hat"); MODULE_DESCRIPTION("I2O PCI Interface"); MODULE_LICENSE("GPL"); - -#else -void __init i2o_pci_init(void) -{ - printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); - i2o_pci_scan(); -} -#endif +MODULE_PARM(dpt, "i"); +MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o"); +module_init(i2o_pci_core_attach); +module_exit(i2o_pci_core_detach); diff -Nru a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c --- a/drivers/message/i2o/i2o_proc.c Fri Jul 26 19:58:50 2002 +++ b/drivers/message/i2o/i2o_proc.c Fri Jul 26 19:58:50 2002 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c --- a/drivers/net/8139cp.c Fri Jul 26 19:58:51 2002 +++ b/drivers/net/8139cp.c Fri Jul 26 19:58:51 2002 @@ -18,6 +18,10 @@ See the file COPYING in this distribution for more information. + Contribuitors: + + Wake-on-LAN support - Felipe Damasio + TODO, in rough priority order: * dev->tx_timeout * LinkChg interrupt @@ -32,7 +36,6 @@ h/w stats can be reset only by software reset * Tx checksumming * Handle netif_rx return value - * ETHTOOL_[GS]WOL, * Investigate using skb->priority with h/w VLAN priority * Investigate using High Priority Tx Queue with skb->priority * Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error @@ -79,7 +82,7 @@ /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; +KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; MODULE_AUTHOR("Jeff Garzik "); MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver"); @@ -87,13 +90,13 @@ static int debug = -1; MODULE_PARM (debug, "i"); -MODULE_PARM_DESC (debug, "8139cp bitmapped message enable number"); +MODULE_PARM_DESC (debug, "8139cp: bitmapped message enable number"); /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 32; MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses"); +MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered multicast addresses"); #define PFX DRV_NAME ": " @@ -260,12 +263,23 @@ /* Config1 register */ DriverLoaded = (1 << 5), /* Software marker, driver is loaded */ + LWACT = (1 << 4), /* LWAKE active mode */ PMEnable = (1 << 0), /* Enable various PM features of chip */ /* Config3 register */ PARMEnable = (1 << 6), /* Enable auto-loading of PHY parms */ + MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ + LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ + + /* Config4 register */ + LWPTN = (1 << 1), /* LWAKE Pattern */ + LWPME = (1 << 4), /* LANWAKE vs PMEB */ /* Config5 register */ + BWF = (1 << 6), /* Accept Broadcast wakeup frame */ + MWF = (1 << 5), /* Accept Multicast wakeup frame */ + UWF = (1 << 4), /* Accept Unicast wakeup frame */ + LANWake = (1 << 1), /* Enable LANWake signal */ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ }; @@ -345,6 +359,8 @@ unsigned dropping_frag : 1; unsigned int board_type; + unsigned int wol_enabled : 1; /* Is Wake-on-LAN enabled? */ + struct mii_if_info mii_if; }; @@ -986,9 +1002,12 @@ cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift)); cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable); - if (cp->board_type == RTL8139Cp) - cpw8(Config3, PARMEnable); /* disables magic packet and WOL */ - cpw8(Config5, cpr8(Config5) & PMEStatus); /* disables more WOL stuff */ + /* Disable Wake-on-LAN. Can be turned on with ETHTOOL_SWOL */ + if (cp->board_type == RTL8139Cp) { + cpw8(Config3, PARMEnable); + cp->wol_enabled = 0; + } + cpw8(Config5, cpr8(Config5) & PMEStatus); if (cp->board_type == RTL8169) cpw16(RxMaxSize, cp->rx_buf_sz); @@ -1220,6 +1239,60 @@ cpw16(mii_2_8139_map[location], value); } +/* Set the ethtool Wake-on-LAN settings */ +static void netdev_set_wol (struct cp_private *cp, + const struct ethtool_wolinfo *wol) +{ + u8 options; + + options = cpr8 (Config3) & ~(LinkUp | MagicPacket); + /* If WOL is being disabled, no need for complexity */ + if (wol->wolopts) { + if (wol->wolopts & WAKE_PHY) options |= LinkUp; + if (wol->wolopts & WAKE_MAGIC) options |= MagicPacket; + } + + cpw8 (Cfg9346, Cfg9346_Unlock); + cpw8 (Config3, options); + cpw8 (Cfg9346, Cfg9346_Lock); + + options = 0; /* Paranoia setting */ + options = cpr8 (Config5) & ~(UWF | MWF | BWF); + /* If WOL is being disabled, no need for complexity */ + if (wol->wolopts) { + if (wol->wolopts & WAKE_UCAST) options |= UWF; + if (wol->wolopts & WAKE_BCAST) options |= BWF; + if (wol->wolopts & WAKE_MCAST) options |= MWF; + } + + cpw8 (Config5, options); + + cp->wol_enabled = (wol->wolopts) ? 1 : 0; +} + +/* Get the ethtool Wake-on-LAN settings */ +static void netdev_get_wol (struct cp_private *cp, + struct ethtool_wolinfo *wol) +{ + u8 options; + + wol->wolopts = 0; /* Start from scratch */ + wol->supported = WAKE_PHY | WAKE_BCAST | WAKE_MAGIC | + WAKE_MCAST | WAKE_UCAST; + /* We don't need to go on if WOL is disabled */ + if (!cp->wol_enabled) return; + + options = cpr8 (Config3); + if (options & LinkUp) wol->wolopts |= WAKE_PHY; + if (options & MagicPacket) wol->wolopts |= WAKE_MAGIC; + + options = 0; /* Paranoia setting */ + options = cpr8 (Config5); + if (options & UWF) wol->wolopts |= WAKE_UCAST; + if (options & BWF) wol->wolopts |= WAKE_BCAST; + if (options & MWF) wol->wolopts |= WAKE_MCAST; +} + static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr) { u32 ethcmd; @@ -1494,6 +1567,27 @@ return 0; } + /* get/set Wake-on-LAN settings */ + case ETHTOOL_GWOL: { + struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; + + spin_lock_irq (&cp->lock); + netdev_get_wol (cp, &wol); + spin_unlock_irq (&cp->lock); + return ((copy_to_user (useraddr, &wol, sizeof (wol)))? -EFAULT : 0); + } + + case ETHTOOL_SWOL: { + struct ethtool_wolinfo wol; + + if (copy_from_user (&wol, useraddr, sizeof (wol))) + return -EFAULT; + spin_lock_irq (&cp->lock); + netdev_set_wol (cp, &wol); + spin_unlock_irq (&cp->lock); + return 0; + } + default: break; } @@ -1606,6 +1700,13 @@ return retval; } +/* Put the board into D3cold state and wait for WakeUp signal */ +static void cp_set_d3_state (struct cp_private *cp) +{ + pci_enable_wake (cp->pdev, 0, 1); /* Enable PME# generation */ + pci_set_power_state (cp->pdev, 3); +} + static int __devinit cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1764,6 +1865,8 @@ } pci_set_master(pdev); + if (cp->wol_enabled) cp_set_d3_state (cp); + return 0; err_out_iomap: @@ -1786,6 +1889,7 @@ BUG(); unregister_netdev(dev); iounmap(cp->regs); + if (cp->wol_enabled) pci_set_power_state (pdev, 0); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -1793,10 +1897,10 @@ } static struct pci_driver cp_driver = { - name: DRV_NAME, - id_table: cp_pci_tbl, - probe: cp_init_one, - remove: __devexit_p(cp_remove_one), + .name = DRV_NAME, + .id_table = cp_pci_tbl, + .probe = cp_init_one, + .remove = __devexit_p(cp_remove_one), }; static int __init cp_init (void) diff -Nru a/drivers/net/aironet4500_card.c b/drivers/net/aironet4500_card.c --- a/drivers/net/aironet4500_card.c Fri Jul 26 19:58:52 2002 +++ b/drivers/net/aironet4500_card.c Fri Jul 26 19:58:52 2002 @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff -Nru a/drivers/net/aironet4500_core.c b/drivers/net/aironet4500_core.c --- a/drivers/net/aironet4500_core.c Fri Jul 26 19:58:50 2002 +++ b/drivers/net/aironet4500_core.c Fri Jul 26 19:58:50 2002 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff -Nru a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c --- a/drivers/net/aironet4500_proc.c Fri Jul 26 19:58:50 2002 +++ b/drivers/net/aironet4500_proc.c Fri Jul 26 19:58:50 2002 @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c --- a/drivers/net/tlan.c Fri Jul 26 19:58:50 2002 +++ b/drivers/net/tlan.c Fri Jul 26 19:58:50 2002 @@ -166,20 +166,18 @@ * Thanks to Gunnar Eikman *******************************************************************************/ -#error Please convert me to Documentation/DMA-mapping.txt - #include - -#include "tlan.h" - #include #include #include +#include #include #include #include +#include #include +#include "tlan.h" typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); @@ -218,10 +216,11 @@ static int bbuf; static u8 *TLanPadBuffer; +static dma_addr_t TLanPadBufferDMA; static char TLanSignature[] = "TLAN"; -static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; -static int tlan_have_pci; -static int tlan_have_eisa; +static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; +static int tlan_have_pci; +static int tlan_have_eisa; const char *media[] = { "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", @@ -422,7 +421,7 @@ unregister_netdev( dev ); if ( priv->dmaStorage ) { - kfree( priv->dmaStorage ); + pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); } release_region( dev->base_addr, 0x10 ); @@ -445,8 +444,7 @@ printk(KERN_INFO "%s", tlan_banner); - TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, - GFP_KERNEL); + TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA); if (TLanPadBuffer == NULL) { printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); @@ -471,7 +469,7 @@ if (TLanDevicesInstalled == 0) { pci_unregister_driver(&tlan_driver); - kfree(TLanPadBuffer); + pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); return -ENODEV; } return 0; @@ -526,12 +524,22 @@ priv = dev->priv; + priv->pciDev = pdev; + /* Is this a PCI device? */ if (pdev) { u32 pci_io_base = 0; priv->adapter = &board_info[ent->driver_data]; + if(pci_set_dma_mask(pdev, 0xFFFFFFFF)) + { + printk(KERN_ERR "TLAN: No suitable PCI mapping available.\n"); + unregister_netdev(dev); + kfree(dev); + return -ENODEV; + } + pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); for ( reg= 0; reg <= 5; reg ++ ) { @@ -639,7 +647,7 @@ dev = TLan_Eisa_Devices; priv = dev->priv; if (priv->dmaStorage) { - kfree(priv->dmaStorage); + pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); } release_region( dev->base_addr, 0x10); unregister_netdev( dev ); @@ -657,7 +665,7 @@ if (tlan_have_eisa) TLan_Eisa_Cleanup(); - kfree( TLanPadBuffer ); + pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); } @@ -808,7 +816,9 @@ dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) ); } - priv->dmaStorage = kmalloc(dma_size, GFP_KERNEL | GFP_DMA); + priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA); + priv->dmaSize = dma_size; + if ( priv->dmaStorage == NULL ) { printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); @@ -818,11 +828,14 @@ memset( priv->dmaStorage, 0, dma_size ); priv->rxList = (TLanList *) ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); + priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 ); priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; + priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS; if ( bbuf ) { priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); - priv->txBuffer = priv->rxBuffer - + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + priv->rxBufferDMA =priv->txListDMA + sizeof(TLanList) * TLAN_NUM_TX_LISTS; + priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + priv->txBufferDMA = priv->rxBufferDMA + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); } err = 0; @@ -1000,6 +1013,7 @@ { TLanPrivateInfo *priv = dev->priv; TLanList *tail_list; + dma_addr_t tail_list_phys; u8 *tail_buffer; int pad; unsigned long flags; @@ -1011,6 +1025,7 @@ } tail_list = priv->txList + priv->txTail; + tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); @@ -1025,7 +1040,7 @@ tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); memcpy( tail_buffer, skb->data, skb->len ); } else { - tail_list->buffer[0].address = virt_to_bus( skb->data ); + tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE); tail_list->buffer[9].address = (u32) skb; } @@ -1035,7 +1050,7 @@ tail_list->frameSize = (u16) skb->len + pad; tail_list->buffer[0].count = (u32) skb->len; tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; - tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer ); + tail_list->buffer[1].address = TLanPadBufferDMA; } else { tail_list->frameSize = (u16) skb->len; tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; @@ -1048,14 +1063,14 @@ if ( ! priv->txInProgress ) { priv->txInProgress = 1; TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); - outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); + outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); } else { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) { - ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = tail_list_phys; } else { - ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); + ( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys; } } spin_unlock_irqrestore(&priv->lock, flags); @@ -1341,6 +1356,7 @@ TLanPrivateInfo *priv = dev->priv; int eoc = 0; TLanList *head_list; + dma_addr_t head_list_phys; u32 ack = 0; u16 tmpCStat; @@ -1350,7 +1366,9 @@ while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { ack++; if ( ! bbuf ) { - dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address ); + struct sk_buff *skb = (struct sk_buff *) head_list->buffer[9].address; + pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); head_list->buffer[9].address = 0; } @@ -1371,8 +1389,9 @@ if ( eoc ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; + head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + outl(head_list_phys, dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO; } else { priv->txInProgress = 0; @@ -1465,9 +1484,11 @@ void *t; u32 frameSize; u16 tmpCStat; + dma_addr_t head_list_phys; TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; + head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { frameSize = head_list->frameSize; @@ -1495,17 +1516,16 @@ struct sk_buff *new_skb; /* - * I changed the algorithm here. What we now do - * is allocate the new frame. If this fails we - * simply recycle the frame. - */ + * I changed the algorithm here. What we now do + * is allocate the new frame. If this fails we + * simply recycle the frame. + */ new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); if ( new_skb != NULL ) { - /* If this ever happened it would be a problem */ - /* not any more - ac */ skb = (struct sk_buff *) head_list->buffer[9].address; + pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); skb_trim( skb, frameSize ); priv->stats.rx_bytes += frameSize; @@ -1516,8 +1536,11 @@ new_skb->dev = dev; skb_reserve( new_skb, 2 ); t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); - head_list->buffer[0].address = virt_to_bus( t ); + head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); head_list->buffer[8].address = (u32) t; +#ifdef __LP64__ +#error "Not 64bit clean" +#endif head_list->buffer[9].address = (u32) new_skb; } else printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); @@ -1526,11 +1549,12 @@ head_list->forward = 0; head_list->cStat = 0; tail_list = priv->rxList + priv->rxTail; - tail_list->forward = virt_to_bus( head_list ); + tail_list->forward = head_list_phys; CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); head_list = priv->rxList + priv->rxHead; + head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; } if (!ack) @@ -1542,7 +1566,8 @@ if ( eoc ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; + outl(head_list_phys, dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; priv->rxEocCount++; } @@ -1621,15 +1646,17 @@ { TLanPrivateInfo *priv = dev->priv; TLanList *head_list; + dma_addr_t head_list_phys; u32 ack = 1; host_int = 0; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; + head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { netif_stop_queue(dev); - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + outl( head_list_phys, dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO; } else { priv->txInProgress = 0; @@ -1742,13 +1769,13 @@ u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) { TLanPrivateInfo *priv = dev->priv; - TLanList *head_list; + dma_addr_t head_list_phys; u32 ack = 1; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); - head_list = priv->rxList + priv->rxHead; - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; + outl( head_list_phys, dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; priv->rxEocCount++; } @@ -1885,6 +1912,7 @@ TLanPrivateInfo *priv = dev->priv; int i; TLanList *list; + dma_addr_t list_phys; struct sk_buff *skb; void *t = NULL; @@ -1894,7 +1922,7 @@ list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; if ( bbuf ) { - list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); + list->buffer[0].address = priv->txBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); } else { list->buffer[0].address = 0; } @@ -1907,11 +1935,12 @@ priv->rxTail = TLAN_NUM_RX_LISTS - 1; for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { list = priv->rxList + i; + list_phys = priv->rxListDMA + sizeof(TLanList) * i; list->cStat = TLAN_CSTAT_READY; list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; if ( bbuf ) { - list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); + list->buffer[0].address = priv->rxBufferDMA + ( i * TLAN_MAX_FRAME_SIZE ); } else { skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); if ( skb == NULL ) { @@ -1922,14 +1951,14 @@ skb_reserve( skb, 2 ); t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); } - list->buffer[0].address = virt_to_bus( t ); + list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); list->buffer[8].address = (u32) t; list->buffer[9].address = (u32) skb; } list->buffer[1].count = 0; list->buffer[1].address = 0; if ( i < TLAN_NUM_RX_LISTS - 1 ) - list->forward = virt_to_bus( list + 1 ); + list->forward = list_phys + sizeof(TLanList); else list->forward = 0; } @@ -1949,6 +1978,7 @@ list = priv->txList + i; skb = (struct sk_buff *) list->buffer[9].address; if ( skb ) { + pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any( skb ); list->buffer[9].address = 0; } @@ -1958,12 +1988,12 @@ list = priv->rxList + i; skb = (struct sk_buff *) list->buffer[9].address; if ( skb ) { + pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb_any( skb ); list->buffer[9].address = 0; } } } - } /* TLan_FreeLists */ @@ -2301,7 +2331,7 @@ if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) { outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); } - outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( priv->rxListDMA, dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); } else { printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); diff -Nru a/drivers/net/tlan.h b/drivers/net/tlan.h --- a/drivers/net/tlan.h Fri Jul 26 19:58:51 2002 +++ b/drivers/net/tlan.h Fri Jul 26 19:58:51 2002 @@ -169,15 +169,22 @@ typedef struct tlan_private_tag { struct net_device *nextDevice; + struct pci_dev *pciDev; void *dmaStorage; + dma_addr_t dmaStorageDMA; + unsigned int dmaSize; u8 *padBuffer; TLanList *rxList; + dma_addr_t rxListDMA; u8 *rxBuffer; + dma_addr_t rxBufferDMA; u32 rxHead; u32 rxTail; u32 rxEocCount; TLanList *txList; + dma_addr_t txListDMA; u8 *txBuffer; + dma_addr_t txBufferDMA; u32 txHead; u32 txInProgress; u32 txTail; diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c --- a/drivers/net/tulip/de2104x.c Fri Jul 26 19:58:51 2002 +++ b/drivers/net/tulip/de2104x.c Fri Jul 26 19:58:51 2002 @@ -2178,7 +2178,7 @@ /* Update the error counts. */ __de_get_stats(de); - synchronize_irq(); + synchronize_irq(dev->irq); de_clean_rings(de); de_adapter_sleep(de); diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c Fri Jul 26 19:58:50 2002 +++ b/drivers/net/tulip/de4x5.c Fri Jul 26 19:58:50 2002 @@ -1522,7 +1522,7 @@ outl(omr|OMR_ST, DE4X5_OMR); /* Poll for setup frame completion (adapter interrupts are disabled now) */ - sti(); /* Ensure timer interrupts */ + for (j=0, i=0;(i<500) && (j==0);i++) { /* Upto 500ms delay */ mdelay(1); if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1; @@ -1644,7 +1644,7 @@ if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt)) printk("%s: Re-entering the interrupt handler.\n", dev->name); - synchronize_irq(); + synchronize_irq(dev->irq); for (limit=0; limit<8; limit++) { sts = inl(DE4X5_STS); /* Read IRQ status */ diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c Fri Jul 26 19:58:50 2002 +++ b/drivers/net/tulip/winbond-840.c Fri Jul 26 19:58:50 2002 @@ -1674,7 +1674,7 @@ spin_unlock_irq(&np->lock); spin_unlock_wait(&dev->xmit_lock); - synchronize_irq(); + synchronize_irq(dev->irq); np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; diff -Nru a/drivers/net/wireless/Config.in b/drivers/net/wireless/Config.in --- a/drivers/net/wireless/Config.in Fri Jul 26 19:58:51 2002 +++ b/drivers/net/wireless/Config.in Fri Jul 26 19:58:51 2002 @@ -33,7 +33,7 @@ # 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 + dep_tristate ' Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards' CONFIG_AIRO_CS $CONFIG_PCMCIA fi # yes, this works even when no drivers are selected diff -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c --- a/drivers/parport/parport_pc.c Fri Jul 26 19:58:51 2002 +++ b/drivers/parport/parport_pc.c Fri Jul 26 19:58:51 2002 @@ -2058,7 +2058,6 @@ int i; unsigned long irqs; - sti(); irqs = probe_irq_on(); ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ @@ -2093,7 +2092,6 @@ if (pb->modes & PARPORT_MODE_PCECR) oecr = inb (ECONTROL (pb)); - sti(); irqs = probe_irq_on(); if (pb->modes & PARPORT_MODE_PCECR) diff -Nru a/drivers/parport/share.c b/drivers/parport/share.c --- a/drivers/parport/share.c Fri Jul 26 19:58:51 2002 +++ b/drivers/parport/share.c Fri Jul 26 19:58:51 2002 @@ -1006,14 +1006,20 @@ #ifdef PARPORT_DEBUG_SHARING printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name); #endif - save_flags (flags); - cli(); + /* + * FIXME!!! Use the proper locking for dev->waiting, + * and make this use the "wait_event_interruptible()" + * interfaces. The cli/sti that used to be here + * did nothing. + * + * See also parport_release() + */ + /* If dev->waiting is clear now, an interrupt gave us the port and we would deadlock if we slept. */ if (dev->waiting) { interruptible_sleep_on (&dev->wait_q); if (signal_pending (current)) { - restore_flags (flags); return -EINTR; } r = 1; @@ -1024,7 +1030,7 @@ dev->name); #endif } - restore_flags(flags); + #ifdef PARPORT_DEBUG_SHARING if (dev->port->physport->cad != dev) printk(KERN_DEBUG "%s: exiting parport_claim_or_block " diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c --- a/drivers/pci/quirks.c Fri Jul 26 19:58:50 2002 +++ b/drivers/pci/quirks.c Fri Jul 26 19:58:50 2002 @@ -457,10 +457,26 @@ } /* + * DreamWorks provided workaround for Dunord I-3000 problem + * + * This card decodes and responds to addresses not apparently + * assigned to it. We force a larger allocation to ensure that + * nothing gets put too close to it. + */ + +static void __init quirk_dunord ( struct pci_dev * dev ) +{ + struct resource * r = & dev -> resource [ 1 ]; + r -> start = 0; + r -> end = 0xffffff; +} + +/* * The main table of quirks. */ static struct pci_fixup pci_fixups[] __initdata = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, /* diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c Fri Jul 26 19:58:52 2002 +++ b/drivers/scsi/BusLogic.c Fri Jul 26 19:58:52 2002 @@ -26,10 +26,8 @@ */ -#define BusLogic_DriverVersion "2.1.15" -#define BusLogic_DriverDate "17 August 1998" - -#error Please convert me to Documentation/DMA-mapping.txt +#define BusLogic_DriverVersion "2.1.16" +#define BusLogic_DriverDate "18 July 2002" #include #include @@ -48,6 +46,7 @@ #include #include #include +/* #include This include file is currently busted */ #include "scsi.h" #include "hosts.h" #include "sd.h" @@ -225,15 +224,19 @@ */ static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter, - void *BlockPointer, int BlockSize) + void *BlockPointer, int BlockSize, + dma_addr_t BlockPointerHandle) { BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer; + unsigned int offset = 0; memset(BlockPointer, 0, BlockSize); - CCB->AllocationGroupHead = true; + CCB->AllocationGroupHead = BlockPointerHandle; + CCB->AllocationGroupSize = BlockSize; while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0) { CCB->Status = BusLogic_CCB_Free; CCB->HostAdapter = HostAdapter; + CCB->DMA_Handle = (BusLogic_BusAddress_T)BlockPointerHandle + offset; if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { CCB->CallbackFunction = BusLogic_QueueCompletedCCB; @@ -245,6 +248,7 @@ HostAdapter->All_CCBs = CCB; HostAdapter->AllocatedCCBs++; CCB++; + offset += sizeof(BusLogic_CCB_T); } } @@ -256,19 +260,20 @@ static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter) { int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); + void *BlockPointer; + dma_addr_t BlockPointerHandle; while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) { - void *BlockPointer = kmalloc(BlockSize, - (HostAdapter->BounceBuffersRequired - ? GFP_ATOMIC | GFP_DMA - : GFP_ATOMIC)); + BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, + &BlockPointerHandle); if (BlockPointer == NULL) { BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", HostAdapter); return false; } - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, + BlockPointerHandle); } return true; } @@ -280,15 +285,25 @@ static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter) { - BusLogic_CCB_T *NextCCB = HostAdapter->All_CCBs, *CCB; + BusLogic_CCB_T *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL; HostAdapter->All_CCBs = NULL; HostAdapter->Free_CCBs = NULL; while ((CCB = NextCCB) != NULL) { NextCCB = CCB->NextAll; if (CCB->AllocationGroupHead) - kfree(CCB); + { + if (Last_CCB) + pci_free_consistent(HostAdapter->PCI_Device, + Last_CCB->AllocationGroupSize, Last_CCB, + Last_CCB->AllocationGroupHead); + Last_CCB = CCB; + } } + if (Last_CCB) + pci_free_consistent(HostAdapter->PCI_Device, + Last_CCB->AllocationGroupSize, Last_CCB, + Last_CCB->AllocationGroupHead); } @@ -305,15 +320,16 @@ { int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); int PreviouslyAllocated = HostAdapter->AllocatedCCBs; + void *BlockPointer; + dma_addr_t BlockPointerHandle; if (AdditionalCCBs <= 0) return; while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) { - void *BlockPointer = kmalloc(BlockSize, - (HostAdapter->BounceBuffersRequired - ? GFP_ATOMIC | GFP_DMA - : GFP_ATOMIC)); + BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, + &BlockPointerHandle); if (BlockPointer == NULL) break; - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, + BlockPointerHandle); } if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) { @@ -379,6 +395,21 @@ static void BusLogic_DeallocateCCB(BusLogic_CCB_T *CCB) { BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter; + if (CCB->Command->use_sg != 0) + { + pci_unmap_sg(HostAdapter->PCI_Device, + (SCSI_ScatterList_T *)CCB->Command->request_buffer, + CCB->Command->use_sg, + scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); + } + else if (CCB->Command->request_bufflen != 0) + { + pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer, + CCB->DataLength, + scsi_to_pci_dma_dir(CCB->Command->sc_data_direction)); + } + pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer, + CCB->SenseDataLength, PCI_DMA_FROMDEVICE); CCB->Command = NULL; CCB->Status = BusLogic_CCB_Free; CCB->Next = HostAdapter->Free_CCBs; @@ -431,8 +462,8 @@ */ if (!HostAdapter->IRQ_ChannelAcquired) { - save_flags(ProcessorFlags); - cli(); + local_irq_save(ProcessorFlags); + local_irq_disable(); } /* Wait for the Host Adapter Ready bit to be set and the Command/Parameter @@ -624,7 +655,7 @@ */ Done: if (!HostAdapter->IRQ_ChannelAcquired) - restore_flags(ProcessorFlags); + local_irq_restore(ProcessorFlags); return Result; } @@ -643,6 +674,7 @@ ProbeInfo->HostAdapterType = BusLogic_MultiMaster; ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Device = NULL; } @@ -769,8 +801,8 @@ BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation; BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; - unsigned char Bus = PCI_Device->bus->number; - unsigned char Device = PCI_Device->devfn >> 3; + unsigned char Bus; + unsigned char Device; unsigned int IRQ_Channel; unsigned long BaseAddress0; unsigned long BaseAddress1; @@ -779,7 +811,12 @@ if (pci_enable_device(PCI_Device)) continue; + + if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) + continue; + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; IRQ_Channel = PCI_Device->irq; IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); @@ -889,6 +926,7 @@ PrimaryProbeInfo->Bus = Bus; PrimaryProbeInfo->Device = Device; PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; + PrimaryProbeInfo->PCI_Device = PCI_Device; PCIMultiMasterCount++; } else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) @@ -902,6 +940,7 @@ ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; NonPrimaryPCIMultiMasterCount++; PCIMultiMasterCount++; } @@ -978,13 +1017,21 @@ PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) { - unsigned char Bus = PCI_Device->bus->number; - unsigned char Device = PCI_Device->devfn >> 3; - unsigned int IRQ_Channel = PCI_Device->irq; - BusLogic_IO_Address_T IO_Address = pci_resource_start(PCI_Device, 0); + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + BusLogic_IO_Address_T IO_Address; if (pci_enable_device(PCI_Device)) - continue; + continue; + + if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) + continue; + + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = pci_resource_start(PCI_Device, 0); if (IO_Address == 0 || IRQ_Channel == 0) continue; for (i = 0; i < BusLogic_ProbeInfoCount; i++) @@ -998,6 +1045,7 @@ ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; break; } } @@ -1025,17 +1073,25 @@ PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) { - unsigned char Bus = PCI_Device->bus->number; - unsigned char Device = PCI_Device->devfn >> 3; - unsigned int IRQ_Channel = PCI_Device->irq; - unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0); - unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1); - BusLogic_IO_Address_T IO_Address = BaseAddress0; - BusLogic_PCI_Address_T PCI_Address = BaseAddress1; + unsigned char Bus; + unsigned char Device; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + BusLogic_IO_Address_T IO_Address; + BusLogic_PCI_Address_T PCI_Address; if (pci_enable_device(PCI_Device)) - continue; + continue; + + if (pci_set_dma_mask(PCI_Device, (u64)0xffffffff)) + continue; + Bus = PCI_Device->bus->number; + Device = PCI_Device->devfn >> 3; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); #ifndef CONFIG_SCSI_OMIT_FLASHPOINT if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { @@ -1080,6 +1136,7 @@ ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; + ProbeInfo->PCI_Device = PCI_Device; FlashPointCount++; } else BusLogic_Warning("BusLogic: Too many Host Adapters " @@ -2299,6 +2356,16 @@ */ if (HostAdapter->DMA_ChannelAcquired) free_dma(HostAdapter->DMA_Channel); + /* + Release any allocated memory structs not released elsewhere + */ + if (HostAdapter->MailboxSpace) + pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, + HostAdapter->MailboxSpace, + HostAdapter->MailboxSpaceHandle); + HostAdapter->MailboxSpace = NULL; + HostAdapter->MailboxSpaceHandle = 0; + HostAdapter->MailboxSize = 0; } @@ -2341,6 +2408,12 @@ /* Initialize the Outgoing and Incoming Mailbox pointers. */ + HostAdapter->MailboxSize = HostAdapter->MailboxCount * + (sizeof(BusLogic_OutgoingMailbox_T) + sizeof(BusLogic_IncomingMailbox_T)); + HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, + HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle); + if (HostAdapter->MailboxSpace == NULL) + return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION"); HostAdapter->FirstOutgoingMailbox = (BusLogic_OutgoingMailbox_T *) HostAdapter->MailboxSpace; HostAdapter->LastOutgoingMailbox = @@ -2351,6 +2424,7 @@ HostAdapter->LastIncomingMailbox = HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; + /* Initialize the Outgoing and Incoming Mailbox structures. */ @@ -2363,7 +2437,7 @@ */ ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; ExtendedMailboxRequest.BaseMailboxAddress = - Virtual_to_Bus(HostAdapter->FirstOutgoingMailbox); + (BusLogic_BusAddress_T) HostAdapter->MailboxSpaceHandle; if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, &ExtendedMailboxRequest, sizeof(ExtendedMailboxRequest), NULL, 0) < 0) @@ -2838,7 +2912,8 @@ HostAdapter->AddressCount, HostAdapter->FullModelName)) { printk(KERN_WARNING "BusLogic: Release and re-register of " - "port 0x%04lx failed \n", HostAdapter->IO_Address); + "port 0x%04lx failed \n", + (unsigned long)HostAdapter->IO_Address); BusLogic_DestroyCCBs(HostAdapter); BusLogic_ReleaseResources(HostAdapter); BusLogic_UnregisterHostAdapter(HostAdapter); @@ -3013,6 +3088,13 @@ while ((CompletionCode = NextIncomingMailbox->CompletionCode) != BusLogic_IncomingMailboxFree) { + /* + We are only allowed to do this because we limit our architectures we + run on to machines where bus_to_virt() actually works. There *needs* + to be a dma_addr_to_virt() in the new PCI DMA mapping interface to + replace bus_to_virt() or else this code is going to become very + innefficient. + */ BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) Bus_to_Virtual(NextIncomingMailbox->CCB); if (CompletionCode != BusLogic_AbortedCommandNotFound) @@ -3285,7 +3367,6 @@ BusLogic_ResetHostAdapter(HostAdapter, NULL, 0); HostAdapter->HostAdapterExternalReset = false; HostAdapter->HostAdapterInternalError = false; - scsi_mark_host_reset(HostAdapter->SCSI_Host); } /* Release exclusive access to Host Adapter. @@ -3315,7 +3396,7 @@ the Host Adapter is operating asynchronously and the locking code does not protect against simultaneous access by the Host Adapter. */ - NextOutgoingMailbox->CCB = Virtual_to_Bus(CCB); + NextOutgoingMailbox->CCB = CCB->DMA_Handle; NextOutgoingMailbox->ActionCode = ActionCode; BusLogic_StartMailboxCommand(HostAdapter); if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) @@ -3354,7 +3435,6 @@ void *BufferPointer = Command->request_buffer; int BufferLength = Command->request_bufflen; int SegmentCount = Command->use_sg; - ProcessorFlags_T ProcessorFlags; BusLogic_CCB_T *CCB; /* SCSI REQUEST_SENSE commands will be executed automatically by the Host @@ -3368,10 +3448,6 @@ return 0; } /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags); - /* Allocate a CCB from the Host Adapter's free list. In the unlikely event that there are none available and memory allocation fails, wait 1 second and try again. If that fails, the Host Adapter is probably hung so signal @@ -3380,41 +3456,56 @@ CCB = BusLogic_AllocateCCB(HostAdapter); if (CCB == NULL) { + BusLogic_ReleaseHostAdapterLock(HostAdapter); BusLogic_Delay(1); + BusLogic_AcquireHostAdapterLock(HostAdapter); CCB = BusLogic_AllocateCCB(HostAdapter); if (CCB == NULL) { Command->result = DID_ERROR << 16; CompletionRoutine(Command); - goto Done; + return 0; } } /* Initialize the fields in the BusLogic Command Control Block (CCB). */ - if (SegmentCount == 0) + if (SegmentCount == 0 && BufferLength != 0) { CCB->Opcode = BusLogic_InitiatorCCB; CCB->DataLength = BufferLength; - CCB->DataPointer = Virtual_to_Bus(BufferPointer); + CCB->DataPointer = + pci_map_single(HostAdapter->PCI_Device, BufferPointer, BufferLength, + scsi_to_pci_dma_dir(Command->sc_data_direction)); } - else + else if (SegmentCount != 0) { SCSI_ScatterList_T *ScatterList = (SCSI_ScatterList_T *) BufferPointer; - int Segment; + int Segment, Count; + + Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount, + scsi_to_pci_dma_dir(Command->sc_data_direction)); CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; - CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T); + CCB->DataLength = Count * sizeof(BusLogic_ScatterGatherSegment_T); if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList); + CCB->DataPointer = (unsigned int)CCB->DMA_Handle + + ((unsigned int)&CCB->ScatterGatherList - + (unsigned int)CCB); else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); - for (Segment = 0; Segment < SegmentCount; Segment++) + for (Segment = 0; Segment < Count; Segment++) { CCB->ScatterGatherList[Segment].SegmentByteCount = - ScatterList[Segment].length; + sg_dma_len(ScatterList+Segment); CCB->ScatterGatherList[Segment].SegmentDataPointer = - Virtual_to_Bus(ScatterList[Segment].address); + sg_dma_address(ScatterList+Segment); } } + else + { + CCB->Opcode = BusLogic_InitiatorCCB; + CCB->DataLength = BufferLength; + CCB->DataPointer = 0; + } switch (CDB[0]) { case READ_6: @@ -3440,7 +3531,6 @@ break; } CCB->CDB_Length = CDB_Length; - CCB->SenseDataLength = sizeof(Command->sense_buffer); CCB->HostAdapterStatus = 0; CCB->TargetDeviceStatus = 0; CCB->TargetID = TargetID; @@ -3507,7 +3597,11 @@ } } memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataPointer = Virtual_to_Bus(&Command->sense_buffer); + CCB->SenseDataLength = sizeof(Command->sense_buffer); + CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, + Command->sense_buffer, + CCB->SenseDataLength, + PCI_DMA_FROMDEVICE); CCB->Command = Command; Command->scsi_done = CompletionRoutine; if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) @@ -3523,9 +3617,11 @@ if (!BusLogic_WriteOutgoingMailbox( HostAdapter, BusLogic_MailboxStartCommand, CCB)) { + BusLogic_ReleaseHostAdapterLock(HostAdapter); BusLogic_Warning("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", HostAdapter); BusLogic_Delay(1); + BusLogic_AcquireHostAdapterLock(HostAdapter); if (!BusLogic_WriteOutgoingMailbox( HostAdapter, BusLogic_MailboxStartCommand, CCB)) { @@ -3553,11 +3649,6 @@ if (CCB->Status == BusLogic_CCB_Completed) BusLogic_ProcessCompletedCCBs(HostAdapter); } - /* - Release exclusive access to Host Adapter. - */ -Done: - BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags); return 0; } @@ -3571,24 +3662,18 @@ BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Command->host->hostdata; int TargetID = Command->target; - ProcessorFlags_T ProcessorFlags; BusLogic_CCB_T *CCB; int Result; BusLogic_IncrementErrorCounter( &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags); - /* If this Command has already completed, then no Abort is necessary. */ if (Command->serial_number != Command->serial_number_at_timeout) { BusLogic_Warning("Unable to Abort Command to Target %d - " "Already Completed\n", HostAdapter, TargetID); - Result = SCSI_ABORT_NOT_RUNNING; - goto Done; + return SCSI_ABORT_NOT_RUNNING; } /* Attempt to find an Active CCB for this Command. If no Active CCB for this @@ -3600,22 +3685,19 @@ { BusLogic_Warning("Unable to Abort Command to Target %d - " "No CCB Found\n", HostAdapter, TargetID); - Result = SCSI_ABORT_NOT_RUNNING; - goto Done; + return SCSI_ABORT_NOT_RUNNING; } else if (CCB->Status == BusLogic_CCB_Completed) { BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Completed\n", HostAdapter, TargetID); - Result = SCSI_ABORT_NOT_RUNNING; - goto Done; + return SCSI_ABORT_NOT_RUNNING; } else if (CCB->Status == BusLogic_CCB_Reset) { BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Reset\n", HostAdapter, TargetID); - Result = SCSI_ABORT_PENDING; - goto Done; + return SCSI_ABORT_PENDING; } if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { @@ -3676,11 +3758,6 @@ Result = SCSI_ABORT_SUCCESS; } } - /* - Release exclusive access to Host Adapter. - */ -Done: - BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags); return Result; } @@ -3694,7 +3771,6 @@ SCSI_Command_T *Command, unsigned int ResetFlags) { - ProcessorFlags_T ProcessorFlags; BusLogic_CCB_T *CCB; int TargetID, Result; boolean HardReset; @@ -3716,10 +3792,6 @@ HardReset = true; } /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags); - /* If this is an Asynchronous Reset and this Command has already completed, then no Reset is necessary. */ @@ -3804,7 +3876,11 @@ already been marked Reset and so a reentrant call will return Pending. */ if (HardReset) - BusLogic_Delay(HostAdapter->BusSettleTime); + { + BusLogic_ReleaseHostAdapterLock(HostAdapter); + BusLogic_Delay(HostAdapter->BusSettleTime); + BusLogic_AcquireHostAdapterLock(HostAdapter); + } /* If this is a Synchronous Reset, perform completion processing for the Command being Reset. @@ -3837,11 +3913,7 @@ HostAdapter->LastResetCompleted[TargetID] = jiffies; } Result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; - /* - Release exclusive access to Host Adapter. - */ Done: - BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags); return Result; } @@ -3857,15 +3929,10 @@ { int TargetID = Command->target; BusLogic_CCB_T *CCB, *XCCB; - ProcessorFlags_T ProcessorFlags; int Result = -1; BusLogic_IncrementErrorCounter( &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested); /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags); - /* If this is an Asynchronous Reset and this Command has already completed, then no Reset is necessary. */ @@ -4026,10 +4093,6 @@ Done: if (Result < 0) Result = BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags); - /* - Release exclusive access to Host Adapter. - */ - BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags); return Result; } @@ -4109,8 +4172,8 @@ table, then the translation inferred from the partition table will be used by the BIOS, and a warning may be displayed. */ - -int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, struct block_device *bdev, +unsigned char *scsi_bios_ptable(struct block_device *); +int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, struct block_device *Device, int *Parameters) { BusLogic_HostAdapter_T *HostAdapter = @@ -4138,7 +4201,7 @@ } DiskParameters->Cylinders = Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors); - buf = scsi_bios_ptable(bdev); + buf = scsi_bios_ptable(Device); if (buf == NULL) return 0; /* If the boot sector partition table flag is valid, search for a partition diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h --- a/drivers/scsi/BusLogic.h Fri Jul 26 19:58:51 2002 +++ b/drivers/scsi/BusLogic.h Fri Jul 26 19:58:51 2002 @@ -57,7 +57,8 @@ void (*CompletionRoutine)(SCSI_Command_T *)); extern int BusLogic_AbortCommand(SCSI_Command_T *); extern int BusLogic_ResetCommand(SCSI_Command_T *, unsigned int); -extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *, int *); +extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *, + int *); extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int); @@ -371,6 +372,7 @@ BusLogic_HostAdapterBusType_T HostAdapterBusType; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; + PCI_Device_T *PCI_Device; unsigned char Bus; unsigned char Device; unsigned char IRQ_Channel; @@ -1191,7 +1193,9 @@ /* BusLogic Linux Driver Defined Portion. */ - boolean AllocationGroupHead; + dma_addr_t AllocationGroupHead; + unsigned int AllocationGroupSize; + BusLogic_BusAddress_T DMA_Handle; BusLogic_CCB_Status_T Status; unsigned long SerialNumber; SCSI_Command_T *Command; @@ -1355,6 +1359,7 @@ typedef struct BusLogic_HostAdapter { SCSI_Host_T *SCSI_Host; + PCI_Device_T *PCI_Device; BusLogic_HostAdapterType_T HostAdapterType; BusLogic_HostAdapterBusType_T HostAdapterBusType; BusLogic_IO_Address_T IO_Address; @@ -1443,9 +1448,13 @@ BusLogic_IncomingMailbox_T *LastIncomingMailbox; BusLogic_IncomingMailbox_T *NextIncomingMailbox; BusLogic_TargetStatistics_T TargetStatistics[BusLogic_MaxTargetDevices]; - unsigned char MailboxSpace[BusLogic_MaxMailboxes + unsigned char *MailboxSpace; + dma_addr_t MailboxSpaceHandle; + unsigned int MailboxSize; + unsigned long CCB_Offset; +/* [BusLogic_MaxMailboxes * (sizeof(BusLogic_OutgoingMailbox_T) - + sizeof(BusLogic_IncomingMailbox_T))]; + + sizeof(BusLogic_IncomingMailbox_T))]; */ char MessageBuffer[BusLogic_MessageBufferSize]; } BusLogic_HostAdapter_T; @@ -1504,9 +1513,9 @@ */ static inline -void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter, - ProcessorFlags_T *ProcessorFlags) +void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter) { + spin_lock_irq(HostAdapter->SCSI_Host->host_lock); } @@ -1515,9 +1524,9 @@ */ static inline -void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter, - ProcessorFlags_T *ProcessorFlags) +void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter) { + spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); } @@ -1648,12 +1657,7 @@ static inline void BusLogic_Delay(int Seconds) { - int Milliseconds = 1000 * Seconds; - unsigned long ProcessorFlags; - save_flags(ProcessorFlags); - sti(); - while (--Milliseconds >= 0) udelay(1000); - restore_flags(ProcessorFlags); + mdelay(1000 * Seconds); } diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c --- a/drivers/scsi/atp870u.c Fri Jul 26 19:58:51 2002 +++ b/drivers/scsi/atp870u.c Fri Jul 26 19:58:51 2002 @@ -3,6 +3,7 @@ * * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski + * 2.5.x update (C) 2002 Red Hat * * Marcelo Tosatti : SMP fixes * @@ -11,11 +12,10 @@ * enable 32 bit fifo transfer * support cdrom & remove device run ultra speed * fix disconnect bug 2000/12/21 - * support atp880 chip lvd u160 2001/05/15 (7.1) + * support atp880 chip lvd u160 2001/05/15 + * fix prd table bug 2001/09/12 (7.1) */ -#error Please convert me to Documentation/DMA-mapping.txt - #include #include @@ -38,19 +38,15 @@ #include -void mydlyu(unsigned int); - /* * static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $"; */ -static unsigned char admaxu = 1; static unsigned short int sync_idu; -static unsigned int irqnumu[2] = {0, 0}; +#define MAX_ATP 16 -struct atp_unit -{ +struct atp_unit { unsigned long ioport; unsigned long irq; unsigned long pciport; @@ -72,8 +68,7 @@ unsigned char ata_cdbu[16]; unsigned char sp[16]; Scsi_Cmnd *querequ[qcnt]; - struct atp_id - { + struct atp_id { unsigned char dirctu; unsigned char devspu; unsigned char devtypeu; @@ -82,58 +77,50 @@ unsigned long last_lenu; unsigned char *prd_posu; unsigned char *prd_tableu; + dma_addr_t prd_phys; Scsi_Cmnd *curr_req; } id[16]; + struct Scsi_Host *host; + struct pci_dev *pdev; }; -static struct Scsi_Host *atp_host[2] = {NULL, NULL}; -static struct atp_unit atp_unit[2]; +static struct Scsi_Host *atp_host[MAX_ATP]; + +static void send_s870(struct Scsi_Host *); static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; unsigned short int tmpcip, id; - unsigned char i, j, h, target_id, lun; + unsigned char i, j, target_id, lun; unsigned char *prd; Scsi_Cmnd *workrequ; unsigned int workportu, tmport; unsigned long adrcntu, k; int errstus; - struct atp_unit *dev = dev_id; + struct Scsi_Host *host = dev_id; + struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - for (h = 0; h < 2; h++) { - if (irq == irqnumu[h]) { - goto irq_numok; - } - } - return; -irq_numok: dev->in_int = 1; workportu = dev->ioport; tmport = workportu; - if (dev->working != 0) - { + if (dev->working != 0) { tmport += 0x1f; j = inb(tmport); - if ((j & 0x80) == 0) - { + if ((j & 0x80) == 0) { dev->in_int = 0; return; } tmpcip = dev->pciport; - if ((inb(tmpcip) & 0x08) != 0) - { + if ((inb(tmpcip) & 0x08) != 0) { tmpcip += 0x2; - for (k=0; k < 1000; k++) - { - if ((inb(tmpcip) & 0x08) == 0) - { + for (k = 0; k < 1000; k++) { + if ((inb(tmpcip) & 0x08) == 0) { goto stop_dma; } - if ((inb(tmpcip) & 0x01) == 0) - { + if ((inb(tmpcip) & 0x01) == 0) { goto stop_dma; } } @@ -150,7 +137,7 @@ tmport += 0x02; /* - * Remap wide devices onto id numbers + * Remap wide devices onto id numbers */ if ((target_id & 0x40) != 0) { @@ -159,60 +146,49 @@ target_id &= 0x07; } - if ((j & 0x40) != 0) - { - if (dev->last_cmd == 0xff) - { - dev->last_cmd = target_id; - } - dev->last_cmd |= 0x40; + if ((j & 0x40) != 0) { + if (dev->last_cmd == 0xff) { + dev->last_cmd = target_id; + } + dev->last_cmd |= 0x40; } - if (i == 0x85) - { - if ((dev->last_cmd & 0xf0) != 0x40) - { - dev->last_cmd = 0xff; + if (i == 0x85) { + if ((dev->last_cmd & 0xf0) != 0x40) { + dev->last_cmd = 0xff; } /* - * Flip wide + * Flip wide */ - if (dev->wide_idu != 0) - { + if (dev->wide_idu != 0) { tmport = workportu + 0x1b; - outb(0x01,tmport); - while ((inb(tmport) & 0x01) != 0x01) - { - outb(0x01,tmport); + outb(0x01, tmport); + while ((inb(tmport) & 0x01) != 0x01) { + outb(0x01, tmport); } } /* - * Issue more commands + * Issue more commands */ - if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) && - (dev->in_snd == 0)) - { - send_s870(h); + if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) && (dev->in_snd == 0)) { + send_s870(host); } /* - * Done + * Done */ dev->in_int = 0; return; } - if (i == 0x40) - { - dev->last_cmd |= 0x40; - dev->in_int = 0; - return; + if (i == 0x40) { + dev->last_cmd |= 0x40; + dev->in_int = 0; + return; } - if (i == 0x21) - { - if ((dev->last_cmd & 0xf0) != 0x40) - { - dev->last_cmd = 0xff; + if (i == 0x21) { + if ((dev->last_cmd & 0xf0) != 0x40) { + dev->last_cmd = 0xff; } tmport -= 0x05; adrcntu = 0; @@ -230,21 +206,18 @@ dev->in_int = 0; return; } - if ((i == 0x80) || (i == 0x8f)) - { + if ((i == 0x80) || (i == 0x8f)) { lun = 0; tmport -= 0x07; j = inb(tmport); - if (j == 0x44 || i==0x80) { + if (j == 0x44 || i == 0x80) { tmport += 0x0d; lun = inb(tmport) & 0x07; } else { - if ((dev->last_cmd & 0xf0) != 0x40) - { - dev->last_cmd = 0xff; + if ((dev->last_cmd & 0xf0) != 0x40) { + dev->last_cmd = 0xff; } - if (j == 0x41) - { + if (j == 0x41) { tmport += 0x02; adrcntu = 0; ((unsigned char *) &adrcntu)[2] = inb(tmport++); @@ -258,9 +231,7 @@ outb(0x08, tmport); dev->in_int = 0; return; - } - else - { + } else { outb(0x46, tmport); dev->id[target_id].dirctu = 0x00; tmport += 0x02; @@ -273,19 +244,17 @@ return; } } - if (dev->last_cmd != 0xff) - { - dev->last_cmd |= 0x40; + if (dev->last_cmd != 0xff) { + dev->last_cmd |= 0x40; } tmport = workportu + 0x10; outb(0x45, tmport); tmport += 0x06; target_id = inb(tmport); /* - * Remap wide identifiers + * Remap wide identifiers */ - if ((target_id & 0x10) != 0) - { + if ((target_id & 0x10) != 0) { target_id = (target_id & 0x07) | 0x08; } else { target_id &= 0x07; @@ -311,31 +280,20 @@ outb(0x80, tmport); /* enable 32 bit fifo transfer */ - if (dev->deviceid != 0x8081) - { - tmport = workportu + 0x3a; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || - (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) - { - outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); - } - else - { - outb((unsigned char)(inb(tmport) & 0xf3),tmport); - } - } - else - { - tmport = workportu - 0x05; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || - (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) - { - outb((unsigned char)((inb(tmport) & 0x3f) | 0xc0),tmport); - } - else - { - outb((unsigned char)(inb(tmport) & 0x3f),tmport); - } + if (dev->deviceid != 0x8081) { + tmport = workportu + 0x3a; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { + outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport); + } else { + outb((unsigned char) (inb(tmport) & 0xf3), tmport); + } + } else { + tmport = workportu - 0x05; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { + outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); + } else { + outb((unsigned char) (inb(tmport) & 0x3f), tmport); + } } tmport = workportu + 0x1b; @@ -343,15 +301,14 @@ id = 1; id = id << target_id; /* - * Is this a wide device + * Is this a wide device */ if ((id & dev->wide_idu) != 0) { j |= 0x01; } outb(j, tmport); - while ((inb(tmport) & 0x01) != j) - { - outb(j,tmport); + while ((inb(tmport) & 0x01) != j) { + outb(j, tmport); } if (dev->id[target_id].last_lenu == 0) { @@ -361,8 +318,7 @@ return; } prd = dev->id[target_id].prd_posu; - while (adrcntu != 0) - { + while (adrcntu != 0) { id = ((unsigned short int *) (prd))[2]; if (id == 0) { k = 0x10000; @@ -392,7 +348,7 @@ tmpcip -= 0x02; tmport = workportu + 0x18; /* - * Check transfer direction + * Check transfer direction */ if (dev->id[target_id].dirctu != 0) { outb(0x08, tmport); @@ -407,25 +363,22 @@ } /* - * Current scsi request on this target + * Current scsi request on this target */ workrequ = dev->id[target_id].curr_req; if (i == 0x42) { - if ((dev->last_cmd & 0xf0) != 0x40) - { - dev->last_cmd = 0xff; + if ((dev->last_cmd & 0xf0) != 0x40) { + dev->last_cmd = 0xff; } errstus = 0x02; workrequ->result = errstus; goto go_42; } - if (i == 0x16) - { - if ((dev->last_cmd & 0xf0) != 0x40) - { - dev->last_cmd = 0xff; + if (i == 0x16) { + if ((dev->last_cmd & 0xf0) != 0x40) { + dev->last_cmd = 0xff; } errstus = 0; tmport -= 0x08; @@ -433,42 +386,43 @@ workrequ->result = errstus; go_42: /* - * Complete the command + * Complete the command */ - spin_lock_irqsave(workrequ->host->host_lock, flags); + + if(workrequ->use_sg) + pci_unmap_sg(dev->pdev, (struct scatterlist *)workrequ->buffer, workrequ->use_sg, scsi_to_pci_dma_dir(workrequ->sc_data_direction)); + else if(workrequ->request_bufflen && workrequ->sc_data_direction != SCSI_DATA_NONE) + pci_unmap_single(dev->pdev, workrequ->SCp.dma_handle, workrequ->request_bufflen, scsi_to_pci_dma_dir(workrequ->sc_data_direction)); + spin_lock_irqsave(dev->host->host_lock, flags); (*workrequ->scsi_done) (workrequ); /* - * Clear it off the queue + * Clear it off the queue */ dev->id[target_id].curr_req = 0; dev->working--; - spin_unlock_irqrestore(workrequ->host->host_lock, flags); + spin_unlock_irqrestore(dev->host->host_lock, flags); /* - * Take it back wide + * Take it back wide */ if (dev->wide_idu != 0) { tmport = workportu + 0x1b; - outb(0x01,tmport); - while ((inb(tmport) & 0x01) != 0x01) - { - outb(0x01,tmport); + outb(0x01, tmport); + while ((inb(tmport) & 0x01) != 0x01) { + outb(0x01, tmport); } } /* - * If there is stuff to send and nothing going then send it + * If there is stuff to send and nothing going then send it */ - if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && - (dev->in_snd == 0)) - { - send_s870(h); + if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && (dev->in_snd == 0)) { + send_s870(host); } dev->in_int = 0; return; } - if ((dev->last_cmd & 0xf0) != 0x40) - { - dev->last_cmd = 0xff; + if ((dev->last_cmd & 0xf0) != 0x40) { + dev->last_cmd = 0xff; } if (i == 0x4f) { i = 0x89; @@ -524,40 +478,36 @@ dev->in_int = 0; return; } else { -// tmport = workportu + 0x17; -// inb(tmport); -// dev->working = 0; +// tmport = workportu + 0x17; +// inb(tmport); +// dev->working = 0; dev->in_int = 0; return; } } -int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *)) +static int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *)) { - unsigned char h; unsigned long flags; unsigned short int m; unsigned int tmport; + struct Scsi_Host *host; struct atp_unit *dev; - for (h = 0; h <= admaxu; h++) { - if (req_p->host == atp_host[h]) { - goto host_ok; - } - } - return 0; -host_ok: if (req_p->channel != 0) { req_p->result = 0x00040000; done(req_p); return 0; - } - dev = &atp_unit[h]; + }; + + host = req_p->host; + dev = (struct atp_unit *)&host->hostdata; + m = 1; m = m << req_p->target; /* - * Fake a timeout for missing targets + * Fake a timeout for missing targets */ if ((m & dev->active_idu) == 0) { @@ -574,16 +524,16 @@ return 0; } /* - * Count new command + * Count new command */ - save_flags(flags); - cli(); + + spin_lock_irqsave(host->host_lock, flags); dev->quendu++; if (dev->quendu >= qcnt) { dev->quendu = 0; } /* - * Check queue state + * Check queue state */ if (dev->quhdu == dev->quendu) { if (dev->quendu == 0) { @@ -591,28 +541,20 @@ } dev->quendu--; req_p->result = 0x00020000; + spin_unlock_irqrestore(host->host_lock, flags); done(req_p); - restore_flags(flags); return 0; } dev->querequ[dev->quendu] = req_p; tmport = dev->ioport + 0x1c; - restore_flags(flags); + spin_unlock_irqrestore(host->host_lock, flags); if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) { - send_s870(h); + send_s870(host); } return 0; } -void mydlyu(unsigned int dlycnt) -{ - unsigned int i; - for (i = 0; i < dlycnt; i++) { - inb(0x80); - } -} - -void send_s870(unsigned char h) +static void send_s870(struct Scsi_Host *host) { unsigned int tmport; Scsi_Cmnd *workrequ; @@ -621,38 +563,37 @@ unsigned char j, target_id; unsigned char *prd; unsigned short int tmpcip, w; - unsigned long l, bttl; + unsigned long l; + dma_addr_t bttl; unsigned int workportu; struct scatterlist *sgpnt; - struct atp_unit *dev = &atp_unit[h]; + struct atp_unit *dev = (struct atp_unit *)&host->hostdata; + int sg_count; - save_flags(flags); - cli(); + spin_lock_irqsave(host->host_lock, flags); + if (dev->in_snd != 0) { - restore_flags(flags); + spin_unlock_irqrestore(host->host_lock, flags); return; } dev->in_snd = 1; if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) { dev->last_cmd &= 0x0f; workrequ = dev->id[dev->last_cmd].curr_req; - if (workrequ != NULL) /* check NULL pointer */ - { - goto cmd_subp; + if (workrequ != NULL) { /* check NULL pointer */ + goto cmd_subp; } dev->last_cmd = 0xff; - if (dev->quhdu == dev->quendu) - { - dev->in_snd = 0; - restore_flags(flags); - return ; + if (dev->quhdu == dev->quendu) { + dev->in_snd = 0; + spin_unlock_irqrestore(dev->host->host_lock, flags); + return; } } - if ((dev->last_cmd != 0xff) && (dev->working != 0)) - { - dev->in_snd = 0; - restore_flags(flags); - return ; + if ((dev->last_cmd != 0xff) && (dev->working != 0)) { + dev->in_snd = 0; + spin_unlock_irqrestore(dev->host->host_lock, flags); + return; } dev->working++; j = dev->quhdu; @@ -669,7 +610,7 @@ dev->quhdu = j; dev->working--; dev->in_snd = 0; - restore_flags(flags); + spin_unlock_irqrestore(host->host_lock, flags); return; cmd_subp: workportu = dev->ioport; @@ -684,7 +625,7 @@ abortsnd: dev->last_cmd |= 0x40; dev->in_snd = 0; - restore_flags(flags); + spin_unlock_irqrestore(dev->host->host_lock, flags); return; oktosend: memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len); @@ -702,7 +643,7 @@ target_id = workrequ->target; /* - * Wide ? + * Wide ? */ w = 1; w = w << target_id; @@ -710,13 +651,12 @@ j |= 0x01; } outb(j, tmport); - while ((inb(tmport) & 0x01) != j) - { - outb(j,tmport); + while ((inb(tmport) & 0x01) != j) { + outb(j, tmport); } /* - * Write the command + * Write the command */ tmport = workportu; @@ -730,30 +670,30 @@ outb(workrequ->lun, tmport); tmport += 0x02; /* - * Write the target + * Write the target */ outb(dev->id[target_id].devspu, tmport++); /* - * Figure out the transfer size + * Figure out the transfer size */ - if (workrequ->use_sg) - { + if (workrequ->use_sg) { l = 0; sgpnt = (struct scatterlist *) workrequ->request_buffer; - for (i = 0; i < workrequ->use_sg; i++) - { - if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) - { + sg_count = pci_map_sg(dev->pdev, sgpnt, workrequ->use_sg, scsi_to_pci_dma_dir(workrequ->sc_data_direction)); + for (i = 0; i < workrequ->use_sg; i++) { + if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) { panic("Foooooooood fight!"); } l += sgpnt[i].length; } - } else { + } else if(workrequ->request_bufflen && workrequ->sc_data_direction != PCI_DMA_NONE) { + workrequ->SCp.dma_handle = pci_map_single(dev->pdev, workrequ->request_buffer, workrequ->request_bufflen, scsi_to_pci_dma_dir(workrequ->sc_data_direction)); l = workrequ->request_bufflen; } + else l = 0; /* - * Write transfer size + * Write transfer size */ outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++); outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++); @@ -762,21 +702,20 @@ dev->id[j].last_lenu = l; dev->id[j].tran_lenu = 0; /* - * Flip the wide bits + * Flip the wide bits */ if ((j & 0x08) != 0) { j = (j & 0x07) | 0x40; } /* - * Check transfer direction + * Check transfer direction */ - if ((dev->ata_cdbu[0] == WRITE_6) || (dev->ata_cdbu[0] == WRITE_10) || - (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) { + if (workrequ->sc_data_direction == SCSI_DATA_WRITE) { outb((unsigned char) (j | 0x20), tmport++); } else { outb(j, tmport++); } - outb((unsigned char)(inb(tmport) | 0x80),tmport); + outb((unsigned char) (inb(tmport) | 0x80), tmport); outb(0x80, tmport); tmport = workportu + 0x1c; dev->id[target_id].dirctu = 0; @@ -788,7 +727,7 @@ dev->last_cmd |= 0x40; } dev->in_snd = 0; - restore_flags(flags); + spin_unlock_irqrestore(host->host_lock, flags); return; } tmpcip = dev->pciport; @@ -796,79 +735,75 @@ dev->id[target_id].prd_posu = prd; /* - * Now write the request list. Either as scatter/gather or as - * a linear chain. + * Now write the request list. Either as scatter/gather or as + * a linear chain. */ - if (workrequ->use_sg) - { + if (workrequ->use_sg) { sgpnt = (struct scatterlist *) workrequ->request_buffer; i = 0; for (j = 0; j < workrequ->use_sg; j++) { - (unsigned long) (((unsigned long *) (prd))[i >> 1]) = virt_to_bus(sgpnt[j].address); - (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = sgpnt[j].length; - (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0; + bttl = sg_dma_address(&sgpnt[j]); + l = sg_dma_len(&sgpnt[j]); + while (l > 0x10000) { + (u16) (((u16 *) (prd))[i + 3]) = 0x0000; + (u16) (((u16 *) (prd))[i + 2]) = 0x0000; + (u32) (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); + l -= 0x10000; + bttl += 0x10000; + i += 0x04; + } + (u32) (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); + (u16) (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); + (u16) (((u16 *) (prd))[i + 3]) = 0; i += 0x04; } - (unsigned short int) (((unsigned short int *) (prd))[i - 1]) = 0x8000; + (u16) (((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000); } else { /* - * For a linear request write a chain of blocks + * For a linear request write a chain of blocks */ - bttl = virt_to_bus(workrequ->request_buffer); + bttl = workrequ->SCp.dma_handle; l = workrequ->request_bufflen; i = 0; while (l > 0x10000) { - (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x0000; - (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = 0x0000; - (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl; + (u16) (((u16 *) (prd))[i + 3]) = 0x0000; + (u16) (((u16 *) (prd))[i + 2]) = 0x0000; + (u32) (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); l -= 0x10000; bttl += 0x10000; i += 0x04; } - (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x8000; - (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = l; - (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl; + (u16) (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000); + (u16) (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); + (u32) (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); } tmpcip = tmpcip + 4; - dev->id[target_id].prdaddru = virt_to_bus(dev->id[target_id].prd_tableu); - outl(dev->id[target_id].prdaddru, tmpcip); + dev->id[target_id].prdaddru = dev->id[target_id].prd_phys; + outl(dev->id[target_id].prd_phys, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip = tmpcip - 2; - if (dev->deviceid != 0x8081) - { - tmport = workportu + 0x3a; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || - (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) - { - outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); - } - else - { - outb((unsigned char)(inb(tmport) & 0xf3),tmport); - } - } - else - { - tmport = workportu - 0x05; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || - (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) - { - outb((unsigned char)((inb(tmport) & 0x3f) | 0xc0),tmport); - } - else - { - outb((unsigned char)(inb(tmport) & 0x3f),tmport); - } + if (dev->deviceid != 0x8081) { + tmport = workportu + 0x3a; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { + outb((inb(tmport) & 0xf3) | 0x08, tmport); + } else { + outb(inb(tmport) & 0xf3, tmport); + } + } else { + tmport = workportu - 0x05; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { + outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); + } else { + outb((unsigned char) (inb(tmport) & 0x3f), tmport); + } } tmport = workportu + 0x1c; - if ((dev->ata_cdbu[0] == WRITE_6) || (dev->ata_cdbu[0] == WRITE_10) || - (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) - { + if (workrequ->sc_data_direction == SCSI_DATA_WRITE) { dev->id[target_id].dirctu = 0x20; if (inb(tmport) == 0) { tmport = workportu + 0x18; @@ -878,11 +813,10 @@ dev->last_cmd |= 0x40; } dev->in_snd = 0; - restore_flags(flags); + spin_unlock_irqrestore(host->host_lock, flags); return; } - if (inb(tmport) == 0) - { + if (inb(tmport) == 0) { tmport = workportu + 0x18; outb(0x08, tmport); outb(0x09, tmpcip); @@ -890,7 +824,7 @@ dev->last_cmd |= 0x40; } dev->in_snd = 0; - restore_flags(flags); + spin_unlock_irqrestore(host->host_lock, flags); return; } @@ -900,18 +834,21 @@ SCpnt->SCp.Status++; } -int atp870u_command(Scsi_Cmnd * SCpnt) +static int atp870u_command(Scsi_Cmnd * SCpnt) { atp870u_queuecommand(SCpnt, internal_done); SCpnt->SCp.Status = 0; while (!SCpnt->SCp.Status) + { + cpu_relax(); barrier(); + } return SCpnt->result; } -unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val) +static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val) { unsigned int tmport; unsigned short int i, k; @@ -927,22 +864,22 @@ goto FUN_D7; } } - *val |= 0x4000; /* assert DB6 */ + *val |= 0x4000; /* assert DB6 */ outw(*val, tmport); - *val &= 0xdfff; /* assert DB5 */ + *val &= 0xdfff; /* assert DB5 */ outw(*val, tmport); FUN_D5: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ - if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ + if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ goto FUN_D5; } } - *val |= 0x8000; /* no DB4-0, assert DB7 */ + *val |= 0x8000; /* no DB4-0, assert DB7 */ *val &= 0xe0ff; outw(*val, tmport); - *val &= 0xbfff; /* release DB6 */ + *val &= 0xbfff; /* release DB6 */ outw(*val, tmport); - FUN_D6: +FUN_D6: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */ goto FUN_D6; @@ -952,7 +889,7 @@ return j; } -void tscam(unsigned char host) +static void tscam(struct Scsi_Host *host) { unsigned int tmport; @@ -960,14 +897,14 @@ unsigned long n; unsigned short int m, assignid_map, val; unsigned char mbuf[33], quintet[2]; - struct atp_unit *dev = &atp_unit[host]; + struct atp_unit *dev = (struct atp_unit *)host->hostdata; static unsigned char g2q_tab[8] = { 0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27 }; for (i = 0; i < 0x10; i++) { - mydlyu(0xffff); + udelay(0xffff); } tmport = dev->ioport + 1; @@ -1046,18 +983,18 @@ outb(0, 0x80); - val = 0x0080; /* bsy */ + val = 0x0080; /* bsy */ tmport = dev->ioport + 0x1c; outw(val, tmport); - val |= 0x0040; /* sel */ + val |= 0x0040; /* sel */ outw(val, tmport); - val |= 0x0004; /* msg */ + val |= 0x0004; /* msg */ outw(val, tmport); inb(0x80); /* 2 deskew delay(45ns*2=90ns) */ val &= 0x007f; /* no bsy */ outw(val, tmport); - mydlyu(0xffff); /* recommanded SCAM selection response time */ - mydlyu(0xffff); + udelay(0xffff); /* recommanded SCAM selection response time */ + udelay(0xffff); val &= 0x00fb; /* after 1ms no msg */ outw(val, tmport); wait_nomsg: @@ -1065,7 +1002,7 @@ goto wait_nomsg; } outb(1, 0x80); - mydlyu(100); + udelay(100); for (n = 0; n < 0x30000; n++) { if ((inb(tmport) & 0x80) != 0) { /* bsy ? */ goto wait_io; @@ -1088,7 +1025,7 @@ outw(val, tmport); outb(2, 0x80); TCM_SYNC: - mydlyu(0x800); + udelay(0x800); if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */ outw(0, tmport--); outb(0, tmport); @@ -1106,7 +1043,7 @@ val |= 0x3f00; fun_scam(dev, &val); outb(3, 0x80); - val &= 0x00ff; /* isolation */ + val &= 0x00ff; /* isolation */ val |= 0x2000; fun_scam(dev, &val); outb(4, 0x80); @@ -1141,10 +1078,10 @@ printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */ i = 15; j = mbuf[0]; - if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */ + if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */ i = 7; } - if ((j & 0x06) == 0) { /* IDvalid? */ + if ((j & 0x06) == 0) { /* IDvalid? */ goto G2Q5; } k = mbuf[1]; @@ -1158,8 +1095,8 @@ k--; goto small_id; } -G2Q5: /* srch from max acceptable ID# */ - k = i; /* max acceptable ID# */ +G2Q5: /* srch from max acceptable ID# */ + k = i; /* max acceptable ID# */ G2Q_LP: m = 1; m <<= k; @@ -1170,12 +1107,12 @@ k--; goto G2Q_LP; } -G2Q_QUIN: /* k=binID#, */ +G2Q_QUIN: /* k=binID#, */ assignid_map |= m; if (k < 8) { quintet[0] = 0x38; /* 1st dft ID<8 */ } else { - quintet[0] = 0x31; /* 1st ID>=8 */ + quintet[0] = 0x31; /* 1st ID>=8 */ } k &= 0x07; quintet[1] = g2q_tab[k]; @@ -1193,19 +1130,19 @@ } -void is870(unsigned long host, unsigned int wkport) +void is870(struct Scsi_Host *host, unsigned int wkport) { unsigned int tmport; unsigned char i, j, k, rmb, n; unsigned short int m; static unsigned char mbuf[512]; - static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; - static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; - static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; - static unsigned char synu[6] = {0x80, 1, 3, 1, 0x0c, 0x0e}; - static unsigned char synw[6] = {0x80, 1, 3, 1, 0x0c, 0x07}; - static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; - struct atp_unit *dev = &atp_unit[host]; + static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 }; + static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 }; + static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e }; + static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e }; + static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 }; + static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 }; + struct atp_unit *dev = (struct atp_unit *)&host->hostdata; sync_idu = 0; tmport = wkport + 0x3a; @@ -1226,11 +1163,9 @@ } tmport = wkport + 0x1b; if (dev->chip_veru == 4) { - outb(0x01, tmport); - } - else - { - outb(0x00, tmport); + outb(0x01, tmport); + } else { + outb(0x00, tmport); } tmport = wkport + 1; outb(0x08, tmport++); @@ -1499,9 +1434,7 @@ m = m << i; dev->wide_idu |= m; not_wide: - if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || - ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) - { + if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) { goto set_sync; } continue; @@ -1682,31 +1615,31 @@ goto set_syn_ok; } j = 0x60; - set_syn_ok: +set_syn_ok: dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j; } tmport = wkport + 0x3a; outb((unsigned char) (inb(tmport) & 0xef), tmport); } -void is880(unsigned long host, unsigned int wkport) +static void is880(struct Scsi_Host *host, unsigned int wkport) { unsigned int tmport; unsigned char i, j, k, rmb, n, lvdmode; unsigned short int m; static unsigned char mbuf[512]; - static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; - static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; - static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; - unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; - static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; - unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; - static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; - static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 }; - struct atp_unit *dev = &atp_unit[host]; + static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 }; + static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 }; + static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e }; + unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e }; + static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e }; + unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e }; + static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 }; + static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 }; + struct atp_unit *dev = (struct atp_unit *)&host->hostdata; sync_idu = 0; - lvdmode=inb(wkport + 0x3f) & 0x40; + lvdmode = inb(wkport + 0x3f) & 0x40; for (i = 0; i < 16; i++) { m = 1; @@ -1842,13 +1775,12 @@ if ((i < 8) && ((dev->global_map & 0x20) == 0)) { goto not_wide; } - if (lvdmode == 0) - { - goto chg_wide; + if (lvdmode == 0) { + goto chg_wide; } - if (dev->sp[i] != 0x04) // force u2 + if (dev->sp[i] != 0x04) // force u2 { - goto chg_wide; + goto chg_wide; } tmport = wkport + 0x5b; @@ -1985,11 +1917,11 @@ goto chg_wide; } if (mbuf[3] == 0x09) { - m = 1; - m = m << i; - dev->wide_idu |= m; - dev->id[i].devspu = 0xce; - continue; + m = 1; + m = m << i; + dev->wide_idu |= m; + dev->id[i].devspu = 0xce; + continue; } chg_wide: tmport = wkport + 0x5b; @@ -2132,30 +2064,23 @@ m = m << i; dev->wide_idu |= m; not_wide: - if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || - ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) - { + if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) { m = 1; m = m << i; - if ((dev->async & m) != 0) - { - goto set_sync; + if ((dev->async & m) != 0) { + goto set_sync; } } continue; set_sync: - if (dev->sp[i] == 0x02) - { - synu[4]=0x0c; - synuw[4]=0x0c; - } - else - { - if (dev->sp[i] >= 0x03) - { - synu[4]=0x0a; - synuw[4]=0x0a; - } + if (dev->sp[i] == 0x02) { + synu[4] = 0x0c; + synuw[4] = 0x0c; + } else { + if (dev->sp[i] >= 0x03) { + synu[4] = 0x0a; + synuw[4] = 0x0a; + } } tmport = wkport + 0x5b; j = 0; @@ -2320,7 +2245,7 @@ mbuf[4] = 0x0e; } dev->id[i].devspu = mbuf[4]; - if (mbuf[3] < 0x0c){ + if (mbuf[3] < 0x0c) { j = 0xb0; goto set_syn_ok; } @@ -2341,101 +2266,102 @@ goto set_syn_ok; } j = 0x60; - set_syn_ok: +set_syn_ok: dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j; } } + +static void atp870u_init_tables(struct Scsi_Host *host) +{ + struct atp_unit *dev = (struct atp_unit *)&host->hostdata; + int k; + + for (k = 0; k < 16; k++) { + /* FIXME */ + dev->id[k].prd_tableu = pci_alloc_consistent(dev->pdev, 1024, &dev->id[k].prd_phys); + dev->id[k].devspu = 0x20; + dev->id[k].devtypeu = 0; + dev->id[k].curr_req = NULL; + } + dev->active_idu = 0; + dev->wide_idu = 0; + dev->host_idu = 0x07; + dev->quhdu = 0; + dev->quendu = 0; + dev->chip_veru = 0; + dev->last_cmd = 0xff; + dev->in_snd = 0; + dev->in_int = 0; + for (k = 0; k < qcnt; k++) { + dev->querequ[k] = 0; + } + for (k = 0; k < 16; k++) { + dev->id[k].curr_req = 0; + dev->sp[k] = 0x04; + } +} + /* return non-zero on detection */ -int atp870u_detect(Scsi_Host_Template * tpnt) +static int atp870u_detect(Scsi_Host_Template * tpnt) { unsigned char irq, h, k, m; unsigned long flags; unsigned int base_io, error, tmport; - unsigned short index = 0; - struct pci_dev *pdev[3]; - unsigned char chip_ver[3], host_id; - unsigned short dev_id[3], n; + struct pci_dev *pdev[MAX_ATP]; + unsigned char chip_ver[MAX_ATP], host_id; + unsigned short dev_id[MAX_ATP], n; struct Scsi_Host *shpnt = NULL; - int tmpcnt = 0; + int card = 0; int count = 0; static unsigned short devid[9] = { - 0x8081, 0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0x8060, 0 + 0x8081, 0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0x8060, 0 }; printk(KERN_INFO "aec671x_detect: \n"); if (!pci_present()) { - printk(KERN_INFO" NO PCI SUPPORT.\n"); + printk(KERN_INFO " NO PCI SUPPORT.\n"); return count; } tpnt->proc_name = "atp870u"; - for (h = 0; h < 2; h++) { - struct atp_unit *dev = &atp_unit[h]; - for(k=0;k<16;k++) - { - dev->id[k].prd_tableu = kmalloc(1024, GFP_KERNEL); - dev->id[k].devspu=0x20; - dev->id[k].devtypeu = 0; - dev->id[k].curr_req = NULL; - } - dev->active_idu = 0; - dev->wide_idu = 0; - dev->host_idu = 0x07; - dev->quhdu = 0; - dev->quendu = 0; - pdev[h]=NULL; - pdev[2]=NULL; - dev->chip_veru = 0; - dev->last_cmd = 0xff; - dev->in_snd = 0; - dev->in_int = 0; - for (k = 0; k < qcnt; k++) { - dev->querequ[k] = 0; - } - for (k = 0; k < 16; k++) { - dev->id[k].curr_req = 0; - dev->sp[k] = 0x04; - } - } h = 0; - while (devid[h] != 0) { - pdev[2] = pci_find_device(0x1191, devid[h], pdev[2]); - if (pdev[2] == NULL || pci_enable_device(pdev[2])) { - h++; - index = 0; - continue; - } - chip_ver[2] = 0; - dev_id[2] = devid[h]; + while (devid[h] != 0) + { + struct pci_dev *dev = NULL; + + while((dev = pci_find_device(0x1191, devid[h], dev))!=NULL) + { + if(pci_enable_device(dev)) + continue; - if (devid[h] == 0x8002) { - error = pci_read_config_byte(pdev[2], 0x08, &chip_ver[2]); - if (chip_ver[2] < 2) { - goto nxt_devfn; + if(pci_set_dma_mask(dev, 0xFFFFFFFFUL)) + { + printk(KERN_ERR "atp870u: 32bit DMA mask required but not available.\n"); + continue; } + chip_ver[card] = 0; + dev_id[card] = devid[h]; + + if (devid[h] == 0x8002) { + error = pci_read_config_byte(dev, 0x08, &chip_ver[card]); + if (chip_ver[card] < 2) { + continue; + } + } + if (devid[h] == 0x8010 || devid[h] == 0x8081 || devid[h] == 0x8050) { + chip_ver[card] = 0x04; + } + pdev[card] = dev; + card++; + if (card == MAX_ATP) + break; } - if (devid[h] == 0x8010 || devid[h] == 0x8081 || devid[h] == 0x8050) - { - chip_ver[2] = 0x04; - } - pdev[tmpcnt] = pdev[2]; - chip_ver[tmpcnt] = chip_ver[2]; - dev_id[tmpcnt] = dev_id[2]; - tmpcnt++; - nxt_devfn: - index++; - if (index > 3) { - index = 0; - h++; - } - if(tmpcnt>1) - break; } - for (h = 0; h < 2; h++) { - struct atp_unit *dev=&atp_unit[h]; - if (pdev[h]==NULL) { + for (h = 0; h < MAX_ATP; h++) { + struct atp_unit tmp, *dev; + if (pdev[h] == NULL) { return count; } @@ -2443,211 +2369,205 @@ base_io = pci_resource_start(pdev[h], 0); irq = pdev[h]->irq; - if (dev_id[h] != 0x8081) - { - error = pci_read_config_byte(pdev[h],0x49,&host_id); + if (dev_id[h] != 0x8081) { + error = pci_read_config_byte(pdev[h], 0x49, &host_id); - base_io &= 0xfffffff8; + base_io &= 0xfffffff8; - if (check_region(base_io,0x40) != 0) - { - return 0; - } - printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n" - ,h, base_io, irq); - dev->ioport = base_io; - dev->pciport = base_io + 0x20; - dev->deviceid = dev_id[h]; - irqnumu[h] = irq; - host_id &= 0x07; - dev->host_idu = host_id; - dev->chip_veru = chip_ver[h]; - - tmport = base_io + 0x22; - dev->scam_on = inb(tmport); - tmport += 0x0b; - dev->global_map = inb(tmport++); - dev->ultra_map = inw(tmport); - if (dev->ultra_map == 0) { - dev->scam_on = 0x00; - dev->global_map = 0x20; - dev->ultra_map = 0xffff; - } - shpnt = scsi_register(tpnt, 4); - if(shpnt==NULL) - return count; - - save_flags(flags); - cli(); - if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", dev)) { - printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); - goto unregister; - } - - if (chip_ver[h] > 0x07) /* check if atp876 chip */ - { /* then enable terminator */ - tmport = base_io + 0x3e; - outb(0x00, tmport); - } - - tmport = base_io + 0x3a; - k = (inb(tmport) & 0xf3) | 0x10; - outb(k, tmport); - outb((k & 0xdf), tmport); - mydlyu(0x8000); - outb(k, tmport); - mydlyu(0x8000); - tmport = base_io; - outb((host_id | 0x08), tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0); - tmport -= 0x08; - inb(tmport); - tmport = base_io + 1; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x11; - outb(0x20, tmport); - - tscam(h); - is870(h, base_io); - tmport = base_io + 0x3a; - outb((inb(tmport) & 0xef), tmport); - tmport++; - outb((inb(tmport) | 0x20),tmport); - } - else - { - base_io &= 0xfffffff8; + if (check_region(base_io, 0x40) != 0) { + return 0; + } + printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n", h, base_io, irq); + + tmp.ioport = base_io; + tmp.pciport = base_io + 0x20; + tmp.deviceid = dev_id[h]; + host_id &= 0x07; + tmp.host_idu = host_id; + tmp.chip_veru = chip_ver[h]; + + tmport = base_io + 0x22; + tmp.scam_on = inb(tmport); + tmport += 0x0b; + tmp.global_map = inb(tmport++); + tmp.ultra_map = inw(tmport); + if (tmp.ultra_map == 0) { + tmp.scam_on = 0x00; + tmp.global_map = 0x20; + tmp.ultra_map = 0xffff; + } + shpnt = scsi_register(tpnt, sizeof(struct atp_unit)); + if (shpnt == NULL) + return count; + tmp.host = shpnt; + tmp.pdev = pdev[h]; + /* Save the atp_unit data */ + memcpy(&shpnt->hostdata, &tmp, sizeof(tmp)); + + atp870u_init_tables(shpnt); + spin_lock_irqsave(shpnt->host_lock, flags); + if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) { + printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); + goto unregister; + } - if (check_region(base_io,0x60) != 0) - { - return 0; - } - host_id = inb(base_io + 0x39); - host_id >>= 0x04; - - printk(KERN_INFO " ACARD AEC-67160 PCI Ultra160 LVD/SE SCSI Adapter: %d IO:%x, IRQ:%d.\n" - ,h, base_io, irq); - dev->ioport = base_io + 0x40; - dev->pciport = base_io + 0x28; - dev->deviceid = dev_id[h]; - irqnumu[h] = irq; - dev->host_idu = host_id; - dev->chip_veru = chip_ver[h]; - - tmport = base_io + 0x22; - dev->scam_on = inb(tmport); - tmport += 0x13; - dev->global_map = inb(tmport); - tmport += 0x07; - dev->ultra_map = inw(tmport); + if (chip_ver[h] > 0x07) { /* check if atp876 chip *//* then enable terminator */ + tmport = base_io + 0x3e; + outb(0x00, tmport); + } + + tmport = base_io + 0x3a; + k = (inb(tmport) & 0xf3) | 0x10; + outb(k, tmport); + outb((k & 0xdf), tmport); + udelay(0x8000); + outb(k, tmport); + udelay(0x8000); + tmport = base_io; + outb((host_id | 0x08), tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 1; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x11; + outb(0x20, tmport); + + tscam(shpnt); + is870(shpnt, base_io); + tmport = base_io + 0x3a; + outb((inb(tmport) & 0xef), tmport); + tmport++; + outb((inb(tmport) | 0x20), tmport); + } else { + base_io &= 0xfffffff8; + + if (check_region(base_io, 0x60) != 0) { + return 0; + } + host_id = inb(base_io + 0x39); + host_id >>= 0x04; + + printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d IO:%x, IRQ:%d.\n", h, base_io, irq); + tmp.ioport = base_io + 0x40; + tmp.pciport = base_io + 0x28; + tmp.deviceid = dev_id[h]; + tmp.host_idu = host_id; + tmp.chip_veru = chip_ver[h]; + + tmport = base_io + 0x22; + tmp.scam_on = inb(tmport); + tmport += 0x13; + tmp.global_map = inb(tmport); + tmport += 0x07; + tmp.ultra_map = inw(tmport); - n=0x3f09; + n = 0x3f09; next_fblk: - if (n >= 0x4000) - { - goto flash_ok; - } - m=0; - outw(n,base_io + 0x34); - n += 0x0002; - if (inb(base_io + 0x30) == 0xff) - { - goto flash_ok; - } - dev->sp[m++]=inb(base_io + 0x30); - dev->sp[m++]=inb(base_io + 0x31); - dev->sp[m++]=inb(base_io + 0x32); - dev->sp[m++]=inb(base_io + 0x33); - outw(n,base_io + 0x34); - n += 0x0002; - dev->sp[m++]=inb(base_io + 0x30); - dev->sp[m++]=inb(base_io + 0x31); - dev->sp[m++]=inb(base_io + 0x32); - dev->sp[m++]=inb(base_io + 0x33); - outw(n,base_io + 0x34); - n += 0x0002; - dev->sp[m++]=inb(base_io + 0x30); - dev->sp[m++]=inb(base_io + 0x31); - dev->sp[m++]=inb(base_io + 0x32); - dev->sp[m++]=inb(base_io + 0x33); - outw(n,base_io + 0x34); - n += 0x0002; - dev->sp[m++]=inb(base_io + 0x30); - dev->sp[m++]=inb(base_io + 0x31); - dev->sp[m++]=inb(base_io + 0x32); - dev->sp[m++]=inb(base_io + 0x33); - n += 0x0018; - goto next_fblk; + if (n >= 0x4000) { + goto flash_ok; + } + m = 0; + outw(n, base_io + 0x34); + n += 0x0002; + if (inb(base_io + 0x30) == 0xff) { + goto flash_ok; + } + tmp.sp[m++] = inb(base_io + 0x30); + tmp.sp[m++] = inb(base_io + 0x31); + tmp.sp[m++] = inb(base_io + 0x32); + tmp.sp[m++] = inb(base_io + 0x33); + outw(n, base_io + 0x34); + n += 0x0002; + tmp.sp[m++] = inb(base_io + 0x30); + tmp.sp[m++] = inb(base_io + 0x31); + tmp.sp[m++] = inb(base_io + 0x32); + tmp.sp[m++] = inb(base_io + 0x33); + outw(n, base_io + 0x34); + n += 0x0002; + tmp.sp[m++] = inb(base_io + 0x30); + tmp.sp[m++] = inb(base_io + 0x31); + tmp.sp[m++] = inb(base_io + 0x32); + tmp.sp[m++] = inb(base_io + 0x33); + outw(n, base_io + 0x34); + n += 0x0002; + tmp.sp[m++] = inb(base_io + 0x30); + tmp.sp[m++] = inb(base_io + 0x31); + tmp.sp[m++] = inb(base_io + 0x32); + tmp.sp[m++] = inb(base_io + 0x33); + n += 0x0018; + goto next_fblk; flash_ok: - outw(0,base_io + 0x34); - dev->ultra_map=0; - dev->async = 0; - for (k=0; k < 16; k++) - { - n=1; - n = n << k; - if (dev->sp[k] > 1) - { - dev->ultra_map |= n; - } - else - { - if (dev->sp[k] == 0) - { - dev->async |= n; - } - } - } - dev->async = ~(dev->async); - outb(dev->global_map,base_io + 0x35); - - shpnt = scsi_register(tpnt, 4); - if(shpnt==NULL) - return count; - - save_flags(flags); - cli(); - if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", dev)) { - printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); - goto unregister; - } - - tmport = base_io + 0x38; - k = inb(tmport) & 0x80; - outb(k, tmport); - tmport += 0x03; - outb(0x20, tmport); - mydlyu(0x8000); - outb(0, tmport); - mydlyu(0x8000); - tmport = base_io + 0x5b; - inb(tmport); - tmport -= 0x04; - inb(tmport); - tmport = base_io + 0x40; - outb((host_id | 0x08), tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0); - tmport -= 0x08; - inb(tmport); - tmport = base_io + 0x41; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x51; - outb(0x20, tmport); - - tscam(h); - is880(h, base_io); - tmport = base_io + 0x38; - outb(0xb0, tmport); + outw(0, base_io + 0x34); + tmp.ultra_map = 0; + tmp.async = 0; + for (k = 0; k < 16; k++) { + n = 1; + n = n << k; + if (tmp.sp[k] > 1) { + tmp.ultra_map |= n; + } else { + if (tmp.sp[k] == 0) { + tmp.async |= n; + } + } + } + tmp.async = ~(tmp.async); + outb(tmp.global_map, base_io + 0x35); + + shpnt = scsi_register(tpnt, sizeof(struct atp_unit)); + if (shpnt == NULL) + return count; + + tmp.pdev = pdev[h]; + memcpy(&shpnt->hostdata, &tmp, sizeof(tmp)); + + atp870u_init_tables(shpnt); + + spin_lock_irqsave(shpnt->host_lock, flags); + if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) { + printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); + goto unregister; + } + + tmport = base_io + 0x38; + k = inb(tmport) & 0x80; + outb(k, tmport); + tmport += 0x03; + outb(0x20, tmport); + udelay(0x8000); + outb(0, tmport); + udelay(0x8000); + tmport = base_io + 0x5b; + inb(tmport); + tmport -= 0x04; + inb(tmport); + tmport = base_io + 0x40; + outb((host_id | 0x08), tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 0x41; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x51; + outb(0x20, tmport); + + tscam(shpnt); + is880(shpnt, base_io); + tmport = base_io + 0x38; + outb(0xb0, tmport); } + dev = (struct atp_unit *)&shpnt->hostdata; + atp_host[h] = shpnt; if (dev->chip_veru == 4) { shpnt->max_id = 16; @@ -2655,31 +2575,23 @@ shpnt->this_id = host_id; shpnt->unique_id = base_io; shpnt->io_port = base_io; - if (dev_id[h] == 0x8081) - { - shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */ - } - else - { - shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ + if (dev_id[h] == 0x8081) { + shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */ + } else { + shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ } shpnt->irq = irq; restore_flags(flags); - if (dev_id[h] == 0x8081) - { - request_region(base_io, 0x60, "atp870u"); /* Register the IO ports that we use */ - } - else - { - request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ + if (dev_id[h] == 0x8081) { + request_region(base_io, 0x60, "atp870u"); /* Register the IO ports that we use */ + } else { + request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ } count++; - index++; continue; unregister: scsi_unregister(shpnt); - restore_flags(flags); - index++; + spin_unlock_irqrestore(shpnt->host_lock, flags); continue; } @@ -2692,18 +2604,11 @@ int atp870u_abort(Scsi_Cmnd * SCpnt) { - unsigned char h, j, k; + unsigned char j, k; Scsi_Cmnd *workrequ; unsigned int tmport; - struct atp_unit *dev; - for (h = 0; h <= admaxu; h++) { - if (SCpnt->host == atp_host[h]) { - goto find_adp; - } - } - panic("Abort host not found !"); -find_adp: - dev=&atp_unit[h]; + struct atp_unit *dev = (struct atp_unit *)&SCpnt->host->hostdata; + printk(KERN_DEBUG "working=%x last_cmd=%x ", dev->working, dev->last_cmd); printk(" quhdu=%x quendu=%x ", dev->quhdu, dev->quendu); tmport = dev->ioport; @@ -2714,71 +2619,44 @@ printk(" r1c=%2x", inb(tmport)); tmport += 0x03; printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd); - tmport= dev->pciport; + tmport = dev->pciport; printk(" r20=%2x", inb(tmport)); tmport += 0x02; printk(" r22=%2x", inb(tmport)); tmport = dev->ioport + 0x3a; - printk(" r3a=%2x \n",inb(tmport)); + printk(" r3a=%2x \n", inb(tmport)); tmport = dev->ioport + 0x3b; - printk(" r3b=%2x \n",inb(tmport)); - for(j=0;j<16;j++) - { - if (dev->id[j].curr_req != NULL) - { - workrequ = dev->id[j].curr_req; - printk("\n que cdb= "); - for (k=0; k < workrequ->cmd_len; k++) - { - printk(" %2x ",workrequ->cmnd[k]); - } - printk(" last_lenu= %lx ",dev->id[j].last_lenu); - } - } - return (SCSI_ABORT_SNOOZE); -} - -int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) -{ - unsigned char h; - struct atp_unit *dev; - /* - * See if a bus reset was suggested. - */ - for (h = 0; h <= admaxu; h++) { - if (SCpnt->host == atp_host[h]) { - goto find_host; + printk(" r3b=%2x \n", inb(tmport)); + for (j = 0; j < 16; j++) { + if (dev->id[j].curr_req != NULL) { + workrequ = dev->id[j].curr_req; + printk("\n que cdb= "); + for (k = 0; k < workrequ->cmd_len; k++) { + printk(" %2x ", workrequ->cmnd[k]); + } + printk(" last_lenu= %lx ", dev->id[j].last_lenu); } } - panic("Reset bus host not found !"); -find_host: - dev=&atp_unit[h]; -/* SCpnt->result = 0x00080000; - SCpnt->scsi_done(SCpnt); - dev->working=0; - dev->quhdu=0; - dev->quendu=0; - return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); */ - return (SCSI_RESET_SNOOZE); + /* Sort of - the thing handles itself */ + return SUCCESS; } const char *atp870u_info(struct Scsi_Host *notused) { static char buffer[128]; - strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.5+ac "); + strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.6+ac "); return buffer; } int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) { - return -ENOSYS; /* Currently this is a no-op */ + return -ENOSYS; /* Currently this is a no-op */ } #define BLS buffer + len + size -int atp870u_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +int atp870u_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct Scsi_Host *HBAptr; static u8 buff[512]; @@ -2789,7 +2667,7 @@ off_t pos = 0; HBAptr = NULL; - for (i = 0; i < 2; i++) { + for (i = 0; i < MAX_ATP; i++) { if ((HBAptr = atp_host[i]) != NULL) { if (HBAptr->host_no == hostno) { break; @@ -2811,7 +2689,7 @@ if (offset == 0) { memset(buff, 0, sizeof(buff)); } - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.5+ac\n"); + size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.6+ac\n"); len += size; pos = begin + len; size = 0; @@ -2835,7 +2713,7 @@ #include "sd.h" -int atp870u_biosparam(Scsi_Disk * disk, struct block_device *dev, int *ip) +static int atp870u_biosparam(Scsi_Disk * disk, struct block_device *dev, int *ip) { int heads, sectors, cylinders; @@ -2856,24 +2734,18 @@ } -int atp870u_release (struct Scsi_Host *pshost) +static int atp870u_release(struct Scsi_Host *pshost) { - int h; - for (h = 0; h <= admaxu; h++) - { - if (pshost == atp_host[h]) { - int k; - free_irq (pshost->irq, &atp_unit[h]); - release_region (pshost->io_port, pshost->n_io_port); - scsi_unregister(pshost); - for(k=0;k<16;k++) - kfree(atp_unit[h].id[k].prd_tableu); - return 0; - } - } - panic("atp870u: bad scsi host passed.\n"); - + struct atp_unit *dev = (struct atp_unit *)&pshost->hostdata; + int k; + free_irq(pshost->irq, pshost); + release_region(pshost->io_port, pshost->n_io_port); + scsi_unregister(pshost); + for (k = 0; k < 16; k++) + pci_free_consistent(dev->pdev, 1024, dev->id[k].prd_tableu, dev->id[k].prd_phys); + return 0; } + MODULE_LICENSE("GPL"); static Scsi_Host_Template driver_template = ATP870U; diff -Nru a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h --- a/drivers/scsi/atp870u.h Fri Jul 26 19:58:50 2002 +++ b/drivers/scsi/atp870u.h Fri Jul 26 19:58:50 2002 @@ -17,14 +17,12 @@ #define MAX_CDB 12 #define MAX_SENSE 14 -int atp870u_detect(Scsi_Host_Template *); -int atp870u_command(Scsi_Cmnd *); -int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int atp870u_abort(Scsi_Cmnd *); -int atp870u_reset(Scsi_Cmnd *, unsigned int); -int atp870u_biosparam(Disk *, struct block_device *, int *); -int atp870u_release(struct Scsi_Host *); -void send_s870(unsigned char); +static int atp870u_detect(Scsi_Host_Template *); +static int atp870u_command(Scsi_Cmnd *); +static int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +static int atp870u_abort(Scsi_Cmnd *); +static int atp870u_biosparam(Disk *, struct block_device *, int *); +static int atp870u_release(struct Scsi_Host *); #define qcnt 32 #define ATP870U_SCATTER 128 @@ -49,12 +47,7 @@ command: atp870u_command, \ queuecommand: atp870u_queuecommand, \ eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: atp870u_abort, \ - reset: atp870u_reset, \ + eh_abort_handler: atp870u_abort, \ slave_attach: NULL, \ bios_param: atp870u_biosparam, \ can_queue: qcnt, /* max simultaneous cmds */\ diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c Fri Jul 26 19:58:50 2002 +++ b/drivers/scsi/cpqfcTSinit.c Fri Jul 26 19:58:50 2002 @@ -475,7 +475,7 @@ { struct request * req; - req = &SCpnt->request; + req = SCpnt->request; req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ if (req->CPQFC_WAITING != NULL) @@ -601,7 +601,7 @@ { CPQFC_DECLARE_COMPLETION(wait); - ScsiPassThruCmnd->request.CPQFC_WAITING = &wait; + ScsiPassThruCmnd->request->CPQFC_WAITING = &wait; // eventually gets us to our own _quecommand routine scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], buf, @@ -611,7 +611,7 @@ // Other I/Os can now resume; we wait for our ioctl // command to complete CPQFC_WAIT_FOR_COMPLETION(&wait); - ScsiPassThruCmnd->request.CPQFC_WAITING = NULL; + ScsiPassThruCmnd->request->CPQFC_WAITING = NULL; } result = ScsiPassThruCmnd->result; @@ -1543,10 +1543,10 @@ SCpnt->SCp.buffers_residual = FCP_TARGET_RESET; - SCpnt->request.CPQFC_WAITING = &wait; + SCpnt->request->CPQFC_WAITING = &wait; scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries); CPQFC_WAIT_FOR_COMPLETION(&wait); - SCpnt->request.CPQFC_WAITING = NULL; + SCpnt->request->CPQFC_WAITING = NULL; } /* diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Fri Jul 26 19:58:51 2002 +++ b/drivers/scsi/scsi_lib.c Fri Jul 26 19:58:51 2002 @@ -51,53 +51,6 @@ */ /* - * Function: __scsi_insert_special() - * - * Purpose: worker for scsi_insert_special_*() - * - * Arguments: q - request queue where request should be inserted - * rq - request to be inserted - * data - private data - * at_head - insert request at head or tail of queue - * - * Lock status: Assumed that queue lock is not held upon entry. - * - * Returns: Nothing - */ -static void __scsi_insert_special(request_queue_t *q, struct request *rq, - void *data, int at_head) -{ - unsigned long flags; - - ASSERT_LOCK(q->queue_lock, 0); - - /* - * tell I/O scheduler that this isn't a regular read/write (ie it - * must not attempt merges on this) and that it acts as a soft - * barrier - */ - rq->flags &= REQ_QUEUED; - rq->flags |= REQ_SPECIAL | REQ_BARRIER; - - rq->special = data; - - /* - * We have the option of inserting the head or the tail of the queue. - * Typically we use the tail for new ioctls and so forth. We use the - * head of the queue for things like a QUEUE_FULL message from a - * device, or a host that is unable to accept a particular command. - */ - spin_lock_irqsave(q->queue_lock, flags); - /* If command is tagged, release the tag */ - if(blk_rq_tagged(rq)) - blk_queue_end_tag(q, rq); - _elv_add_request(q, rq, !at_head, 0); - q->request_fn(q); - spin_unlock_irqrestore(q->queue_lock, flags); -} - - -/* * Function: scsi_insert_special_cmd() * * Purpose: Insert pre-formed command into request queue. @@ -121,7 +74,7 @@ { request_queue_t *q = &SCpnt->device->request_queue; - __scsi_insert_special(q, SCpnt->request, SCpnt, at_head); + blk_insert_request(q, SCpnt->request, at_head, SCpnt); return 0; } @@ -149,7 +102,7 @@ { request_queue_t *q = &SRpnt->sr_device->request_queue; - __scsi_insert_special(q, SRpnt->sr_request, SRpnt, at_head); + blk_insert_request(q, SRpnt->sr_request, at_head, SRpnt); return 0; } diff -Nru a/drivers/serial/21285.c b/drivers/serial/21285.c --- a/drivers/serial/21285.c Fri Jul 26 19:58:51 2002 +++ b/drivers/serial/21285.c Fri Jul 26 19:58:51 2002 @@ -344,33 +344,33 @@ } static struct uart_ops serial21285_ops = { - tx_empty: serial21285_tx_empty, - get_mctrl: serial21285_get_mctrl, - set_mctrl: serial21285_set_mctrl, - stop_tx: serial21285_stop_tx, - start_tx: serial21285_start_tx, - stop_rx: serial21285_stop_rx, - enable_ms: serial21285_enable_ms, - break_ctl: serial21285_break_ctl, - startup: serial21285_startup, - shutdown: serial21285_shutdown, - change_speed: serial21285_change_speed, - type: serial21285_type, - release_port: serial21285_release_port, - request_port: serial21285_request_port, - config_port: serial21285_config_port, - verify_port: serial21285_verify_port, + .tx_empty = serial21285_tx_empty, + .get_mctrl = serial21285_get_mctrl, + .set_mctrl = serial21285_set_mctrl, + .stop_tx = serial21285_stop_tx, + .start_tx = serial21285_start_tx, + .stop_rx = serial21285_stop_rx, + .enable_ms = serial21285_enable_ms, + .break_ctl = serial21285_break_ctl, + .startup = serial21285_startup, + .shutdown = serial21285_shutdown, + .change_speed = serial21285_change_speed, + .type = serial21285_type, + .release_port = serial21285_release_port, + .request_port = serial21285_request_port, + .config_port = serial21285_config_port, + .verify_port = serial21285_verify_port, }; static struct uart_port serial21285_port = { - membase: 0, - mapbase: 0x42000160, - iotype: SERIAL_IO_MEM, - irq: NO_IRQ, - uartclk: 0, - fifosize: 16, - ops: &serial21285_ops, - flags: ASYNC_BOOT_AUTOCONF, + .membase = 0, + .mapbase = 0x42000160, + .iotype = SERIAL_IO_MEM, + .irq = NO_IRQ, + .uartclk = 0, + .fifosize = 16, + .ops = &serial21285_ops, + .flags = ASYNC_BOOT_AUTOCONF, }; static void serial21285_setup_ports(void) @@ -466,23 +466,23 @@ #ifdef CONFIG_SERIAL_21285_OLD static struct console serial21285_old_cons = { - name: SERIAL_21285_OLD_NAME, - write: serial21285_console_write, - device: serial21285_console_device, - setup: serial21285_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = SERIAL_21285_OLD_NAME, + .write = serial21285_console_write, + .device = serial21285_console_device, + .setup = serial21285_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; #endif static struct console serial21285_console = { - name: SERIAL_21285_NAME, - write: serial21285_console_write, - device: serial21285_console_device, - setup: serial21285_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = SERIAL_21285_NAME, + .write = serial21285_console_write, + .device = serial21285_console_device, + .setup = serial21285_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void __init rs285_console_init(void) @@ -497,17 +497,17 @@ #endif static struct uart_driver serial21285_reg = { - owner: THIS_MODULE, - driver_name: "ttyFB", + .owner = THIS_MODULE, + .driver_name = "ttyFB", #ifdef CONFIG_DEVFS_FS - dev_name: "ttyFB%d", + .dev_name = "ttyFB%d", #else - dev_name: "ttyFB", + .dev_name = "ttyFB", #endif - major: SERIAL_21285_MAJOR, - minor: SERIAL_21285_MINOR, - nr: 1, - cons: SERIAL_21285_CONSOLE, + .major = SERIAL_21285_MAJOR, + .minor = SERIAL_21285_MINOR, + .nr = 1, + .cons = SERIAL_21285_CONSOLE, }; static int __init serial21285_init(void) diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c Fri Jul 26 19:58:50 2002 +++ b/drivers/serial/8250.c Fri Jul 26 19:58:50 2002 @@ -1336,7 +1336,7 @@ fcr |= UART_FCR7_64BYTE; up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (iflag & IGNPAR) + if (iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (iflag & (BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; @@ -1672,23 +1672,23 @@ } static struct uart_ops serial8250_pops = { - tx_empty: serial8250_tx_empty, - set_mctrl: serial8250_set_mctrl, - get_mctrl: serial8250_get_mctrl, - stop_tx: serial8250_stop_tx, - start_tx: serial8250_start_tx, - stop_rx: serial8250_stop_rx, - enable_ms: serial8250_enable_ms, - break_ctl: serial8250_break_ctl, - startup: serial8250_startup, - shutdown: serial8250_shutdown, - change_speed: serial8250_change_speed, - pm: serial8250_pm, - type: serial8250_type, - release_port: serial8250_release_port, - request_port: serial8250_request_port, - config_port: serial8250_config_port, - verify_port: serial8250_verify_port, + .tx_empty = serial8250_tx_empty, + .set_mctrl = serial8250_set_mctrl, + .get_mctrl = serial8250_get_mctrl, + .stop_tx = serial8250_stop_tx, + .start_tx = serial8250_start_tx, + .stop_rx = serial8250_stop_rx, + .enable_ms = serial8250_enable_ms, + .break_ctl = serial8250_break_ctl, + .startup = serial8250_startup, + .shutdown = serial8250_shutdown, + .change_speed = serial8250_change_speed, + .pm = serial8250_pm, + .type = serial8250_type, + .release_port = serial8250_release_port, + .request_port = serial8250_request_port, + .config_port = serial8250_config_port, + .verify_port = serial8250_verify_port, }; static struct uart_8250_port serial8250_ports[UART_NR]; @@ -1707,6 +1707,7 @@ serial8250_ports[i].port.irq = irq_cannonicalize(old_serial_port[i].irq); serial8250_ports[i].port.uartclk = old_serial_port[i].base_baud * 16; serial8250_ports[i].port.flags = old_serial_port[i].flags; + serial8250_ports[i].port.hub6 = old_serial_port[i].hub6; serial8250_ports[i].port.ops = &serial8250_pops; } } @@ -1836,12 +1837,12 @@ } static struct console serial8250_console = { - name: "ttyS", - write: serial8250_console_write, - device: serial8250_console_device, - setup: serial8250_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = "ttyS", + .write = serial8250_console_write, + .device = serial8250_console_device, + .setup = serial8250_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void __init serial8250_console_init(void) @@ -1856,17 +1857,17 @@ #endif static struct uart_driver serial8250_reg = { - owner: THIS_MODULE, - driver_name: "serial", + .owner = THIS_MODULE, + .driver_name = "serial", #ifdef CONFIG_DEVFS_FS - dev_name: "tts/%d", + .dev_name = "tts/%d", #else - dev_name: "ttyS", + .dev_name = "ttyS", #endif - major: TTY_MAJOR, - minor: 64, - nr: UART_NR, - cons: SERIAL8250_CONSOLE, + .major = TTY_MAJOR, + .minor = 64, + .nr = UART_NR, + .cons = SERIAL8250_CONSOLE, }; /* diff -Nru a/drivers/serial/8250.h b/drivers/serial/8250.h --- a/drivers/serial/8250.h Fri Jul 26 19:58:50 2002 +++ b/drivers/serial/8250.h Fri Jul 26 19:58:50 2002 @@ -34,6 +34,7 @@ unsigned int port; unsigned int irq; unsigned int flags; + unsigned char hub6; }; #undef SERIAL_DEBUG_PCI diff -Nru a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c --- a/drivers/serial/8250_pci.c Fri Jul 26 19:58:52 2002 +++ b/drivers/serial/8250_pci.c Fri Jul 26 19:58:52 2002 @@ -1112,10 +1112,10 @@ #endif static struct pci_driver serial_pci_driver = { - name: "serial", - probe: pci_init_one, - remove: __devexit_p(pci_remove_one), - id_table: serial_pci_tbl, + .name = "serial", + .probe = pci_init_one, + .remove = __devexit_p(pci_remove_one), + .id_table = serial_pci_tbl, }; static int __init serial8250_pci_init(void) diff -Nru a/drivers/serial/amba.c b/drivers/serial/amba.c --- a/drivers/serial/amba.c Fri Jul 26 19:58:50 2002 +++ b/drivers/serial/amba.c Fri Jul 26 19:58:50 2002 @@ -557,54 +557,54 @@ } static struct uart_ops amba_pops = { - tx_empty: ambauart_tx_empty, - set_mctrl: ambauart_set_mctrl, - get_mctrl: ambauart_get_mctrl, - stop_tx: ambauart_stop_tx, - start_tx: ambauart_start_tx, - stop_rx: ambauart_stop_rx, - enable_ms: ambauart_enable_ms, - break_ctl: ambauart_break_ctl, - startup: ambauart_startup, - shutdown: ambauart_shutdown, - change_speed: ambauart_change_speed, - type: ambauart_type, - release_port: ambauart_release_port, - request_port: ambauart_request_port, - config_port: ambauart_config_port, - verify_port: ambauart_verify_port, + .tx_empty = ambauart_tx_empty, + .set_mctrl = ambauart_set_mctrl, + .get_mctrl = ambauart_get_mctrl, + .stop_tx = ambauart_stop_tx, + .start_tx = ambauart_start_tx, + .stop_rx = ambauart_stop_rx, + .enable_ms = ambauart_enable_ms, + .break_ctl = ambauart_break_ctl, + .startup = ambauart_startup, + .shutdown = ambauart_shutdown, + .change_speed = ambauart_change_speed, + .type = ambauart_type, + .release_port = ambauart_release_port, + .request_port = ambauart_request_port, + .config_port = ambauart_config_port, + .verify_port = ambauart_verify_port, }; static struct uart_amba_port amba_ports[UART_NR] = { { - port: { - membase: (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE), - mapbase: INTEGRATOR_UART0_BASE, - iotype: SERIAL_IO_MEM, - irq: IRQ_UARTINT0, - uartclk: 14745600, - fifosize: 16, - ops: &amba_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 0, + .port = { + .membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE), + .mapbase = INTEGRATOR_UART0_BASE, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UARTINT0, + .uartclk = 14745600, + .fifosize = 16, + .ops = &amba_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, }, - dtr_mask: 1 << 5, - rts_mask: 1 << 4, + .dtr_mask = 1 << 5, + .rts_mask = 1 << 4, }, { - port: { - membase: (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE), - mapbase: INTEGRATOR_UART1_BASE, - iotype: SERIAL_IO_MEM, - irq: IRQ_UARTINT1, - uartclk: 14745600, - fifosize: 16, - ops: &amba_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 1, + .port = { + .membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE), + .mapbase = INTEGRATOR_UART1_BASE, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UARTINT1, + .uartclk = 14745600, + .fifosize = 16, + .ops = &amba_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, }, - dtr_mask: 1 << 7, - rts_mask: 1 << 6, + .dtr_mask = 1 << 7, + .rts_mask = 1 << 6, } }; @@ -706,12 +706,12 @@ } static struct console amba_console = { - name: "ttyAM", - write: ambauart_console_write, - device: ambauart_console_device, - setup: ambauart_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = "ttyAM", + .write = ambauart_console_write, + .device = ambauart_console_device, + .setup = ambauart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void __init ambauart_console_init(void) @@ -725,17 +725,17 @@ #endif static struct uart_driver amba_reg = { - owner: THIS_MODULE, - driver_name: "ttyAM", + .owner = THIS_MODULE, + .driver_name = "ttyAM", #ifdef CONFIG_DEVFS_FS - dev_name: "ttyAM%d", + .dev_name = "ttyAM%d", #else - dev_name: "ttyAM", + .dev_name = "ttyAM", #endif - major: SERIAL_AMBA_MAJOR, - minor: SERIAL_AMBA_MINOR, - nr: UART_NR, - cons: AMBA_CONSOLE, + .major = SERIAL_AMBA_MAJOR, + .minor = SERIAL_AMBA_MINOR, + .nr = UART_NR, + .cons = AMBA_CONSOLE, }; static int __init ambauart_init(void) diff -Nru a/drivers/serial/anakin.c b/drivers/serial/anakin.c --- a/drivers/serial/anakin.c Fri Jul 26 19:58:51 2002 +++ b/drivers/serial/anakin.c Fri Jul 26 19:58:51 2002 @@ -322,65 +322,65 @@ } static struct uart_ops anakin_pops = { - tx_empty: anakin_tx_empty, - set_mctrl: anakin_set_mctrl, - get_mctrl: anakin_get_mctrl, - stop_tx: anakin_stop_tx, - start_tx: anakin_start_tx, - stop_rx: anakin_stop_rx, - enable_ms: anakin_enable_ms, - break_ctl: anakin_break_ctl, - startup: anakin_startup, - shutdown: anakin_shutdown, - change_speed: anakin_change_speed, - type: anakin_type, + .tx_empty = anakin_tx_empty, + .set_mctrl = anakin_set_mctrl, + .get_mctrl = anakin_get_mctrl, + .stop_tx = anakin_stop_tx, + .start_tx = anakin_start_tx, + .stop_rx = anakin_stop_rx, + .enable_ms = anakin_enable_ms, + .break_ctl = anakin_break_ctl, + .startup = anakin_startup, + .shutdown = anakin_shutdown, + .change_speed = anakin_change_speed, + .type = anakin_type, }; static struct uart_port anakin_ports[UART_NR] = { { - base: IO_BASE + UART0, - irq: IRQ_UART0, - uartclk: 3686400, - fifosize: 0, - ops: &anakin_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 0, + .base = IO_BASE + UART0, + .irq = IRQ_UART0, + .uartclk = 3686400, + .fifosize = 0, + .ops = &anakin_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, }, { - base: IO_BASE + UART1, - irq: IRQ_UART1, - uartclk: 3686400, - fifosize: 0, - ops: &anakin_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 1, + .base = IO_BASE + UART1, + .irq = IRQ_UART1, + .uartclk = 3686400, + .fifosize = 0, + .ops = &anakin_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, }, { - base: IO_BASE + UART2, - irq: IRQ_UART2, - uartclk: 3686400, - fifosize: 0, - ops: &anakin_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 2, + .base = IO_BASE + UART2, + .irq = IRQ_UART2, + .uartclk = 3686400, + .fifosize = 0, + .ops = &anakin_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, }, { - base: IO_BASE + UART3, - irq: IRQ_UART3, - uartclk: 3686400, - fifosize: 0, - ops: &anakin_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 3, + .base = IO_BASE + UART3, + .irq = IRQ_UART3, + .uartclk = 3686400, + .fifosize = 0, + .ops = &anakin_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 3, }, { - base: IO_BASE + UART4, - irq: IRQ_UART4, - uartclk: 3686400, - fifosize: 0, - ops: &anakin_pops, - flags: ASYNC_BOOT_AUTOCONF, - line: 4, + .base = IO_BASE + UART4, + .irq = IRQ_UART4, + .uartclk = 3686400, + .fifosize = 0, + .ops = &anakin_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 4, }, }; @@ -485,12 +485,12 @@ } static struct console anakin_console = { - name: SERIAL_ANAKIN_NAME, - write: anakin_console_write, - device: anakin_console_device, - setup: anakin_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = SERIAL_ANAKIN_NAME, + .write = anakin_console_write, + .device = anakin_console_device, + .setup = anakin_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void __init @@ -505,12 +505,12 @@ #endif static struct uart_register anakin_reg = { - driver_name: SERIAL_ANAKIN_NAME, - dev_name: SERIAL_ANAKIN_NAME, - major: SERIAL_ANAKIN_MAJOR, - minor: SERIAL_ANAKIN_MINOR, - nr: UART_NR, - cons: ANAKIN_CONSOLE, + .driver_name = SERIAL_ANAKIN_NAME, + .dev_name = SERIAL_ANAKIN_NAME, + .major = SERIAL_ANAKIN_MAJOR, + .minor = SERIAL_ANAKIN_MINOR, + .nr = UART_NR, + .cons = ANAKIN_CONSOLE, }; static int __init diff -Nru a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c --- a/drivers/serial/clps711x.c Fri Jul 26 19:58:51 2002 +++ b/drivers/serial/clps711x.c Fri Jul 26 19:58:51 2002 @@ -418,39 +418,39 @@ } static struct uart_ops clps711x_pops = { - tx_empty: clps711xuart_tx_empty, - set_mctrl: clps711xuart_set_mctrl_null, - get_mctrl: clps711xuart_get_mctrl, - stop_tx: clps711xuart_stop_tx, - start_tx: clps711xuart_start_tx, - stop_rx: clps711xuart_stop_rx, - enable_ms: clps711xuart_enable_ms, - break_ctl: clps711xuart_break_ctl, - startup: clps711xuart_startup, - shutdown: clps711xuart_shutdown, - change_speed: clps711xuart_change_speed, - type: clps711xuart_type, - config_port: clps711xuart_config_port, - release_port: clps711xuart_release_port, - request_port: clps711xuart_request_port, + .tx_empty = clps711xuart_tx_empty, + .set_mctrl = clps711xuart_set_mctrl_null, + .get_mctrl = clps711xuart_get_mctrl, + .stop_tx = clps711xuart_stop_tx, + .start_tx = clps711xuart_start_tx, + .stop_rx = clps711xuart_stop_rx, + .enable_ms = clps711xuart_enable_ms, + .break_ctl = clps711xuart_break_ctl, + .startup = clps711xuart_startup, + .shutdown = clps711xuart_shutdown, + .change_speed = clps711xuart_change_speed, + .type = clps711xuart_type, + .config_port = clps711xuart_config_port, + .release_port = clps711xuart_release_port, + .request_port = clps711xuart_request_port, }; static struct uart_port clps711x_ports[UART_NR] = { { - iobase: SYSCON1, - irq: IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ - uartclk: 3686400, - fifosize: 16, - ops: &clps711x_pops, - flags: ASYNC_BOOT_AUTOCONF, + .iobase = SYSCON1, + .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ + .uartclk = 3686400, + .fifosize = 16, + .ops = &clps711x_pops, + .flags = ASYNC_BOOT_AUTOCONF, }, { - iobase: SYSCON2, - irq: IRQ_UTXINT2, /* IRQ_URXINT2 */ - uartclk: 3686400, - fifosize: 16, - ops: &clps711x_pops, - flags: ASYNC_BOOT_AUTOCONF, + .iobase = SYSCON2, + .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ + .uartclk = 3686400, + .fifosize = 16, + .ops = &clps711x_pops, + .flags = ASYNC_BOOT_AUTOCONF, } }; @@ -560,12 +560,12 @@ } static struct console clps711x_console = { - name: SERIAL_CLPS711X_NAME, - write: clps711xuart_console_write, - device: clps711xuart_console_device, - setup: clps711xuart_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = SERIAL_CLPS711X_NAME, + .write = clps711xuart_console_write, + .device = clps711xuart_console_device, + .setup = clps711xuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void __init clps711xuart_console_init(void) @@ -579,18 +579,18 @@ #endif static struct uart_driver clps711x_reg = { - driver_name: "ttyCL", + .driver_name = "ttyCL", #ifdef CONFIG_DEVFS_FS - dev_name: SERIAL_CLPS711X_NAME, + .dev_name = SERIAL_CLPS711X_NAME, #else - dev_name: SERIAL_CLPS711X_NAME, + .dev_name = SERIAL_CLPS711X_NAME, #endif - major: SERIAL_CLPS711X_MAJOR, - minor: SERIAL_CLPS711X_MINOR, - nr: UART_NR, + .major = SERIAL_CLPS711X_MAJOR, + .minor = SERIAL_CLPS711X_MINOR, + .nr = UART_NR, - cons: CLPS711X_CONSOLE, + .cons = CLPS711X_CONSOLE, }; static int __init clps711xuart_init(void) diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c --- a/drivers/serial/core.c Fri Jul 26 19:58:51 2002 +++ b/drivers/serial/core.c Fri Jul 26 19:58:51 2002 @@ -1450,6 +1450,9 @@ if (signal_pending(current)) return -ERESTARTSYS; + if (info->tty->flags & (1 << TTY_IO_ERROR)) + return 0; + if (tty_hung_up_p(filp) || !(info->flags & UIF_INITIALIZED)) return (port->flags & UPF_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; @@ -2425,7 +2428,7 @@ state->port->regshift = port->regshift; state->port->iotype = port->iotype; state->port->flags = port->flags; - state->port->line = drv->state - state; + state->port->line = state - drv->state; __uart_register_port(drv, state, state->port); @@ -2469,6 +2472,8 @@ EXPORT_SYMBOL(uart_unregister_driver); EXPORT_SYMBOL(uart_register_port); EXPORT_SYMBOL(uart_unregister_port); +EXPORT_SYMBOL(uart_add_one_port); +EXPORT_SYMBOL(uart_remove_one_port); MODULE_DESCRIPTION("Serial driver core"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c --- a/drivers/serial/sa1100.c Fri Jul 26 19:58:50 2002 +++ b/drivers/serial/sa1100.c Fri Jul 26 19:58:50 2002 @@ -602,22 +602,22 @@ } static struct uart_ops sa1100_pops = { - tx_empty: sa1100_tx_empty, - set_mctrl: sa1100_set_mctrl, - get_mctrl: sa1100_get_mctrl, - stop_tx: sa1100_stop_tx, - start_tx: sa1100_start_tx, - stop_rx: sa1100_stop_rx, - enable_ms: sa1100_enable_ms, - break_ctl: sa1100_break_ctl, - startup: sa1100_startup, - shutdown: sa1100_shutdown, - change_speed: sa1100_change_speed, - type: sa1100_type, - release_port: sa1100_release_port, - request_port: sa1100_request_port, - config_port: sa1100_config_port, - verify_port: sa1100_verify_port, + .tx_empty = sa1100_tx_empty, + .set_mctrl = sa1100_set_mctrl, + .get_mctrl = sa1100_get_mctrl, + .stop_tx = sa1100_stop_tx, + .start_tx = sa1100_start_tx, + .stop_rx = sa1100_stop_rx, + .enable_ms = sa1100_enable_ms, + .break_ctl = sa1100_break_ctl, + .startup = sa1100_startup, + .shutdown = sa1100_shutdown, + .change_speed = sa1100_change_speed, + .type = sa1100_type, + .release_port = sa1100_release_port, + .request_port = sa1100_request_port, + .config_port = sa1100_config_port, + .verify_port = sa1100_verify_port, }; static struct sa1100_port sa1100_ports[NR_PORTS]; @@ -820,12 +820,12 @@ } static struct console sa1100_console = { - name: "ttySA", - write: sa1100_console_write, - device: sa1100_console_device, - setup: sa1100_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = "ttySA", + .write = sa1100_console_write, + .device = sa1100_console_device, + .setup = sa1100_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void __init sa1100_rs_console_init(void) @@ -840,17 +840,17 @@ #endif static struct uart_driver sa1100_reg = { - owner: THIS_MODULE, - driver_name: "ttySA", + .owner = THIS_MODULE, + .driver_name = "ttySA", #ifdef CONFIG_DEVFS_FS - dev_name: "ttySA%d", + .dev_name = "ttySA%d", #else - dev_name: "ttySA", + .dev_name = "ttySA", #endif - major: SERIAL_SA1100_MAJOR, - minor: MINOR_START, - nr: NR_PORTS, - cons: SA1100_CONSOLE, + .major = SERIAL_SA1100_MAJOR, + .minor = MINOR_START, + .nr = NR_PORTS, + .cons = SA1100_CONSOLE, }; static int __init sa1100_serial_init(void) diff -Nru a/drivers/serial/uart00.c b/drivers/serial/uart00.c --- a/drivers/serial/uart00.c Fri Jul 26 19:58:51 2002 +++ b/drivers/serial/uart00.c Fri Jul 26 19:58:51 2002 @@ -498,35 +498,35 @@ } static struct uart_ops uart00_pops = { - tx_empty: uart00_tx_empty, - set_mctrl: uart00_set_mctrl_null, - get_mctrl: uart00_get_mctrl, - stop_tx: uart00_stop_tx, - start_tx: uart00_start_tx, - stop_rx: uart00_stop_rx, - enable_ms: uart00_enable_ms, - break_ctl: uart00_break_ctl, - startup: uart00_startup, - shutdown: uart00_shutdown, - change_speed: uart00_change_speed, - type: uart00_type, - release_port: uart00_release_port, - request_port: uart00_request_port, - config_port: uart00_config_port, - verify_port: uart00_verify_port, + .tx_empty = uart00_tx_empty, + .set_mctrl = uart00_set_mctrl_null, + .get_mctrl = uart00_get_mctrl, + .stop_tx = uart00_stop_tx, + .start_tx = uart00_start_tx, + .stop_rx = uart00_stop_rx, + .enable_ms = uart00_enable_ms, + .break_ctl = uart00_break_ctl, + .startup = uart00_startup, + .shutdown = uart00_shutdown, + .change_speed = uart00_change_speed, + .type = uart00_type, + .release_port = uart00_release_port, + .request_port = uart00_request_port, + .config_port = uart00_config_port, + .verify_port = uart00_verify_port, }; #ifdef CONFIG_ARCH_CAMELOT static struct uart_port epxa10db_port = { - membase: (void*)IO_ADDRESS(EXC_UART00_BASE), - mapbase: EXC_UART00_BASE, - iotype: SERIAL_IO_MEM, - irq: IRQ_UART, - uartclk: EXC_AHB2_CLK_FREQUENCY, - fifosize: 16, - ops: &uart00_pops, - flags: ASYNC_BOOT_AUTOCONF, + .membase = (void*)IO_ADDRESS(EXC_UART00_BASE), + .mapbase = EXC_UART00_BASE, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART, + .uartclk = EXC_AHB2_CLK_FREQUENCY, + .fifosize = 16, + .ops = &uart00_pops, + .flags = ASYNC_BOOT_AUTOCONF, }; #endif @@ -633,12 +633,12 @@ } static struct console uart00_console = { - name: SERIAL_UART00_NAME, - write: uart00_console_write, - device: uart00_console_device, - setup: uart00_console_setup, - flags: CON_PRINTBUFFER, - index: 0, + .name = SERIAL_UART00_NAME, + .write = uart00_console_write, + .device = uart00_console_device, + .setup = uart00_console_setup, + .flags = CON_PRINTBUFFER, + .index = 0, }; void __init uart00_console_init(void) @@ -652,13 +652,13 @@ #endif static struct uart_driver uart00_reg = { - owner: NULL, - driver_name: SERIAL_UART00_NAME, - dev_name: SERIAL_UART00_NAME, - major: SERIAL_UART00_MAJOR, - minor: SERIAL_UART00_MINOR, - nr: UART_NR, - cons: UART00_CONSOLE, + .owner = NULL, + .driver_name = SERIAL_UART00_NAME, + .dev_name = SERIAL_UART00_NAME, + .major = SERIAL_UART00_MAJOR, + .minor = SERIAL_UART00_MINOR, + .nr = UART_NR, + .cons = UART00_CONSOLE, }; struct dev_port_entry{ diff -Nru a/drivers/usb/Config.help b/drivers/usb/Config.help --- a/drivers/usb/Config.help Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/Config.help Fri Jul 26 19:58:51 2002 @@ -11,13 +11,18 @@ to the PC via those ports. Say Y here if your computer has a USB port and you want to use USB - devices. You then need to say Y to at least one of "UHCI support" - or "OHCI support" below (the type of interface that the USB hardware + devices. You then need to say Y to at least one of "UHCI HCD support" + or "OHCI HCD support" below (the type of interface that the USB hardware in your computer provides to the operating system) and then choose - from among the drivers for USB peripherals. You may want to check + from amongst the drivers for USB peripherals. You may want to check out the information provided in and especially the links given in . + If you have a new USB 2.0 High Speed system, you should also choose + "EHCI HCD (USB 2.0) support" as well as at least one of UHCI or OHCI. + + It doesn't normally hurt to select them all if you are not certain. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usbcore.o. If you want to compile it as a @@ -39,7 +44,7 @@ CONFIG_USB_DEVICEFS If you say Y here (and to "/proc file system support" in the "File - systems section, above), you will get a file /proc/bus/usb/devices + systems" section, above), you will get a file /proc/bus/usb/devices which lists the devices currently connected to your USB bus or busses, a file /proc/bus/usb/drivers which lists the USB kernel client drivers currently loaded, and for every connected device a diff -Nru a/drivers/usb/class/Config.help b/drivers/usb/class/Config.help --- a/drivers/usb/class/Config.help Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/class/Config.help Fri Jul 26 19:58:51 2002 @@ -3,6 +3,10 @@ Communication Device Class Abstract Control Model interface. Please read for details. + If your modem only reports "Cls=ff(vend.)" in the descriptors in + /proc/bus/usb/devices, then your modem will not work with this + driver. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called acm.o. If you want to compile it as a diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/class/audio.c Fri Jul 26 19:58:52 2002 @@ -2745,8 +2745,8 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr); static struct usb_device_id usb_audio_ids [] = { - { match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), - bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: 1}, + { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), + .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 1}, { } /* Terminating entry */ }; diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/core/usb.c Fri Jul 26 19:58:51 2002 @@ -947,8 +947,8 @@ /* register this interface with driverfs */ interface->dev.parent = &dev->dev; interface->dev.bus = &usb_bus_type; - sprintf (&interface->dev.bus_id[0], "%s:%d", - dev->devpath, + sprintf (&interface->dev.bus_id[0], "%s-%s:%d", + dev->bus->bus_name, dev->devpath, interface->altsetting->bInterfaceNumber); if (!desc->iInterface || usb_string (dev, desc->iInterface, diff -Nru a/drivers/usb/host/Config.help b/drivers/usb/host/Config.help --- a/drivers/usb/host/Config.help Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/host/Config.help Fri Jul 26 19:58:51 2002 @@ -12,7 +12,8 @@ will connect to EHCI if it the device is high speed, otherwise they connect to a companion controller. If you configure EHCI, you should probably configure the OHCI (for NEC and some other vendors) USB Host - Controller Driver too. + Controller Driver or UHCI (for Via motherboards) Host Controller + Driver too. You may want to read . diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/host/ehci-hcd.c Fri Jul 26 19:58:52 2002 @@ -65,6 +65,8 @@ * * HISTORY: * + * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support, + * clean up HC run state handshaking. * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other * missing pieces: enabling 64bit dma, handoff from BIOS/SMM. @@ -83,7 +85,7 @@ * 2001-June Works with usb-storage and NEC EHCI on 2.4 */ -#define DRIVER_VERSION "2002-May-24" +#define DRIVER_VERSION "2002-Jul-25" #define DRIVER_AUTHOR "David Brownell" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" @@ -113,42 +115,105 @@ /*-------------------------------------------------------------------------*/ /* + * handshake - spin reading hc until handshake completes or fails + * @ptr: address of hc register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + * + * That last failure should_only happen in cases like physical cardbus eject + * before driver shutdown. But it also seems to be caused by bugs in cardbus + * bridge shutdown: shutting down the bridge before the devices using it. + */ +static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = readl (ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay (1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* * hc states include: unknown, halted, ready, running * transitional states are messy just now * trying to avoid "running" unless urbs are active * a "ready" hc can be finishing prefetched work */ -/* halt a non-running controller */ -static void ehci_reset (struct ehci_hcd *ehci) +/* force HC to halt state from unknown (EHCI spec section 2.3) */ +static int ehci_halt (struct ehci_hcd *ehci) +{ + u32 temp = readl (&ehci->regs->status); + + if ((temp & STS_HALT) != 0) + return 0; + + temp = readl (&ehci->regs->command); + temp &= ~CMD_RUN; + writel (temp, &ehci->regs->command); + return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); +} + +/* reset a non-running (STS_HALT == 1) controller */ +static int ehci_reset (struct ehci_hcd *ehci) { u32 command = readl (&ehci->regs->command); command |= CMD_RESET; dbg_cmd (ehci, "reset", command); writel (command, &ehci->regs->command); - while (readl (&ehci->regs->command) & CMD_RESET) - continue; ehci->hcd.state = USB_STATE_HALT; + return handshake (&ehci->regs->command, CMD_RESET, 0, 050); } /* idle the controller (from running) */ static void ehci_ready (struct ehci_hcd *ehci) { - u32 command; + u32 temp; #ifdef DEBUG if (!HCD_IS_RUNNING (ehci->hcd.state)) BUG (); #endif - while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS))) - udelay (100); - command = readl (&ehci->regs->command); - command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - writel (command, &ehci->regs->command); + /* wait for any schedule enables/disables to take effect */ + temp = 0; + if (ehci->async) + temp = STS_ASS; + if (ehci->next_uframe != -1) + temp |= STS_PSS; + if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + temp, 16 * 125) != 0) { + ehci->hcd.state = USB_STATE_HALT; + return; + } - // hardware can take 16 microframes to turn off ... + /* then disable anything that's still active */ + temp = readl (&ehci->regs->command); + temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); + writel (temp, &ehci->regs->command); + + /* hardware can take 16 microframes to turn off ... */ + if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + 0, 16 * 125) != 0) { + ehci->hcd.state = USB_STATE_HALT; + return; + } ehci->hcd.state = USB_STATE_READY; } @@ -236,6 +301,10 @@ /* cache this readonly data; minimize PCI reads */ ehci->hcs_params = readl (&ehci->caps->hcs_params); + /* force HC to halt state */ + if ((retval = ehci_halt (ehci)) != 0) + return retval; + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -257,8 +326,10 @@ /* controller state: unknown --> reset */ /* EHCI spec section 4.1 */ - // FIXME require STS_HALT before reset... - ehci_reset (ehci); + if ((retval = ehci_reset (ehci)) != 0) { + ehci_mem_cleanup (ehci); + return retval; + } writel (INTR_MASK, &ehci->regs->intr_enable); writel (ehci->periodic_dma, &ehci->regs->frame_list); @@ -335,8 +406,6 @@ if (usb_register_root_hub (udev, &ehci->hcd.pdev->dev) != 0) { if (hcd->state == USB_STATE_RUNNING) ehci_ready (ehci); - while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) - udelay (100); ehci_reset (ehci); hcd->self.root_hub = 0; usb_free_dev (udev); @@ -355,16 +424,14 @@ dbg ("%s: stop", hcd->self.bus_name); + /* no more interrupts ... */ if (hcd->state == USB_STATE_RUNNING) ehci_ready (ehci); - while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) - udelay (100); ehci_reset (ehci); - // root hub is shut down separately (first, when possible) - scan_async (ehci); - if (ehci->next_uframe != -1) - scan_periodic (ehci); + /* root hub is shut down separately (first, when possible) */ + tasklet_disable (&ehci->tasklet); + ehci_tasklet ((unsigned long) ehci); ehci_mem_cleanup (ehci); dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); @@ -412,8 +479,6 @@ if (hcd->state == USB_STATE_RUNNING) ehci_ready (ehci); - while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) - udelay (100); writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command); // save pci FLADJ value @@ -489,6 +554,12 @@ u32 status = readl (&ehci->regs->status); int bh; + /* e.g. cardbus physical eject */ + if (status == ~(u32) 0) { + dbg ("%s: device removed!", hcd->self.bus_name); + goto dead; + } + status &= INTR_MASK; if (!status) /* irq sharing? */ return; @@ -517,10 +588,13 @@ /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { - err ("%s: fatal error, state %x", hcd->self.bus_name, hcd->state); + err ("%s: fatal error, state %x", + hcd->self.bus_name, hcd->state); +dead: ehci_reset (ehci); - // generic layer kills/unlinks all urbs - // then tasklet cleans up the rest + /* generic layer kills/unlinks all urbs, then + * uses ehci_stop to clean up the rest + */ bh = 1; } diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/host/ehci-q.c Fri Jul 26 19:58:51 2002 @@ -718,8 +718,7 @@ u32 cmd = readl (&ehci->regs->command); /* in case a clear of CMD_ASE didn't take yet */ - while (readl (&ehci->regs->status) & STS_ASS) - udelay (100); + (void) handshake (&ehci->regs->status, STS_ASS, 0, 150); qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ qh->qh_next.qh = qh; @@ -917,11 +916,8 @@ if (ehci->hcd.state != USB_STATE_HALT) { if (cmd & CMD_PSE) writel (cmd & ~CMD_ASE, &ehci->regs->command); - else { + else ehci_ready (ehci); - while (readl (&ehci->regs->status) & STS_ASS) - udelay (100); - } } qh->qh_next.qh = ehci->async = 0; diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/host/ehci-sched.c Fri Jul 26 19:58:51 2002 @@ -171,15 +171,19 @@ /*-------------------------------------------------------------------------*/ -static void enable_periodic (struct ehci_hcd *ehci) +static int enable_periodic (struct ehci_hcd *ehci) { u32 cmd; + int status; /* did clearing PSE did take effect yet? * takes effect only at frame boundaries... */ - while (readl (&ehci->regs->status) & STS_PSS) - udelay (20); + status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); + if (status != 0) { + ehci->hcd.state = USB_STATE_HALT; + return status; + } cmd = readl (&ehci->regs->command) | CMD_PSE; writel (cmd, &ehci->regs->command); @@ -189,23 +193,29 @@ /* make sure tasklet scans these */ ehci->next_uframe = readl (&ehci->regs->frame_index) % (ehci->periodic_size << 3); + return 0; } -static void disable_periodic (struct ehci_hcd *ehci) +static int disable_periodic (struct ehci_hcd *ehci) { u32 cmd; + int status; /* did setting PSE not take effect yet? * takes effect only at frame boundaries... */ - while (!(readl (&ehci->regs->status) & STS_PSS)) - udelay (20); + status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); + if (status != 0) { + ehci->hcd.state = USB_STATE_HALT; + return status; + } cmd = readl (&ehci->regs->command) & ~CMD_PSE; writel (cmd, &ehci->regs->command); /* posted write ... */ ehci->next_uframe = -1; + return 0; } /*-------------------------------------------------------------------------*/ @@ -217,6 +227,7 @@ unsigned period ) { unsigned long flags; + int status; period >>= 3; // FIXME microframe periods not handled yet @@ -234,9 +245,11 @@ /* maybe turn off periodic schedule */ if (!ehci->periodic_urbs) - disable_periodic (ehci); - else + status = disable_periodic (ehci); + else { + status = 0; vdbg ("periodic schedule still enabled"); + } spin_unlock_irqrestore (&ehci->lock, flags); @@ -245,7 +258,7 @@ * (yeech!) to be sure it's done. * No other threads may be mucking with this qh. */ - if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0) + if (!status && ((ehci_get_frame (&ehci->hcd) - frame) % period) == 0) udelay (125); qh->qh_state = QH_STATE_IDLE; @@ -501,7 +514,7 @@ /* maybe enable periodic schedule processing */ if (!ehci->periodic_urbs++) - enable_periodic (ehci); + status = enable_periodic (ehci); break; } while (frame); @@ -913,8 +926,12 @@ usb_claim_bandwidth (urb->dev, urb, usecs, 1); /* maybe enable periodic schedule processing */ - if (!ehci->periodic_urbs++) - enable_periodic (ehci); + if (!ehci->periodic_urbs++) { + if ((status = enable_periodic (ehci)) != 0) { + // FIXME deschedule right away + err ("itd_schedule, enable = %d", status); + } + } return 0; @@ -994,7 +1011,7 @@ /* defer stopping schedule; completion can submit */ ehci->periodic_urbs--; if (!ehci->periodic_urbs) - disable_periodic (ehci); + (void) disable_periodic (ehci); return flags; } diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/host/ohci-dbg.c Fri Jul 26 19:58:52 2002 @@ -281,16 +281,21 @@ cbp ? (be + 1 - cbp) : 0); } else { unsigned i; - dbg (" info %08x CC=%x DI=%d START=%04x", tmp, - TD_CC_GET(tmp), /* FC, */ + dbg (" info %08x CC=%x FC=%d DI=%d SF=%04x", tmp, + TD_CC_GET(tmp), + (tmp >> 24) & 0x07, (tmp & TD_DI) >> 21, tmp & 0x0000ffff); dbg (" bp0 %08x be %08x", le32_to_cpup (&td->hwCBP) & ~0x0fff, le32_to_cpup (&td->hwBE)); for (i = 0; i < MAXPSW; i++) { - dbg (" psw [%d] = %2x", i, - le16_to_cpu (td->hwPSW [i])); + u16 psw = le16_to_cpup (&td->hwPSW [i]); + int cc = (psw >> 12) & 0x0f; + dbg (" psw [%d] = %2x, CC=%x %s=%d", i, + psw, cc, + (cc >= 0x0e) ? "OFFSET" : "SIZE", + psw & 0x0fff); } } } diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/host/ohci-hcd.c Fri Jul 26 19:58:50 2002 @@ -10,8 +10,15 @@ * [ (C) Copyright 1999 Gregory P. Smith] * * + * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller + * interfaces (though some non-x86 Intel chips use it). It supports + * smarter hardware than UHCI. A download link for the spec available + * through the http://www.usb.org website. + * * History: * + * 2002/07/19 fixes to management of ED and schedule state. + * 2002/06/09 SA-1111 support (Christopher Hoover) * 2002/06/01 remember frame when HC won't see EDs any more; use that info * to fix urb unlink races caused by interrupt latency assumptions; * minor ED field and function naming updates @@ -95,12 +102,12 @@ /* * TO DO: * - * - "disabled" should be the hcd state + * - "disabled" and "sleeping" should be in hcd->state * - bandwidth alloc to generic code * - lots more testing!! */ -#define DRIVER_VERSION "2002-Jun-15" +#define DRIVER_VERSION "2002-Jul-19" #define DRIVER_AUTHOR "Roman Weissgaerber , David Brownell" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" @@ -118,6 +125,12 @@ #include "ohci.h" +static inline void disable (struct ohci_hcd *ohci) +{ + ohci->disabled = 1; + ohci->hcd.state = USB_STATE_HALT; +} + #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -140,6 +153,7 @@ int i, size = 0; unsigned long flags; int bustime = 0; + int retval = 0; #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "SUB", usb_pipein (pipe)); @@ -150,12 +164,18 @@ return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ - switch (usb_pipetype (pipe)) { + switch (ed->type) { case PIPE_CONTROL: + /* td_submit_urb() doesn't yet handle these */ + if (urb->transfer_buffer_length > 4096) + return -EMSGSIZE; + /* 1 TD for setup, 1 for ACK, plus ... */ size = 2; /* FALLTHROUGH */ - case PIPE_BULK: + // case PIPE_INTERRUPT: + // case PIPE_BULK: + default: /* one TD for every 4096 Bytes (can be upto 8K) */ size += urb->transfer_buffer_length / 4096; /* ... and for any remaining bytes ... */ @@ -179,9 +199,6 @@ urb->iso_frame_desc [i].status = -EXDEV; } break; - case PIPE_INTERRUPT: /* one TD */ - size = 1; - break; } /* allocate the private part of the URB */ @@ -191,19 +208,25 @@ return -ENOMEM; memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); + spin_lock_irqsave (&ohci->lock, flags); + + /* don't submit to a dead HC */ + if (ohci->disabled || ohci->sleeping) { + retval = -ENODEV; + goto fail; + } + /* 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); - return -ENOMEM; + retval = -ENOMEM; + goto fail; } } @@ -217,20 +240,19 @@ switch (usb_pipetype (pipe)) { case PIPE_ISOCHRONOUS: if (urb->transfer_flags & USB_ISO_ASAP) { - urb->start_frame = ( (ed->state == ED_OPER) + urb->start_frame = ((ed->state != ED_IDLE) ? (ed->intriso.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); - return bustime; + retval = bustime; + goto fail; } usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); @@ -238,18 +260,20 @@ urb->hcpriv = urb_priv; - /* link the ed into a chain if is not already */ - if (ed->state != ED_OPER) - ep_link (ohci, ed); + /* schedule the ed if needed */ + if (ed->state == ED_IDLE) + ed_schedule (ohci, ed); /* fill the TDs and link them to the ed; and * enable that part of the schedule, if needed */ - td_submit_urb (urb); + td_submit_urb (ohci, urb); +fail: + if (retval) + urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&ohci->lock, flags); - - return 0; + return retval; } /* @@ -270,19 +294,17 @@ if (!ohci->disabled) { urb_priv_t *urb_priv; - /* flag the urb's data for deletion in some upcoming - * SF interrupt's delete list processing + /* Unless an IRQ completed the unlink while it was being + * handed to us, flag it for unlink and giveback, and force + * some upcoming INTR_SF to call finish_unlinks() */ 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; + if (urb_priv) { + urb_priv->state = URB_DEL; + if (urb_priv->ed->state == ED_OPER) + start_urb_unlink (ohci, urb_priv->ed); } - - urb_priv->state = URB_DEL; - start_urb_unlink (ohci, urb_priv->ed); spin_unlock_irqrestore (&ohci->lock, flags); } else { /* @@ -290,12 +312,16 @@ * any more ... just clean up every urb's memory. */ finish_urb (ohci, urb); - } + } return 0; } /*-------------------------------------------------------------------------*/ +/* frees config/altsetting state for endpoints, + * including ED memory, dummy TD, and bulk/intr data toggle + */ + static void ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) { @@ -303,7 +329,11 @@ struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv; int i; unsigned long flags; +#ifdef DEBUG + int rescans = 0; +#endif +rescan: /* free any eds, and dummy tds, still hanging around */ spin_lock_irqsave (&ohci->lock, flags); for (i = 0; i < 32; i++) { @@ -312,27 +342,47 @@ if (!ed) continue; - ed->state &= ~ED_URB_DEL; - if (ohci->disabled && ed->state == ED_OPER) - ed->state = ED_UNLINK; + if (ohci->disabled && ed->state != ED_IDLE) + ed->state = ED_IDLE; switch (ed->state) { - case ED_NEW: - break; - case ED_UNLINK: + case ED_UNLINK: /* wait a frame? */ + goto do_rescan; + case ED_IDLE: /* fully unlinked */ td_free (ohci, ed->dummy); break; - - case ED_OPER: default: +#ifdef DEBUG err ("illegal ED %d state in free_config, %d", i, ed->state); -#ifdef DEBUG - BUG (); #endif + /* ED_OPER: some driver disconnect() is broken, + * it didn't even start its unlinks much less wait + * for their completions. + * OTHERWISE: hcd bug, ed is garbage + */ + BUG (); } ed_free (ohci, ed); } spin_unlock_irqrestore (&ohci->lock, flags); + return; + +do_rescan: +#ifdef DEBUG + /* a driver->disconnect() returned before its unlinks completed? */ + if (in_interrupt ()) { + dbg ("WARNING: spin in interrupt; driver->disconnect() bug"); + dbg ("dev usb-%s-%s ep 0x%x", + ohci->hcd.self.bus_name, udev->devpath, i); + } + BUG_ON (!(readl (&ohci->regs->intrenable) & OHCI_INTR_SF)); + BUG_ON (rescans >= 2); /* HWBUG */ + rescans++; +#endif + + spin_unlock_irqrestore (&ohci->lock, flags); + wait_ms (1); + goto rescan; } static int ohci_get_frame (struct usb_hcd *hcd) @@ -471,7 +521,7 @@ ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self); ohci->hcd.state = USB_STATE_READY; if (!udev) { - ohci->disabled = 1; + disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; writel (ohci->hc_control, &ohci->regs->control); return -ENOMEM; @@ -481,7 +531,7 @@ udev->speed = USB_SPEED_FULL; if (usb_register_root_hub (udev, ohci->parent_dev) != 0) { usb_free_dev (udev); - ohci->disabled = 1; + disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; writel (ohci->hc_control, &ohci->regs->control); return -ENODEV; @@ -507,8 +557,8 @@ /* cardbus/... hardware gone before remove() */ } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { - ohci->disabled++; - err ("%s device removed!", hcd->self.bus_name); + disable (ohci); + dbg ("%s device removed!", hcd->self.bus_name); return; /* interrupt for some other device? */ @@ -520,7 +570,7 @@ // dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); if (ints & OHCI_INTR_UE) { - ohci->disabled++; + disable (ohci); err ("OHCI Unrecoverable Error, %s disabled", hcd->self.bus_name); // e.g. due to PCI Master/Target Abort diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c --- a/drivers/usb/host/ohci-hub.c Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/host/ohci-hub.c Fri Jul 26 19:58:50 2002 @@ -22,7 +22,9 @@ */ #define read_roothub(hc, register, mask) ({ \ u32 temp = readl (&hc->regs->roothub.register); \ - if (hc->flags & OHCI_QUIRK_AMD756) \ + if (temp == -1) \ + disable (hc); \ + else if (hc->flags & OHCI_QUIRK_AMD756) \ while (temp & mask) \ temp = readl (&hc->regs->roothub.register); \ temp; }) @@ -71,8 +73,10 @@ ports = roothub_a (ohci) & RH_A_NDP; if (ports > MAX_ROOT_PORTS) { - err ("%s: bogus NDP=%d", hcd->self.bus_name, ports); - err ("rereads as NDP=%d", + if (ohci->disabled) + return -ESHUTDOWN; + err ("%s bogus NDP=%d, rereads as NDP=%d", + hcd->self.bus_name, ports, readl (&ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ return 0; diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/host/ohci-q.c Fri Jul 26 19:58:52 2002 @@ -77,12 +77,12 @@ usb_hcd_giveback_urb (&ohci->hcd, urb); } -static void td_submit_urb (struct urb *urb); +static void td_submit_urb (struct ohci_hcd *ohci, struct urb *urb); /* Report interrupt transfer completion, maybe reissue */ -static void intr_resub (struct ohci_hcd *hc, struct urb *urb) +static inline void intr_resub (struct ohci_hcd *hc, struct urb *urb) { - urb_priv_t *urb_priv = urb->hcpriv; + struct urb_priv *urb_priv = urb->hcpriv; unsigned long flags; // FIXME rewrite this resubmit path. use pci_dma_sync_single() @@ -120,7 +120,7 @@ spin_unlock (&urb->lock); spin_lock (&hc->lock); - td_submit_urb (urb); + td_submit_urb (hc, urb); spin_unlock_irqrestore (&hc->lock, flags); } @@ -170,50 +170,50 @@ /* link an ed into one of the HC chains */ -static int ep_link (struct ohci_hcd *ohci, struct ed *edi) +static void ed_schedule (struct ohci_hcd *ohci, struct ed *ed) { int int_branch, i; int inter, interval, load; __u32 *ed_p; - volatile struct ed *ed = edi; ed->state = ED_OPER; + ed->hwNextED = 0; + wmb (); + + /* we care about rm_list when setting CLE/BLE in case the HC was at + * work on some TD when CLE/BLE was turned off, and isn't quiesced + * yet. finish_unlinks() restarts as needed, some upcoming INTR_SF. + */ 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 - && !ohci->sleeping - ) { + if (!ohci->ed_controltail && !ohci->ed_rm_list) { ohci->hc_control |= OHCI_CTRL_CLE; + writel (0, &ohci->regs->ed_controlcurrent); writel (ohci->hc_control, &ohci->regs->control); } - ohci->ed_controltail = edi; + ohci->ed_controltail = ed; 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 - && !ohci->sleeping - ) { + if (!ohci->ed_bulktail && !ohci->ed_rm_list) { ohci->hc_control |= OHCI_CTRL_BLE; + writel (0, &ohci->regs->ed_bulkcurrent); writel (ohci->hc_control, &ohci->regs->control); } - ohci->ed_bulktail = edi; + ohci->ed_bulktail = ed; break; case PIPE_INTERRUPT: @@ -231,17 +231,16 @@ ed->hwNextED = *ed_p; *ed_p = cpu_to_le32 (ed->dma); } + wmb (); #ifdef OHCI_VERBOSE_DEBUG ohci_dump_periodic (ohci, "LINK_INT"); #endif break; case PIPE_ISOCHRONOUS: - ed->hwNextED = 0; - ed->interval = 1; + ed->ed_prev = ohci->ed_isotail; 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; @@ -251,15 +250,18 @@ inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval); *ed_p = cpu_to_le32 (ed->dma); } - ed->ed_prev = NULL; } - ohci->ed_isotail = edi; + wmb (); + ohci->ed_isotail = ed; #ifdef OHCI_VERBOSE_DEBUG ohci_dump_periodic (ohci, "LINK_ISO"); #endif break; } - return 0; + + /* the HC may not see the schedule updates yet, but if it does + * then they'll be properly ordered. + */ } /*-------------------------------------------------------------------------*/ @@ -288,9 +290,8 @@ * 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 - * caller guarantees the ED has no active TDs. */ -static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) +static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) { int i; @@ -361,15 +362,14 @@ break; } - /* FIXME ED's "unlink" state is indeterminate; - * the HC might still be caching it (till SOF). - * - use ed_rm_list and finish_unlinks(), adding some state that - * prevents clobbering hw linkage before the appropriate SOF - * - a speedup: when only one urb is queued on the ed, save 1msec - * by making start_urb_unlink() use this routine to deschedule. + /* FIXME Except for a couple of exceptionally clean unlink cases + * (like unlinking the only c/b ED, with no TDs) HCs may still be + * caching this (till SOF). + * + * To avoid racing with the hardware, this needs to use ED_UNLINK + * and delay til next INTR_SF. Merge with start_urb_unlink(). */ - ed->state = ED_UNLINK; - return 0; + ed->state = ED_IDLE; } @@ -403,35 +403,27 @@ spin_lock_irqsave (&ohci->lock, flags); if (!(ed = dev->ep [ep])) { + struct td *td; + ed = ed_alloc (ohci, SLAB_ATOMIC); if (!ed) { /* out of memory */ goto done; } dev->ep [ep] = ed; - } - if (ed->state & ED_URB_DEL) { - /* pending unlink request */ - ed = 0; - goto done; - } - - if (ed->state == ED_NEW) { - struct td *td; - - ed->hwINFO = ED_SKIP; /* dummy td; end of td list for ed */ td = td_alloc (ohci, SLAB_ATOMIC); if (!td) { /* out of memory */ + ed_free (ohci, ed); ed = 0; goto done; } ed->dummy = td; ed->hwTailP = cpu_to_le32 (td->td_dma); ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */ - ed->state = ED_UNLINK; + ed->state = ED_IDLE; ed->type = type; } @@ -439,7 +431,7 @@ * state/mode info. Currently the upper layers don't support such * guarantees; we're lucky changing config/altsetting is rare. */ - if (ed->state == ED_UNLINK) { + if (ed->state == ED_IDLE) { u32 info; info = usb_pipedevice (pipe); @@ -494,30 +486,13 @@ /*-------------------------------------------------------------------------*/ /* request unlinking of an endpoint from an operational HC. - * put the ep on the rm_list and stop the bulk or ctrl list + * put the ep on the rm_list * real work is done at the next start frame (SF) hardware interrupt */ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) { - /* already pending? */ - if (ed->state & ED_URB_DEL) - return; - ed->state |= ED_URB_DEL; - - ed->hwINFO |= 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; - } + ed_deschedule (ohci, ed); + ed->state = ED_UNLINK; /* SF interrupt might get delayed; record the frame counter value that * indicates when the HC isn't looking at it, so concurrent unlinks @@ -526,7 +501,7 @@ */ ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1; - ed->ed_rm_list = ohci->ed_rm_list; + ed->ed_next = ohci->ed_rm_list; ohci->ed_rm_list = ed; /* enable SOF interrupt */ @@ -543,12 +518,12 @@ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ static void -td_fill (struct ohci_hcd *ohci, unsigned int info, +td_fill (unsigned int info, dma_addr_t data, int len, struct urb *urb, int index) { struct td *td, *td_pt; - urb_priv_t *urb_priv = urb->hcpriv; + struct urb_priv *urb_priv = urb->hcpriv; int is_iso = info & TD_ISO; if (index >= urb_priv->length) { @@ -607,28 +582,30 @@ /*-------------------------------------------------------------------------*/ -/* 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); +/* Prepare all TDs of a transfer, and queue them onto the ED. + * Caller guarantees HC is active. + * Usually the ED is already on the schedule, so TDs might be + * processed as soon as they're queued. + */ +static void td_submit_urb ( + struct ohci_hcd *ohci, + struct urb *urb +) { + struct urb_priv *urb_priv = urb->hcpriv; dma_addr_t data; int data_len = urb->transfer_buffer_length; - int cnt = 0; - __u32 info = 0; - unsigned int toggle = 0; + int cnt = 0; + u32 info = 0; int is_out = usb_pipeout (urb->pipe); - /* OHCI handles the DATA-toggles itself, we just use the - * USB-toggle bits for resetting + /* OHCI handles the bulk/interrupt data toggles itself. We just + * use the device toggle bits for resetting, and rely on the fact + * that resetting toggle is meaningless if the endpoint is active. */ - if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { - toggle = TD_T_TOGGLE; - } else { - toggle = TD_T_DATA0; + if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out, 1); + urb_priv->ed->hwHeadP &= ~ED_C; } urb_priv->td_cnt = 0; @@ -644,91 +621,88 @@ /* NOTE: TD_CC is set so we can tell which TDs the HC processed by * using TD_CC_GET, as well as by seeing them on the done list. + * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.) */ - switch (usb_pipetype (urb->pipe)) { - case PIPE_BULK: - info = is_out - ? TD_CC | TD_DP_OUT - : TD_CC | TD_DP_IN ; - /* TDs _could_ transfer up to 8K each */ - while (data_len > 4096) { - td_fill (ohci, - info | (cnt? TD_T_TOGGLE:toggle), - data, 4096, urb, cnt); - data += 4096; data_len -= 4096; cnt++; - } - /* maybe avoid ED halt on final TD short read */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - info |= TD_R; - td_fill (ohci, info | (cnt ? TD_T_TOGGLE : toggle), - data, data_len, urb, cnt); + switch (urb_priv->ed->type) { + + /* Bulk and interrupt are identical except for where in the schedule + * their EDs live. + */ + // case PIPE_BULK: + // case PIPE_INTERRUPT: + default: + info = is_out + ? TD_T_TOGGLE | TD_CC | TD_DP_OUT + : TD_T_TOGGLE | TD_CC | TD_DP_IN; + /* TDs _could_ transfer up to 8K each */ + while (data_len > 4096) { + td_fill (info, data, 4096, urb, cnt); + data += 4096; + data_len -= 4096; 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) { - wmb (); - writel (OHCI_BLF, &ohci->regs->cmdstatus); - } - break; + } + /* maybe avoid ED halt on final TD short read */ + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + info |= TD_R; + td_fill (info, data, data_len, urb, cnt); + cnt++; + if ((urb->transfer_flags & USB_ZERO_PACKET) + && cnt < urb_priv->length) { + td_fill (info, 0, 0, urb, cnt); + cnt++; + } + /* maybe kickstart bulk list */ + if (urb_priv->ed->type == PIPE_BULK) { + wmb (); + writel (OHCI_BLF, &ohci->regs->cmdstatus); + } + break; - case PIPE_INTERRUPT: - /* current policy: only one TD per request. - * otherwise identical to bulk, except for BLF - */ - info = TD_CC | toggle; - info |= is_out - ? TD_DP_OUT - : TD_R | TD_DP_IN; - td_fill (ohci, info, data, data_len, urb, cnt++); - break; - - case PIPE_CONTROL: - /* control requests don't use toggle state */ - info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - td_fill (ohci, info, - pci_map_single (ohci->hcd.pdev, - urb->setup_packet, 8, - PCI_DMA_TODEVICE), - 8, urb, cnt++); - if (data_len > 0) { - info = TD_CC | TD_R | TD_T_DATA1; - info |= is_out ? TD_DP_OUT : TD_DP_IN; - /* NOTE: mishandles transfers >8K, some >4K */ - td_fill (ohci, info, data, data_len, - urb, cnt++); - } - info = is_out - ? 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) { - wmb (); - writel (OHCI_CLF, &ohci->regs->cmdstatus); - } - break; + /* control manages DATA0/DATA1 toggle per-request; SETUP resets it, + * any DATA phase works normally, and the STATUS ack is special. + */ + case PIPE_CONTROL: + info = TD_CC | TD_DP_SETUP | TD_T_DATA0; + td_fill (info, + pci_map_single (ohci->hcd.pdev, + urb->setup_packet, 8, + PCI_DMA_TODEVICE), + 8, urb, cnt++); + if (data_len > 0) { + info = TD_CC | TD_R | TD_T_DATA1; + info |= is_out ? TD_DP_OUT : TD_DP_IN; + /* NOTE: mishandles transfers >8K, some >4K */ + td_fill (info, data, data_len, urb, cnt++); + } + info = is_out + ? TD_CC | TD_DP_IN | TD_T_DATA1 + : TD_CC | TD_DP_OUT | TD_T_DATA1; + td_fill (info, data, 0, urb, cnt++); + /* maybe kickstart control list */ + wmb (); + writel (OHCI_CLF, &ohci->regs->cmdstatus); + break; - case PIPE_ISOCHRONOUS: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { - int frame = urb->start_frame; - - // FIXME scheduling should handle frame counter - // roll-around ... exotic case (and OHCI has - // a 2^16 iso range, vs other HCs max of 2^10) - frame += cnt * urb->interval; - frame &= 0xffff; - td_fill (ohci, TD_CC | TD_ISO | frame, - data + urb->iso_frame_desc [cnt].offset, - urb->iso_frame_desc [cnt].length, urb, cnt); - } - break; - } - if (urb_priv->length != cnt) + /* ISO has no retransmit, so no toggle; and it uses special TDs. + * Each TD could handle multiple consecutive frames (interval 1); + * we could often reduce the number of TDs here. + */ + case PIPE_ISOCHRONOUS: + for (cnt = 0; cnt < urb->number_of_packets; cnt++) { + int frame = urb->start_frame; + + // FIXME scheduling should handle frame counter + // roll-around ... exotic case (and OHCI has + // a 2^16 iso range, vs other HCs max of 2^10) + frame += cnt * urb->interval; + frame &= 0xffff; + td_fill (TD_CC | TD_ISO | frame, + 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); } @@ -744,13 +718,17 @@ u32 tdINFO = le32_to_cpup (&td->hwINFO); int cc = 0; - /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { u16 tdPSW = le16_to_cpu (td->hwPSW [0]); int dlen = 0; + /* NOTE: assumes FC in tdINFO == 0 (and MAXPSW == 1) */ + cc = (tdPSW >> 12) & 0xF; + if (tdINFO & TD_CC) /* hc didn't touch? */ + return; + if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; else @@ -759,9 +737,11 @@ urb->iso_frame_desc [td->index].actual_length = dlen; urb->iso_frame_desc [td->index].status = cc_to_error [cc]; - if (cc != 0) +#ifdef VERBOSE_DEBUG + if (cc != TD_CC_NOERROR) dbg (" urb %p iso TD %p (%d) len %d CC %d", urb, td, 1 + td->index, dlen, cc); +#endif /* BULK, INT, CONTROL ... drivers see aggregate length/status, * except that "setup" bytes aren't counted and "short" transfers @@ -783,7 +763,7 @@ if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR) { + if (cc != TD_CC_NOERROR && cc < 0x0E) { spin_lock (&urb->lock); if (urb->status == -EINPROGRESS) urb->status = cc_to_error [cc]; @@ -801,7 +781,7 @@ } #ifdef VERBOSE_DEBUG - if (cc != 0) + if (cc != TD_CC_NOERROR && cc < 0x0E) dbg (" urb %p TD %p (%d) CC %d, len=%d/%d", urb, td, 1 + td->index, cc, urb->actual_length, @@ -876,28 +856,39 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick) { struct ed *ed, **last; - int ctrl = 0, bulk = 0; +rescan_all: for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) { struct td *td, *td_next, *tdHeadP, *tdTailP; u32 *td_p; - int unlinked; + int completed, modified; /* only take off EDs that the HC isn't using, accounting for - * frame counter wraps. completion callbacks might prepend - * EDs to the list, they'll be checked next irq. + * frame counter wraps. */ - if (tick_before (tick, ed->tick)) { - last = &ed->ed_rm_list; + if (tick_before (tick, ed->tick) && !ohci->disabled) { + last = &ed->ed_next; continue; } - *last = ed->ed_rm_list; - ed->ed_rm_list = 0; - unlinked = 0; - /* unlink urbs from first one requested to queue end; - * leave earlier urbs alone + /* reentrancy: if we drop the schedule lock, someone might + * have modified this list. normally it's just prepending + * entries (which we'd ignore), but paranoia won't hurt. + */ + *last = ed->ed_next; + ed->ed_next = 0; + modified = 0; + + /* unlink urbs as requested, but rescan the list after + * we call a completion since it might have unlinked + * another (earlier) urb + * + * FIXME use td_list to scan, not ed hashtables. + * completely abolish ed hashtables! */ +rescan_this: + completed = 0; + tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP)); tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP)); td_p = &ed->hwHeadP; @@ -908,21 +899,18 @@ td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD)); - if (unlinked || (urb_priv->state == URB_DEL)) { - u32 tdINFO = le32_to_cpup (&td->hwINFO); - - unlinked = 1; + if (urb_priv->state == URB_DEL) { /* HC may have partly processed this TD */ - if (TD_CC_GET (tdINFO) < 0xE) - td_done (urb, td); + td_done (urb, td); + urb_priv->td_cnt++; + *td_p = td->hwNextTD | (*td_p & __constant_cpu_to_le32 (0x3)); /* URB is done; clean up */ - if (++ (urb_priv->td_cnt) == urb_priv->length) { - if (urb->status == -EINPROGRESS) - urb->status = -ECONNRESET; + if (urb_priv->td_cnt == urb_priv->length) { + modified = completed = 1; spin_unlock (&ohci->lock); finish_urb (ohci, urb); spin_lock (&ohci->lock); @@ -932,49 +920,52 @@ } } - /* FIXME actually want four cases here: - * (a) finishing URB unlink - * [a1] no URBs queued, so start ED unlink - * [a2] some (earlier) URBs still linked, re-enable - * (b) finishing ED unlink - * [b1] no URBs queued, ED is truly idle now - * ... we could set state ED_NEW and free dummy - * [b2] URBs now queued, link ED back into schedule - * right now we only have (a) - */ - ed->state &= ~ED_URB_DEL; - tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP)); + /* ED's now officially unlinked, hc doesn't see */ + ed->state = ED_IDLE; + ed->hwINFO &= ~ED_SKIP; + ed->hwHeadP &= ~cpu_to_le32 (ED_H); + ed->hwNextED = 0; - if (tdHeadP == tdTailP) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - } else - ed->hwINFO &= ~ED_SKIP; - - switch (ed->type) { - case PIPE_CONTROL: - ctrl = 1; - break; - case PIPE_BULK: - bulk = 1; - break; + /* but if there's work queued, reschedule */ + tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP)); + if (tdHeadP != tdTailP) { + if (completed) + goto rescan_this; + if (!ohci->disabled && !ohci->sleeping) + ed_schedule (ohci, ed); } + + if (modified) + goto rescan_all; } /* 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) { - 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); - } - } + if (!ohci->disabled && !ohci->ed_rm_list) { + u32 command = 0, control = 0; + + if (ohci->ed_controltail) { + command |= OHCI_CLF; + if (!(ohci->hc_control & OHCI_CTRL_CLE)) { + control |= OHCI_CTRL_CLE; + writel (0, &ohci->regs->ed_controlcurrent); + } + } + if (ohci->ed_bulktail) { + command |= OHCI_BLF; + if (!(ohci->hc_control & OHCI_CTRL_BLE)) { + control |= OHCI_CTRL_BLE; + writel (0, &ohci->regs->ed_bulkcurrent); + } + } + + /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ + if (control) { + ohci->hc_control |= control; + writel (ohci->hc_control, &ohci->regs->control); + } + if (command) + writel (command, &ohci->regs->cmdstatus); + } } @@ -1026,7 +1017,7 @@ if ((ed->hwHeadP & __constant_cpu_to_le32 (TD_MASK)) == ed->hwTailP && (ed->state == ED_OPER)) - start_ed_unlink (ohci, ed); + ed_deschedule (ohci, ed); td = td_next; } spin_unlock_irqrestore (&ohci->lock, flags); diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h --- a/drivers/usb/host/ohci.h Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/host/ohci.h Fri Jul 26 19:58:52 2002 @@ -31,15 +31,21 @@ /* rest are purely for the driver's use */ dma_addr_t dma; /* addr of ED */ + struct td *dummy; /* next TD to activate */ + + /* host's view of schedule */ + struct ed *ed_next; /* on schedule or rm_list */ struct ed *ed_prev; /* for non-interrupt EDs */ - struct td *dummy; struct list_head td_list; /* "shadow list" of our TDs */ - u8 state; /* ED_{NEW,UNLINK,OPER} */ -#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 /* for unlinking; masked in */ + /* create --> IDLE --> OPER --> ... --> IDLE --> destroy + * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... + * some special cases : OPER --> IDLE ... + */ + u8 state; /* ED_{IDLE,UNLINK,OPER} */ +#define ED_IDLE 0x00 /* NOT linked to HC */ +#define ED_UNLINK 0x01 /* being unlinked from hc */ +#define ED_OPER 0x02 /* IS linked to hc */ u8 type; /* PIPE_{BULK,...} */ u16 interval; /* interrupt, isochronous */ @@ -53,7 +59,6 @@ /* HC may see EDs on rm_list until next frame (frame_no == tick) */ u16 tick; - struct ed *ed_rm_list; } __attribute__ ((aligned(16))); #define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ @@ -396,5 +401,5 @@ struct usb_hcd hcd; }; -#define hcd_to_ohci(hcd_ptr) list_entry(hcd_ptr, struct ohci_hcd, hcd) +#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd) diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h --- a/drivers/usb/image/scanner.h Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/image/scanner.h Fri Jul 26 19:58:51 2002 @@ -93,9 +93,12 @@ { USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */ { USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */ /* Canon */ - { USB_DEVICE(0x04a9, 0x2202) }, /* FB620U */ + { USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */ + { USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */ + { USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */ + { USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */ + { USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */ { USB_DEVICE(0x04a9, 0x220b) }, /* D646U */ - { USB_DEVICE(0x04a9, 0x2207) }, /* 1220U */ /* Colorado -- See Primax/Colorado below */ /* Epson -- See Seiko/Epson below */ /* Genius */ diff -Nru a/drivers/usb/input/Config.help b/drivers/usb/input/Config.help --- a/drivers/usb/input/Config.help Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/input/Config.help Fri Jul 26 19:58:52 2002 @@ -18,27 +18,34 @@ CONFIG_USB_HIDINPUT Say Y here if you want to use a USB keyboard, mouse or joystick, - or any other HID input device. You also need Input layer support, - (CONFIG_INPUT) which you select under "Input core support". + or any other HID input device. You also need "Input core support", + (CONFIG_INPUT), which you select under "Input device support", above. If unsure, say Y. CONFIG_HID_FF - Say Y here is you want force feedback support for a few hid devices. See + Say Y here is you want force feedback support for a few HID devices. See below for a list of supported devices. See Documentation/input/ff.txt for a description of the force feedback API. If unsure, say N. -CONFIG_LOGITECH_RUMBLE - Say Y here if you have a Logitech WingMan Cordless rumble pad and if you - want to enable force feedback. Note: if you say N here, this device will - still be supported, but without force feedback. +CONFIG_LOGITECH_FF + Say Y here if you have one of these devices: + - Logitech WingMan Cordless RumblePad + - Logitech WingMan Force 3D + and if you want to enable force feedback for them. + Note: if you say N here, this device will still be supported, but without + force feedback. CONFIG_HID_PID - Say Y yes if you have a PID-compliant joystick and wish to enable force + Say Y here if you have a PID-compliant joystick and wish to enable force feedback for it. The Microsoft Sidewinder Force Feedback 2 is one such device. + +CONFIG_LOGITECH_3D + Say Y here if you have a Logitech force feedback device from the + *3D family. CONFIG_USB_HIDDEV Say Y here if you want to support HID devices (from the USB diff -Nru a/drivers/usb/input/Config.in b/drivers/usb/input/Config.in --- a/drivers/usb/input/Config.in Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/input/Config.in Fri Jul 26 19:58:52 2002 @@ -11,8 +11,7 @@ dep_mbool ' HID input layer support' CONFIG_USB_HIDINPUT $CONFIG_INPUT $CONFIG_USB_HID dep_mbool ' Force feedback support (EXPERIMENTAL)' CONFIG_HID_FF $CONFIG_USB_HIDINPUT $CONFIG_EXPERIMENTAL dep_mbool ' PID Devices' CONFIG_HID_PID $CONFIG_USB_HID $CONFIG_HID_FF -dep_mbool ' Logitech RumblePad support' CONFIG_LOGITECH_RUMBLE $CONFIG_USB_HID $CONFIG_HID_FF -dep_mbool ' Logitech WingMan Force 3D support' CONFIG_LOGITECH_3D $CONFIG_USB_HID $CONFIG_HID_FF +dep_mbool ' Logitech WingMan *3D support' CONFIG_LOGITECH_FF $CONFIG_USB_HID $CONFIG_HID_FF dep_mbool ' /dev/hiddev raw HID device support' CONFIG_USB_HIDDEV $CONFIG_USB_HID if [ "$CONFIG_USB_HID" != "y" ]; then diff -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile --- a/drivers/usb/input/Makefile Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/input/Makefile Fri Jul 26 19:58:50 2002 @@ -16,11 +16,8 @@ ifeq ($(CONFIG_HID_PID),y) hid-objs += pid.o endif -ifeq ($(CONFIG_LOGITECH_RUMBLE),y) +ifeq ($(CONFIG_LOGITECH_FF),y) hid-objs += hid-lgff.o -endif -ifeq ($(CONFIG_LOGITECH_3D),y) - hid-objs += hid-lg3dff.o endif ifeq ($(CONFIG_HID_FF),y) hid-objs += hid-ff.o diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/aiptek.c Fri Jul 26 19:58:51 2002 @@ -161,6 +161,8 @@ input_report_key(dev, BTN_STYLUS2, data[5] & 0x10); } + input_sync(dev); + } struct aiptek_features aiptek_features[] = { @@ -277,10 +279,10 @@ aiptek->dev.close = aiptek_close; aiptek->dev.name = aiptek->features->name; - aiptek->dev.idbus = BUS_USB; - aiptek->dev.idvendor = dev->descriptor.idVendor; - aiptek->dev.idproduct = dev->descriptor.idProduct; - aiptek->dev.idversion = dev->descriptor.bcdDevice; + aiptek->dev.id.bustype = BUS_USB; + aiptek->dev.id.vendor = dev->descriptor.idVendor; + aiptek->dev.id.product = dev->descriptor.idProduct; + aiptek->dev.id.version = dev->descriptor.bcdDevice; aiptek->usbdev = dev; endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; diff -Nru a/drivers/usb/input/fixp-arith.h b/drivers/usb/input/fixp-arith.h --- a/drivers/usb/input/fixp-arith.h Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/fixp-arith.h Fri Jul 26 19:58:51 2002 @@ -66,7 +66,13 @@ inline fixp_t fixp_cos(unsigned int degrees) { int quadrant = (degrees / 90) & 3; - unsigned int i = (degrees % 90) >> 1; + unsigned int i = degrees % 90; + + if (quadrant == 1 || quadrant == 3) { + i = 89 - i; + } + + i >>= 1; return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i]; } diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/hid-core.c Fri Jul 26 19:58:51 2002 @@ -903,6 +903,9 @@ for (n = 0; n < report->maxfield; n++) hid_input_field(hid, report->field[n], data); + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_report_event(hid, report); + return 0; } @@ -1278,10 +1281,8 @@ usb_unlink_urb(hid->urbout); } - if (err) { + if (err) warn("timeout initializing reports\n"); - return; - } report_enum = hid->report_enum + HID_INPUT_REPORT; list = report_enum->report_list.next; @@ -1548,8 +1549,8 @@ } static struct usb_device_id hid_usb_ids [] = { - { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass: USB_INTERFACE_CLASS_HID }, + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_INTERFACE_CLASS_HID }, { } /* Terminating entry */ }; diff -Nru a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c --- a/drivers/usb/input/hid-ff.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/hid-ff.c Fri Jul 26 19:58:51 2002 @@ -1,5 +1,5 @@ /* - * $Id: hid-ff.c,v 1.3 2002/06/09 11:06:38 jdeneux Exp $ + * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $ * * Force feedback support for hid devices. * Not all hid devices use the same protocol. For example, some use PID, @@ -44,17 +44,15 @@ * devices, you need to add the USB vendor and product ids here. */ struct hid_ff_initializer { - __u16 idVendor; - __u16 idProduct; + u16 idVendor; + u16 idProduct; int (*init)(struct hid_device*); }; static struct hid_ff_initializer inits[] = { -#ifdef CONFIG_LOGITECH_RUMBLE +#ifdef CONFIG_LOGITECH_FF {0x46d, 0xc211, hid_lgff_init}, -#endif -#ifdef CONFIG_LOGITECH_3D - {0x46d, 0xc283, hid_lg3d_init}, + {0x46d, 0xc283, hid_lgff_init}, #endif #ifdef CONFIG_HID_PID {0x45e, 0x001b, hid_pid_init}, @@ -68,8 +66,8 @@ struct hid_ff_initializer *init; for (init = inits; init->idVendor - && !(init->idVendor == idVendor - && init->idProduct == idProduct); + && !(init->idVendor == idVendor + && init->idProduct == idProduct); init++); return init->idVendor? init : NULL; diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c --- a/drivers/usb/input/hid-input.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/hid-input.c Fri Jul 26 19:58:51 2002 @@ -428,6 +428,11 @@ input_event(input, usage->type, usage->code, 0); } +void hidinput_report_event(struct hid_device *hid, struct hid_report *report) +{ + input_sync(&hid->input); +} + static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct hid_device *hid = dev->private; @@ -490,10 +495,10 @@ hid->input.name = hid->name; hid->input.phys = hid->phys; hid->input.uniq = hid->uniq; - hid->input.idbus = BUS_USB; - hid->input.idvendor = dev->descriptor.idVendor; - hid->input.idproduct = dev->descriptor.idProduct; - hid->input.idversion = dev->descriptor.bcdDevice; + hid->input.id.bustype = BUS_USB; + hid->input.id.vendor = dev->descriptor.idVendor; + hid->input.id.product = dev->descriptor.idProduct; + hid->input.id.version = dev->descriptor.bcdDevice; for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { report_enum = hid->report_enum + k; diff -Nru a/drivers/usb/input/hid-lg3dff.c b/drivers/usb/input/hid-lg3dff.c --- a/drivers/usb/input/hid-lg3dff.c Fri Jul 26 19:58:50 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,444 +0,0 @@ -/* - * $$ - * - * Force feedback support for hid-compliant devices of the Logitech *3D family - * - * Copyright (c) 2002 Johann Deneux - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so by - * e-mail - mail your message to - */ - -#include -#include - -#define DEBUG -#include - -#include - -#include "hid.h" -#include "fixp-arith.h" - -#define RUN_AT(t) (jiffies + (t)) - -/* Periodicity of the update */ -#define PERIOD (HZ/10) - -/* Effect status: lg3d_effect::flags */ -#define EFFECT_STARTED 0 /* Effect is going to play after some time - (ff_replay.delay) */ -#define EFFECT_PLAYING 1 /* Effect is being played */ -#define EFFECT_USED 2 - -/* Check that the current process can access an effect */ -#define CHECK_OWNERSHIP(i, l) \ - (i>=0 && ieffects[i].flags) \ - && (current->pid == 0 \ - || l->effects[i].owner == current->pid)) - -#define N_EFFECTS 8 - -struct lg3d_effect { - pid_t owner; - - struct ff_effect effect; /* Description of the effect */ - - unsigned int count; /* Number of times left to play */ - unsigned long flags[1]; - - unsigned long started_at; /* When the effect started to play */ -}; - -// For lg3d_device::flags -#define DEVICE_USB_XMIT 0 /* An URB is being sent */ -#define DEVICE_CLOSING 1 /* The driver is being unitialised */ - -struct lg3d_device { - struct hid_device* hid; - - struct urb* urbffout; /* Output URB used to send ff commands */ - struct usb_ctrlrequest ffcr; /* ff commands use control URBs */ - char buf[8]; - - struct lg3d_effect effects[N_EFFECTS]; - spinlock_t lock; /* device-level lock. Having locks on - a per-effect basis could be nice, but - isn't really necessary */ - struct timer_list timer; - unsigned long last_time; /* Last time the timer handler was - executed */ - - unsigned long flags[1]; /* Contains various information about the - state of the driver for this device */ -}; - -static void hid_lg3d_ctrl_out(struct urb *urb); -static void hid_lg3d_exit(struct hid_device* hid); -static int hid_lg3d_event(struct hid_device *hid, struct input_dev *input, - unsigned int type, unsigned int code, int value); -static int hid_lg3d_flush(struct input_dev *input, struct file *file); -static int hid_lg3d_upload_effect(struct input_dev *input, - struct ff_effect *effect); -static int hid_lg3d_erase(struct input_dev *input, int id); -static void hid_lg3d_timer(unsigned long timer_data); - - -int hid_lg3d_init(struct hid_device* hid) -{ - struct lg3d_device *private; - - /* Private data */ - private = kmalloc(sizeof(struct lg3d_device), GFP_KERNEL); - if (!private) return -1; - - memset(private, 0, sizeof(struct lg3d_device)); - - hid->ff_private = private; - - private->hid = hid; - spin_lock_init(&private->lock); - - /* Timer for the periodic update task */ - init_timer(&private->timer); - private->timer.data = (unsigned long)private; - private->timer.function = hid_lg3d_timer; - - /* Event and exit callbacks */ - hid->ff_exit = hid_lg3d_exit; - hid->ff_event = hid_lg3d_event; - - /* USB init */ - if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) { - kfree(hid->ff_private); - return -1; - } - - usb_fill_control_urb(private->urbffout, hid->dev, 0, - (void*) &private->ffcr, private->buf, 8, - hid_lg3d_ctrl_out, hid); - dbg("Created ff output control urb"); - - /* Input init */ - hid->input.upload_effect = hid_lg3d_upload_effect; - hid->input.flush = hid_lg3d_flush; - set_bit(FF_CONSTANT, hid->input.ffbit); - set_bit(EV_FF, hid->input.evbit); - hid->input.ff_effects_max = N_EFFECTS; - - printk(KERN_INFO "Force feedback for Logitech *3D devices by Johann Deneux \n"); - - /* Start the update task */ - private->timer.expires = RUN_AT(PERIOD); - add_timer(&private->timer); /*TODO: only run the timer when at least - one effect is playing */ - - return 0; -} - -static void hid_lg3d_exit(struct hid_device* hid) -{ - struct lg3d_device *lg3d = hid->ff_private; - unsigned long flags; - - spin_lock_irqsave(&lg3d->lock, flags); - set_bit(DEVICE_CLOSING, lg3d->flags); - spin_unlock_irqrestore(&lg3d->lock, flags); - - del_timer_sync(&lg3d->timer); - - if (lg3d->urbffout) { - usb_unlink_urb(lg3d->urbffout); - usb_free_urb(lg3d->urbffout); - } - - kfree(lg3d); -} - -static int hid_lg3d_event(struct hid_device *hid, struct input_dev* input, - unsigned int type, unsigned int code, int value) -{ - struct lg3d_device *lg3d = hid->ff_private; - struct lg3d_effect *effect = lg3d->effects + code; - unsigned long flags; - - if (type != EV_FF) return -EINVAL; - if (!CHECK_OWNERSHIP(code, lg3d)) return -EACCES; - if (value < 0) return -EINVAL; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (value > 0) { - if (test_bit(EFFECT_STARTED, effect->flags)) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -EBUSY; - } - if (test_bit(EFFECT_PLAYING, effect->flags)) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -EBUSY; - } - - effect->count = value; - - if (effect->effect.replay.delay) { - set_bit(EFFECT_STARTED, effect->flags); - } else { - set_bit(EFFECT_PLAYING, effect->flags); - } - effect->started_at = jiffies; - } - else { /* value == 0 */ - clear_bit(EFFECT_STARTED, effect->flags); - clear_bit(EFFECT_PLAYING, effect->flags); - } - - spin_unlock_irqrestore(&lg3d->lock, flags); - - return 0; -} - -/* Erase all effects this process owns */ -static int hid_lg3d_flush(struct input_dev *dev, struct file *file) -{ - struct hid_device *hid = dev->private; - struct lg3d_device *lg3d = hid->ff_private; - int i; - - for (i=0; iff_effects_max; ++i) { - - /*NOTE: no need to lock here. The only times EFFECT_USED is - modified is when effects are uploaded or when an effect is - erased. But a process cannot close its dev/input/eventX fd - and perform ioctls on the same fd all at the same time */ - if ( current->pid == lg3d->effects[i].owner - && test_bit(EFFECT_USED, lg3d->effects[i].flags)) { - - if (hid_lg3d_erase(dev, i)) - warn("erase effect %d failed", i); - } - - } - - return 0; -} - -static int hid_lg3d_erase(struct input_dev *dev, int id) -{ - struct hid_device *hid = dev->private; - struct lg3d_device *lg3d = hid->ff_private; - unsigned long flags; - - if (!CHECK_OWNERSHIP(id, lg3d)) return -EACCES; - - spin_lock_irqsave(&lg3d->lock, flags); - lg3d->effects[id].flags[0] = 0; - spin_unlock_irqrestore(&lg3d->lock, flags); - - return 0; -} - -static int hid_lg3d_upload_effect(struct input_dev* input, - struct ff_effect* effect) -{ - struct hid_device *hid = input->private; - struct lg3d_device *lg3d = hid->ff_private; - struct lg3d_effect new; - int id; - unsigned long flags; - - dbg("ioctl upload"); - - if (!test_bit(effect->type, input->ffbit)) return -EINVAL; - - if (effect->type != FF_CONSTANT) return -EINVAL; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (effect->id == -1) { - int i; - - for (i=0; ieffects[i].flags); ++i); - if (i >= N_EFFECTS) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -ENOSPC; - } - - effect->id = i; - lg3d->effects[i].owner = current->pid; - lg3d->effects[i].flags[0] = 0; - set_bit(EFFECT_USED, lg3d->effects[i].flags); - } - else if (!CHECK_OWNERSHIP(effect->id, lg3d)) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -EACCES; - } - - id = effect->id; - new = lg3d->effects[id]; - - new.effect = *effect; - new.effect.replay = effect->replay; - - if (test_bit(EFFECT_STARTED, lg3d->effects[id].flags) - || test_bit(EFFECT_STARTED, lg3d->effects[id].flags)) { - - /* Changing replay parameters is not allowed (for the time - being) */ - if (new.effect.replay.delay != lg3d->effects[id].effect.replay.delay - || new.effect.replay.length != lg3d->effects[id].effect.replay.length) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -ENOSYS; - } - - lg3d->effects[id] = new; - - } else { - lg3d->effects[id] = new; - } - - spin_unlock_irqrestore(&lg3d->lock, flags); - return 0; -} - -static void hid_lg3d_ctrl_out(struct urb *urb) -{ - struct hid_device *hid = urb->context; - struct lg3d_device *lg3d = hid->ff_private; - unsigned long flags; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (urb->status) - warn("hid_irq_ffout status %d received", urb->status); - clear_bit(DEVICE_USB_XMIT, lg3d->flags); - dbg("xmit = 0"); - - spin_unlock_irqrestore(&lg3d->lock, flags); -} - -static void hid_lg3d_timer(unsigned long timer_data) -{ - struct lg3d_device *lg3d = (struct lg3d_device*)timer_data; - struct hid_device *hid = lg3d->hid; - unsigned long flags; - int x, y; - int i; - int err; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (test_bit(DEVICE_USB_XMIT, lg3d->flags)) { - if (lg3d->urbffout->status != -EINPROGRESS) { - warn("xmit *not* in progress"); - } - else { - dbg("xmit in progress"); - } - - spin_unlock_irqrestore(&lg3d->lock, flags); - - lg3d->timer.expires = RUN_AT(PERIOD); - add_timer(&lg3d->timer); - - return; - } - - x = 0x7f; - y = 0x7f; - - for (i=0; ieffects +i; - - if (test_bit(EFFECT_PLAYING, effect->flags)) { - - if (effect->effect.type == FF_CONSTANT) { - //TODO: handle envelopes - int degrees = effect->effect.direction * 360 >> 16; - x += fixp_mult(fixp_sin(degrees), - fixp_new16(effect->effect.u.constant.level)); - y += fixp_mult(-fixp_cos(degrees), - fixp_new16(effect->effect.u.constant.level)); - } - - /* One run of the effect is finished playing */ - if (time_after(jiffies, - effect->started_at - + effect->effect.replay.delay*HZ/1000 - + effect->effect.replay.length*HZ/1000)) { - dbg("Finished playing once"); - if (--effect->count <= 0) { - dbg("Stopped"); - clear_bit(EFFECT_PLAYING, effect->flags); - } - else { - dbg("Start again"); - if (effect->effect.replay.length != 0) { - clear_bit(EFFECT_PLAYING, effect->flags); - set_bit(EFFECT_STARTED, effect->flags); - } - effect->started_at = jiffies; - } - } - - } else if (test_bit(EFFECT_STARTED, lg3d->effects[i].flags)) { - dbg("Started"); - /* Check if we should start playing the effect */ - if (time_after(jiffies, - lg3d->effects[i].started_at - + lg3d->effects[i].effect.replay.delay*HZ/1000)) { - dbg("Now playing"); - clear_bit(EFFECT_STARTED, lg3d->effects[i].flags); - set_bit(EFFECT_PLAYING, lg3d->effects[i].flags); - } - } - } - - if (x < 0) x = 0; - if (x > 0xff) x = 0xff; - if (y < 0) y = 0; - if (y > 0xff) y = 0xff; - - lg3d->urbffout->pipe = usb_sndctrlpipe(hid->dev, 0); - lg3d->ffcr.bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE; - lg3d->urbffout->transfer_buffer_length = lg3d->ffcr.wLength = 8; - lg3d->ffcr.bRequest = 9; - lg3d->ffcr.wValue = 0x0200; /*NOTE: Potential problem with - little/big endian */ - lg3d->ffcr.wIndex = 0; - - lg3d->urbffout->dev = hid->dev; - - lg3d->buf[0] = 0x51; - lg3d->buf[1] = 0x08; - lg3d->buf[2] = x; - lg3d->buf[3] = y; - - if ((err=usb_submit_urb(lg3d->urbffout, GFP_ATOMIC))) - warn("usb_submit_urb returned %d", err); - else - set_bit(DEVICE_USB_XMIT, lg3d->flags); - - if (!test_bit(DEVICE_CLOSING, lg3d->flags)) { - lg3d->timer.expires = RUN_AT(PERIOD); - add_timer(&lg3d->timer); - } - - spin_unlock_irqrestore(&lg3d->lock, flags); -} diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c --- a/drivers/usb/input/hid-lgff.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/input/hid-lgff.c Fri Jul 26 19:58:52 2002 @@ -4,6 +4,7 @@ * Force feedback support for hid-compliant for some of the devices from * Logitech, namely: * - WingMan Cordless RumblePad + * - WingMan Force 3D * * Copyright (c) 2002 Johann Deneux */ @@ -36,6 +37,11 @@ #include #include "hid.h" +#include "fixp-arith.h" + + +/* Periodicity of the update */ +#define PERIOD (HZ/10) #define RUN_AT(t) (jiffies + (t)) @@ -48,145 +54,243 @@ #define EFFECT_PLAYING 1 /* Effect is being played */ #define EFFECT_USED 2 +// For lgff_device::flags +#define DEVICE_CLOSING 0 /* The driver is being unitialised */ + /* Check that the current process can access an effect */ #define CHECK_OWNERSHIP(effect) (current->pid == 0 \ || effect.owner == current->pid) -/* **************************************************************************/ -/* Implements the protocol used by the Logitech WingMan Cordless RumblePad */ -/* **************************************************************************/ - #define LGFF_CHECK_OWNERSHIP(i, l) \ (i>=0 && ieffects[i].flags) \ && CHECK_OWNERSHIP(l->effects[i])) -#define LGFF_BUFFER_SIZE 64 #define LGFF_EFFECTS 8 -struct lgff_magnitudes { - unsigned char left; - unsigned char right; +struct device_type { + u16 idVendor; + u16 idProduct; + signed short *ff; }; struct lgff_effect { - int id; - struct hid_ff_logitech* lgff; - pid_t owner; - unsigned char left; /* Magnitude of vibration for left motor */ - unsigned char right; /* Magnitude of vibration for right motor */ - struct ff_replay replay; - unsigned int count; /* Number of times to play */ - struct timer_list timer; + + struct ff_effect effect; + unsigned long flags[1]; + unsigned int count; /* Number of times left to play */ + unsigned long started_at; /* When the effect started to play */ }; -struct hid_ff_logitech { +struct lgff_device { struct hid_device* hid; - struct urb* urbffout; /* Output URB used to send ff commands */ - struct usb_ctrlrequest ffcr; /* ff commands use control URBs */ - char buf[8]; - - spinlock_t xmit_lock; - unsigned int xmit_head, xmit_tail; - struct lgff_magnitudes xmit_data[LGFF_BUFFER_SIZE]; - long xmit_flags[1]; + struct hid_report* constant; + struct hid_report* rumble; + struct hid_report* condition; struct lgff_effect effects[LGFF_EFFECTS]; spinlock_t lock; /* device-level lock. Having locks on a per-effect basis could be nice, but isn't really necessary */ + + unsigned long flags[1]; /* Contains various information about the + state of the driver for this device */ + + struct timer_list timer; }; -static void hid_lgff_ctrl_out(struct urb *urb); +/* Callbacks */ static void hid_lgff_exit(struct hid_device* hid); static int hid_lgff_event(struct hid_device *hid, struct input_dev *input, unsigned int type, unsigned int code, int value); -static void hid_lgff_make_rumble(struct hid_device* hid); - static int hid_lgff_flush(struct input_dev *input, struct file *file); static int hid_lgff_upload_effect(struct input_dev *input, struct ff_effect *effect); static int hid_lgff_erase(struct input_dev *input, int id); -static void hid_lgff_ctrl_playback(struct hid_device* hid, struct lgff_effect*, - int play); + +/* Local functions */ +static void hid_lgff_input_init(struct hid_device* hid); static void hid_lgff_timer(unsigned long timer_data); +static struct hid_report* hid_lgff_duplicate_report(struct hid_report*); +static void hid_lgff_delete_report(struct hid_report*); + +static signed short ff_rumble[] = { + FF_RUMBLE, + -1 +}; + +static signed short ff_joystick[] = { + FF_CONSTANT, + -1 +}; +static struct device_type devices[] = { + {0x046d, 0xc211, ff_rumble}, + {0x046d, 0xc283, ff_joystick}, + {0x0000, 0x0000, ff_joystick} +}; int hid_lgff_init(struct hid_device* hid) { - struct hid_ff_logitech *private; - int i; + struct lgff_device *private; + struct hid_report* report; + struct hid_field* field; + + /* Find the report to use */ + if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) { + err("No output report found"); + return -1; + } + /* Check that the report looks ok */ + report = (struct hid_report*)hid->report_enum[HID_OUTPUT_REPORT].report_list.next; + if (!report) { + err("NULL output report"); + return -1; + } + field = report->field[0]; + if (!field) { + err("NULL field"); + return -1; + } - /* Private data */ - private = kmalloc(sizeof(struct hid_ff_logitech), GFP_KERNEL); + private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL); if (!private) return -1; - - memset(private, 0, sizeof(struct hid_ff_logitech)); - + memset(private, 0, sizeof(struct lgff_device)); hid->ff_private = private; - private->hid = hid; - spin_lock_init(&private->lock); - spin_lock_init(&private->xmit_lock); + /* Input init */ + hid_lgff_input_init(hid); + - private->buf[0] = 0x03; - private->buf[1] = 0x42; + private->constant = hid_lgff_duplicate_report(report); + if (!private->constant) { + kfree(private); + return -1; + } + private->constant->field[0]->value[0] = 0x51; + private->constant->field[0]->value[1] = 0x08; + private->constant->field[0]->value[2] = 0x7f; + private->constant->field[0]->value[3] = 0x7f; + + private->rumble = hid_lgff_duplicate_report(report); + if (!private->rumble) { + hid_lgff_delete_report(private->constant); + kfree(private); + return -1; + } + private->rumble->field[0]->value[0] = 0x03; + private->rumble->field[0]->value[1] = 0x42; - for (i=0; ieffects[i]; - struct timer_list* timer = &effect->timer; - init_timer(timer); - effect->id = i; - effect->lgff = private; - timer->data = (unsigned long)effect; - timer->function = hid_lgff_timer; + private->condition = hid_lgff_duplicate_report(report); + if (!private->condition) { + hid_lgff_delete_report(private->rumble); + hid_lgff_delete_report(private->constant); + kfree(private); + return -1; } + private->hid = hid; + + spin_lock_init(&private->lock); + init_timer(&private->timer); + private->timer.data = (unsigned long)private; + private->timer.function = hid_lgff_timer; + /* Event and exit callbacks */ hid->ff_exit = hid_lgff_exit; hid->ff_event = hid_lgff_event; - /* USB init */ - if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) { - kfree(hid->ff_private); - return -1; + /* Start the update task */ + private->timer.expires = RUN_AT(PERIOD); + add_timer(&private->timer); /*TODO: only run the timer when at least + one effect is playing */ + + printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux \n"); + + return 0; +} + +static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report) +{ + struct hid_report* ret; + + ret = kmalloc(sizeof(struct lgff_device), GFP_KERNEL); + if (!ret) return NULL; + *ret = *report; + + ret->field[0] = kmalloc(sizeof(struct hid_field), GFP_KERNEL); + if (!ret->field[0]) { + kfree(ret); + return NULL; } + *ret->field[0] = *report->field[0]; - usb_fill_control_urb(private->urbffout, hid->dev, 0, - (void*) &private->ffcr, private->buf, 8, - hid_lgff_ctrl_out, hid); - dbg("Created ff output control urb"); + ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL); + if (!ret->field[0]->value) { + kfree(ret->field[0]); + kfree(ret); + return NULL; + } + memset(ret->field[0]->value, 0, sizeof(s32[8])); + + return ret; +} + +static void hid_lgff_delete_report(struct hid_report* report) +{ + if (report) { + kfree(report->field[0]->value); + kfree(report->field[0]); + kfree(report); + } +} + +static void hid_lgff_input_init(struct hid_device* hid) +{ + struct device_type* dev = devices; + signed short* ff; + u16 idVendor = hid->dev->descriptor.idVendor; + u16 idProduct = hid->dev->descriptor.idProduct; + + while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct)) + dev++; + + ff = dev->ff; + + while (*ff >= 0) { + set_bit(*ff, hid->input.ffbit); + ++ff; + } - /* Input init */ hid->input.upload_effect = hid_lgff_upload_effect; hid->input.flush = hid_lgff_flush; - set_bit(FF_RUMBLE, hid->input.ffbit); + set_bit(EV_FF, hid->input.evbit); hid->input.ff_effects_max = LGFF_EFFECTS; - - printk(KERN_INFO "Force feedback for Logitech rumble devices by Johann Deneux \n"); - - return 0; } static void hid_lgff_exit(struct hid_device* hid) { - struct hid_ff_logitech *lgff = hid->ff_private; + struct lgff_device *lgff = hid->ff_private; - if (lgff->urbffout) { - usb_unlink_urb(lgff->urbffout); - usb_free_urb(lgff->urbffout); - } + set_bit(DEVICE_CLOSING, lgff->flags); + del_timer_sync(&lgff->timer); + + hid_lgff_delete_report(lgff->condition); + hid_lgff_delete_report(lgff->rumble); + hid_lgff_delete_report(lgff->constant); + + kfree(lgff); } static int hid_lgff_event(struct hid_device *hid, struct input_dev* input, unsigned int type, unsigned int code, int value) { - struct hid_ff_logitech *lgff = hid->ff_private; + struct lgff_device *lgff = hid->ff_private; struct lgff_effect *effect = lgff->effects + code; unsigned long flags; @@ -208,27 +312,16 @@ effect->count = value; - if (effect->replay.delay) { + if (effect->effect.replay.delay) { set_bit(EFFECT_STARTED, effect->flags); - effect->timer.expires = RUN_AT(effect->replay.delay * HZ / 1000); } else { - hid_lgff_ctrl_playback(hid, effect, value); - effect->timer.expires = RUN_AT(effect->replay.length * HZ / 1000); + set_bit(EFFECT_PLAYING, effect->flags); } - - add_timer(&effect->timer); + effect->started_at = jiffies; } else { /* value == 0 */ - if (test_and_clear_bit(EFFECT_STARTED, effect->flags)) { - del_timer(&effect->timer); - - } else if (test_and_clear_bit(EFFECT_PLAYING, effect->flags)) { - del_timer(&effect->timer); - hid_lgff_ctrl_playback(hid, effect, value); - } - - if (test_bit(EFFECT_PLAYING, effect->flags)) - warn("Effect %d still playing", code); + clear_bit(EFFECT_STARTED, effect->flags); + clear_bit(EFFECT_PLAYING, effect->flags); } spin_unlock_irqrestore(&lgff->lock, flags); @@ -241,7 +334,7 @@ static int hid_lgff_flush(struct input_dev *dev, struct file *file) { struct hid_device *hid = dev->private; - struct hid_ff_logitech *lgff = hid->ff_private; + struct lgff_device *lgff = hid->ff_private; int i; for (i=0; iff_effects_max; ++i) { @@ -265,13 +358,12 @@ static int hid_lgff_erase(struct input_dev *dev, int id) { struct hid_device *hid = dev->private; - struct hid_ff_logitech *lgff = hid->ff_private; + struct lgff_device *lgff = hid->ff_private; unsigned long flags; if (!LGFF_CHECK_OWNERSHIP(id, lgff)) return -EACCES; spin_lock_irqsave(&lgff->lock, flags); - hid_lgff_ctrl_playback(hid, lgff->effects + id, 0); lgff->effects[id].flags[0] = 0; spin_unlock_irqrestore(&lgff->lock, flags); @@ -282,7 +374,7 @@ struct ff_effect* effect) { struct hid_device *hid = input->private; - struct hid_ff_logitech *lgff = hid->ff_private; + struct lgff_device *lgff = hid->ff_private; struct lgff_effect new; int id; unsigned long flags; @@ -291,8 +383,6 @@ if (!test_bit(effect->type, input->ffbit)) return -EINVAL; - if (effect->type != FF_RUMBLE) return -EINVAL; - spin_lock_irqsave(&lgff->lock, flags); if (effect->id == -1) { @@ -317,25 +407,20 @@ id = effect->id; new = lgff->effects[id]; - new.right = effect->u.rumble.strong_magnitude >> 9; - new.left = effect->u.rumble.weak_magnitude >> 9; - new.replay = effect->replay; + new.effect = *effect; - /* If we updated an effect that was being played, we need to remake - the rumble effect */ if (test_bit(EFFECT_STARTED, lgff->effects[id].flags) || test_bit(EFFECT_STARTED, lgff->effects[id].flags)) { /* Changing replay parameters is not allowed (for the time being) */ - if (new.replay.delay != lgff->effects[id].replay.delay - || new.replay.length != lgff->effects[id].replay.length) { + if (new.effect.replay.delay != lgff->effects[id].effect.replay.delay + || new.effect.replay.length != lgff->effects[id].effect.replay.length) { spin_unlock_irqrestore(&lgff->lock, flags); return -ENOSYS; } lgff->effects[id] = new; - hid_lgff_make_rumble(hid); } else { lgff->effects[id] = new; @@ -345,151 +430,99 @@ return 0; } -static void hid_lgff_xmit(struct hid_device* hid) +static void hid_lgff_timer(unsigned long timer_data) { - struct hid_ff_logitech *lgff = hid->ff_private; - int err; - int tail; + struct lgff_device *lgff = (struct lgff_device*)timer_data; + struct hid_device *hid = lgff->hid; unsigned long flags; - - spin_lock_irqsave(&lgff->xmit_lock, flags); - - tail = lgff->xmit_tail; - if (lgff->xmit_head == tail) { - clear_bit(XMIT_RUNNING, lgff->xmit_flags); - spin_unlock_irqrestore(&lgff->xmit_lock, flags); - return; - } - lgff->buf[3] = lgff->xmit_data[tail].left; - lgff->buf[4] = lgff->xmit_data[tail].right; - tail++; tail &= LGFF_BUFFER_SIZE -1; - lgff->xmit_tail = tail; - - spin_unlock_irqrestore(&lgff->xmit_lock, flags); - - lgff->urbffout->pipe = usb_sndctrlpipe(hid->dev, 0); - lgff->ffcr.bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE; - lgff->urbffout->transfer_buffer_length = lgff->ffcr.wLength = 8; - lgff->ffcr.bRequest = 9; - lgff->ffcr.wValue = 0x0203; /*NOTE: Potential problem with - little/big endian */ - lgff->ffcr.wIndex = 0; - - lgff->urbffout->dev = hid->dev; - - if ((err=usb_submit_urb(lgff->urbffout, GFP_ATOMIC))) - warn("usb_submit_urb returned %d", err); -} - -static void hid_lgff_make_rumble(struct hid_device* hid) -{ - struct hid_ff_logitech *lgff = hid->ff_private; - int left = 0, right = 0; + int x = 0x7f, y = 0x7f; // Coordinates of constant effects + unsigned int left = 0, right = 0; // Rumbling int i; - int head, tail; - unsigned long flags; - - for (i=0; ieffects[i].flags) - && test_bit(EFFECT_PLAYING, lgff->effects[i].flags)) { - left += lgff->effects[i].left; - right += lgff->effects[i].right; - } - } - spin_lock_irqsave(&lgff->xmit_lock, flags); + spin_lock_irqsave(&lgff->lock, flags); - head = lgff->xmit_head; - tail = lgff->xmit_tail; + for (i=0; ieffects +i; - if (CIRC_SPACE(head, tail, LGFF_BUFFER_SIZE) < 1) { - warn("not enough space in xmit buffer to send new packet"); - spin_unlock_irqrestore(&lgff->xmit_lock, flags); - return; - } - - lgff->xmit_data[head].left = left > 0x7f ? 0x7f : left; - lgff->xmit_data[head].right = right > 0x7f ? 0x7f : right; - head++; head &= LGFF_BUFFER_SIZE -1; - lgff->xmit_head = head; - - if (test_and_set_bit(XMIT_RUNNING, lgff->xmit_flags)) - spin_unlock_irqrestore(&lgff->xmit_lock, flags); - else { - spin_unlock_irqrestore(&lgff->xmit_lock, flags); - hid_lgff_xmit(hid); - } -} + if (test_bit(EFFECT_PLAYING, effect->flags)) { -static void hid_lgff_ctrl_out(struct urb *urb) -{ - struct hid_device *hid = urb->context; + switch (effect->effect.type) { + case FF_CONSTANT: { + //TODO: handle envelopes + int degrees = effect->effect.direction * 360 >> 16; + x += fixp_mult(fixp_sin(degrees), + fixp_new16(effect->effect.u.constant.level)); + y += fixp_mult(-fixp_cos(degrees), + fixp_new16(effect->effect.u.constant.level)); + } break; + case FF_RUMBLE: + right += effect->effect.u.rumble.strong_magnitude; + left += effect->effect.u.rumble.weak_magnitude; + break; + }; + + /* One run of the effect is finished playing */ + if (time_after(jiffies, + effect->started_at + + effect->effect.replay.delay*HZ/1000 + + effect->effect.replay.length*HZ/1000)) { + dbg("Finished playing once %d", i); + if (--effect->count <= 0) { + dbg("Stopped %d", i); + clear_bit(EFFECT_PLAYING, effect->flags); + } + else { + dbg("Start again %d", i); + if (effect->effect.replay.length != 0) { + clear_bit(EFFECT_PLAYING, effect->flags); + set_bit(EFFECT_STARTED, effect->flags); + } + effect->started_at = jiffies; + } + } + + } else if (test_bit(EFFECT_STARTED, lgff->effects[i].flags)) { + /* Check if we should start playing the effect */ + if (time_after(jiffies, + lgff->effects[i].started_at + + lgff->effects[i].effect.replay.delay*HZ/1000)) { + dbg("Now playing %d", i); + clear_bit(EFFECT_STARTED, lgff->effects[i].flags); + set_bit(EFFECT_PLAYING, lgff->effects[i].flags); + } + } + } - if (urb->status) - warn("hid_irq_ffout status %d received", urb->status); +#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff - hid_lgff_xmit(hid); -} + // Clamp values + CLAMP(x); + CLAMP(y); + CLAMP(left); + CLAMP(right); -/* Lock must be held by caller */ -static void hid_lgff_ctrl_playback(struct hid_device *hid, - struct lgff_effect *effect, int play) -{ - if (play) { - set_bit(EFFECT_PLAYING, effect->flags); - hid_lgff_make_rumble(hid); +#undef CLAMP - } else { - clear_bit(EFFECT_PLAYING, effect->flags); - hid_lgff_make_rumble(hid); + if (x != lgff->constant->field[0]->value[2] + || y != lgff->constant->field[0]->value[3]) { + lgff->constant->field[0]->value[2] = x; + lgff->constant->field[0]->value[3] = y; + dbg("(x,y)=(%04x, %04x)", x, y); + hid_submit_report(hid, lgff->constant, USB_DIR_OUT); } -} - -static void hid_lgff_timer(unsigned long timer_data) -{ - struct lgff_effect *effect = (struct lgff_effect*) timer_data; - struct hid_ff_logitech* lgff = effect->lgff; - int id = effect->id; - unsigned long flags; - - dbg("in hid_lgff_timer"); - - if (id < 0 || id >= LGFF_EFFECTS) { - warn("Bad effect id %d", id); - return; + if (left != lgff->rumble->field[0]->value[3] + || right != lgff->rumble->field[0]->value[4]) { + lgff->rumble->field[0]->value[3] = left; + lgff->rumble->field[0]->value[4] = right; + dbg("(left,right)=(%04x, %04x)", left, right); + hid_submit_report(hid, lgff->rumble, USB_DIR_OUT); } - effect = lgff->effects + id; - - spin_lock_irqsave(&lgff->lock, flags); - - if (!test_bit(EFFECT_USED, effect->flags)) { - warn("Unused effect id %d", id); - - } else if (test_bit(EFFECT_STARTED, effect->flags)) { - clear_bit(EFFECT_STARTED, effect->flags); - set_bit(EFFECT_PLAYING, effect->flags); - hid_lgff_ctrl_playback(lgff->hid, effect, 1); - effect->timer.expires = RUN_AT(effect->replay.length * HZ / 1000); - add_timer(&effect->timer); - - dbg("Effect %d starts playing", id); - } else if (test_bit(EFFECT_PLAYING, effect->flags)) { - clear_bit(EFFECT_PLAYING, effect->flags); - hid_lgff_ctrl_playback(lgff->hid, effect, 0); - if (--effect->count > 0) { - /*TODO: check that replay.delay is non-null */ - set_bit(EFFECT_STARTED, effect->flags); - effect->timer.expires = RUN_AT(effect->replay.delay * HZ / 1000); - add_timer(&effect->timer); - dbg("Effect %d restarted", id); - } else { - dbg("Effect %d stopped", id); - } - } else { - warn("Effect %d is not started nor playing", id); + if (!test_bit(DEVICE_CLOSING, lgff->flags)) { + lgff->timer.expires = RUN_AT(PERIOD); + add_timer(&lgff->timer); } - spin_unlock_irqrestore(&lgff->lock, flags); + spin_unlock_irqrestore(&lgff->lock, flags); } diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h --- a/drivers/usb/input/hid.h Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/input/hid.h Fri Jul 26 19:58:50 2002 @@ -416,11 +416,13 @@ /* We ignore a few input applications that are not widely used */ #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001)) extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); +extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); extern int hidinput_connect(struct hid_device *); extern void hidinput_disconnect(struct hid_device *); #else #define IS_INPUT_APPLICATION(a) (0) static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } +static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } static inline void hidinput_disconnect(struct hid_device *hid) { } #endif diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/powermate.c Fri Jul 26 19:58:51 2002 @@ -83,6 +83,7 @@ /* handle updates to device state */ input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01); input_report_rel(&pm->input, REL_DIAL, pm->data[1]); + input_sync(&pm->input); } /* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ @@ -293,10 +294,10 @@ pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); - pm->input.idbus = BUS_USB; - pm->input.idvendor = udev->descriptor.idVendor; - pm->input.idproduct = udev->descriptor.idProduct; - pm->input.idversion = udev->descriptor.bcdDevice; + pm->input.id.bustype = BUS_USB; + pm->input.id.vendor = udev->descriptor.idVendor; + pm->input.id.product = udev->descriptor.idProduct; + pm->input.id.version = udev->descriptor.bcdDevice; pm->input.event = powermate_input_event; input_register_device(&pm->input); diff -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c --- a/drivers/usb/input/usbkbd.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/usbkbd.c Fri Jul 26 19:58:51 2002 @@ -104,6 +104,8 @@ } } + input_sync(&kbd->dev); + memcpy(kbd->old, kbd->new, 8); } @@ -236,10 +238,10 @@ kbd->dev.name = kbd->name; kbd->dev.phys = kbd->phys; - kbd->dev.idbus = BUS_USB; - kbd->dev.idvendor = dev->descriptor.idVendor; - kbd->dev.idproduct = dev->descriptor.idProduct; - kbd->dev.idversion = dev->descriptor.bcdDevice; + kbd->dev.id.bustype = BUS_USB; + kbd->dev.id.vendor = dev->descriptor.idVendor; + kbd->dev.id.product = dev->descriptor.idProduct; + kbd->dev.id.version = dev->descriptor.bcdDevice; if (!(buf = kmalloc(63, GFP_KERNEL))) { kfree(kbd); @@ -255,7 +257,7 @@ if (!strlen(kbd->name)) sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x", - kbd->dev.idvendor, kbd->dev.idproduct); + kbd->dev.id.vendor, kbd->dev.id.product); kfree(buf); diff -Nru a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c --- a/drivers/usb/input/usbmouse.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/input/usbmouse.c Fri Jul 26 19:58:52 2002 @@ -72,6 +72,8 @@ input_report_rel(dev, REL_X, data[1]); input_report_rel(dev, REL_Y, data[2]); input_report_rel(dev, REL_WHEEL, data[3]); + + input_sync(dev); } static int usb_mouse_open(struct input_dev *dev) @@ -145,10 +147,10 @@ mouse->dev.name = mouse->name; mouse->dev.phys = mouse->phys; - mouse->dev.idbus = BUS_USB; - mouse->dev.idvendor = dev->descriptor.idVendor; - mouse->dev.idproduct = dev->descriptor.idProduct; - mouse->dev.idversion = dev->descriptor.bcdDevice; + mouse->dev.id.bustype = BUS_USB; + mouse->dev.id.vendor = dev->descriptor.idVendor; + mouse->dev.id.product = dev->descriptor.idProduct; + mouse->dev.id.version = dev->descriptor.bcdDevice; if (!(buf = kmalloc(63, GFP_KERNEL))) { kfree(mouse); @@ -164,7 +166,7 @@ if (!strlen(mouse->name)) sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x", - mouse->dev.idvendor, mouse->dev.idproduct); + mouse->dev.id.vendor, mouse->dev.id.product); kfree(buf); diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/input/wacom.c Fri Jul 26 19:58:50 2002 @@ -136,6 +136,7 @@ } input_event(dev, EV_MSC, MSC_SERIAL, 0); + input_sync(dev); } static void wacom_graphire_irq(struct urb *urb) @@ -189,6 +190,8 @@ input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01); + + input_sync(dev); } static void wacom_intuos_irq(struct urb *urb) @@ -291,6 +294,8 @@ } input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + + input_sync(dev); } #define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS)) @@ -316,13 +321,13 @@ }; struct usb_device_id wacom_ids[] = { - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), driver_info: 0 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), driver_info: 1 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), driver_info: 2 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), driver_info: 3 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), driver_info: 4 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), driver_info: 5 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), driver_info: 6 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), .driver_info = 0 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), .driver_info = 1 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), .driver_info = 2 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), .driver_info = 3 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), .driver_info = 4 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), .driver_info = 5 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), .driver_info = 6 }, { } }; @@ -400,10 +405,10 @@ wacom->dev.name = wacom->features->name; wacom->dev.phys = wacom->phys; - wacom->dev.idbus = BUS_USB; - wacom->dev.idvendor = dev->descriptor.idVendor; - wacom->dev.idproduct = dev->descriptor.idProduct; - wacom->dev.idversion = dev->descriptor.bcdDevice; + wacom->dev.id.bustype = BUS_USB; + wacom->dev.id.vendor = dev->descriptor.idVendor; + wacom->dev.id.product = dev->descriptor.idProduct; + wacom->dev.id.version = dev->descriptor.bcdDevice; wacom->usbdev = dev; endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/input/xpad.c Fri Jul 26 19:58:51 2002 @@ -1,68 +1,70 @@ /* - * USB XBOX HID Gamecontroller - v0.0.3 + * X-Box gamepad - v0.0.5 * * Copyright (c) 2002 Marko Friedemann * * - * 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 + * 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 * * * This driver is based on: - * - information from http://euc.jp/periphs/xbox-controller.ja.html - * - the iForce driver drivers/char/joystick/iforce.c - * - the skeleton-driver drivers/usb/usb-skeleton.c + * - information from http://euc.jp/periphs/xbox-controller.ja.html + * - the iForce driver drivers/char/joystick/iforce.c + * - the skeleton-driver drivers/usb/usb-skeleton.c * * Thanks to: - * - ITO Takayuki for providing xpad information on his website - * - Vojtech Pavlik - iforce driver / input subsystem - * - Greg Kroah-Hartman - usb-skeleton driver + * - ITO Takayuki for providing essential xpad information on his website + * - Vojtech Pavlik - iforce driver / input subsystem + * - Greg Kroah-Hartman - usb-skeleton driver * * TODO: - * - get the black button to work - * - fine tune axes - * - fix "analog" buttons - * - get rumble working + * - fine tune axes + * - fix "analog" buttons (reported as digital now) + * - get rumble working * * History: * - * 2002-06-27 - 0.0.1 - first version, just said "XBOX HID controller" + * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller" * - * 2002-07-02 - 0.0.2 - basic working version - * all axes and 9 of the 10 buttons work (german InterAct device) - * the black button does not work + * 2002-07-02 - 0.0.2 : basic working version + * - all axes and 9 of the 10 buttons work (german InterAct device) + * - the black button does not work + * + * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik + * - indentation fixes + * - usb + input init sequence fixes + * + * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3 + * - verified the lack of HID and report descriptors + * - verified that ALL buttons WORK + * - fixed d-pad to axes mapping * + * 2002-07-17 - 0.0.5 : simplified d-pad handling */ #include #include #include -#include -#include -#include -#include #include #include -#include #include -#include -#include #include #include #include -#define DRIVER_VERSION "v0.0.3" +#define DRIVER_VERSION "v0.0.5" #define DRIVER_AUTHOR "Marko Friedemann " #define DRIVER_DESC "X-Box pad driver" @@ -75,29 +77,24 @@ } xpad_device[] = { { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, - { 0x05fd, 0x107a, "InterAct X-Box pad (Germany)" }, + { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, { 0x0000, 0x0000, "X-Box pad" } }; static signed short xpad_btn[] = { - BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* 6 "analog" buttons */ - BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back + stick press */ - -1 /* terminating entry */ + BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* "analog" buttons */ + BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ + -1 /* terminating entry */ }; static signed short xpad_abs[] = { ABS_X, ABS_Y, /* left stick */ ABS_RX, ABS_RY, /* right stick */ ABS_Z, ABS_RZ, /* triggers left/right */ - ABS_HAT0X, ABS_HAT0Y, /* dpad */ - -1 /* terminating entry */ + ABS_HAT0X, ABS_HAT0Y, /* digital pad */ + -1 /* terminating entry */ }; -static struct { - __s32 x; - __s32 y; -} xpad_hat_to_axis[] = { {0, 0}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1} }; - static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ { } @@ -113,28 +110,17 @@ unsigned char idata[XPAD_PKT_LEN]; /* input data */ char phys[65]; /* physical device path */ - int open_count; /* how many times has this been opened */ + int open_count; /* reference count */ }; /* - * xpad_process_packet + * xpad_process_packet + * + * Completes a request by converting the data into events for the + * input subsystem. * - * Completes a request by converting the data into events for the input subsystem. - * - * The used report descriptor given below was taken from ITO Takayukis website: - * http://euc.jp/periphs/xbox-controller.ja.html - * - * ---------------------------------------------------------------------------------------------------------------- - * | padding | byte-cnt | dpad sb12 | reserved | bt A | bt B | bt X | bt Y | bt black | bt white | - * | 01234567 | 01234567 | 0123 4567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | - * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - * ---------------------------------------------------------------------------------------------------------------- - * - * --------------------------------------------------------------------------------------------------------------- - * | trig L | trig R | left stick X | left stick Y | right stick X | right stick Y | - * | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | - * | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | - * --------------------------------------------------------------------------------------------------------------- + * The used report descriptor was taken from ITO Takayukis website: + * http://euc.jp/periphs/xbox-controller.ja.html */ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) @@ -154,8 +140,8 @@ input_report_abs(dev, ABS_RZ, data[11]); /* digital pad */ - input_report_abs(dev, ABS_HAT0X, xpad_hat_to_axis[data[2] & 0x0f].x); - input_report_abs(dev, ABS_HAT0Y, xpad_hat_to_axis[data[2] & 0x0f].y); + input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); /* start/back buttons and stick press left/right */ input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); @@ -172,6 +158,8 @@ /* "analog" buttons black, white */ input_report_key(dev, BTN_C, data[8]); input_report_key(dev, BTN_Z, data[9]); + + input_sync(dev); } static void xpad_irq_in(struct urb *urb) @@ -224,7 +212,7 @@ return NULL; } memset(xpad, 0, sizeof(struct usb_xpad)); - + xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { err("cannot allocate memory for new pad irq urb"); @@ -234,52 +222,54 @@ ep_irq_in = udev->actconfig->interface[ifnum].altsetting[0].endpoint + 0; - FILL_INT_URB(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), - xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, ep_irq_in->bInterval); + FILL_INT_URB(xpad->irq_in, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, + ep_irq_in->bInterval); xpad->udev = udev; - - xpad->dev.idbus = BUS_USB; - xpad->dev.idvendor = udev->descriptor.idVendor; - xpad->dev.idproduct = udev->descriptor.idProduct; - xpad->dev.idversion = udev->descriptor.bcdDevice; + + xpad->dev.id.bustype = BUS_USB; + xpad->dev.id.vendor = udev->descriptor.idVendor; + xpad->dev.id.product = udev->descriptor.idProduct; + xpad->dev.id.version = udev->descriptor.bcdDevice; xpad->dev.private = xpad; xpad->dev.name = xpad_device[i].name; xpad->dev.phys = xpad->phys; xpad->dev.open = xpad_open; xpad->dev.close = xpad_close; - + usb_make_path(udev, path, 64); snprintf(xpad->phys, 64, "%s/input0", path); xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - + for (i = 0; xpad_btn[i] >= 0; i++) - set_bit(xpad_btn[i], xpad->dev.keybit); + set_bit(xpad_btn[i], xpad->dev.keybit); for (i = 0; xpad_abs[i] >= 0; i++) { - + signed short t = xpad_abs[i]; - + set_bit(t, xpad->dev.absbit); switch (t) { case ABS_X: case ABS_Y: case ABS_RX: - case ABS_RY: + case ABS_RY: /* the two sticks */ xpad->dev.absmax[t] = 32767; xpad->dev.absmin[t] = -32768; xpad->dev.absflat[t] = 128; xpad->dev.absfuzz[t] = 16; break; case ABS_Z: - case ABS_RZ: + case ABS_RZ: /* the triggers */ xpad->dev.absmax[t] = 255; xpad->dev.absmin[t] = 0; break; case ABS_HAT0X: - case ABS_HAT0Y: + case ABS_HAT0Y: /* the d-pad */ xpad->dev.absmax[t] = 1; xpad->dev.absmin[t] = -1; break; @@ -304,10 +294,10 @@ } static struct usb_driver xpad_driver = { - .name = "xpad", - .probe = xpad_probe, - .disconnect = xpad_disconnect, - .id_table = xpad_table, + .name = "xpad", + .probe = xpad_probe, + .disconnect = xpad_disconnect, + .id_table = xpad_table, }; static int __init usb_xpad_init(void) diff -Nru a/drivers/usb/misc/Config.help b/drivers/usb/misc/Config.help --- a/drivers/usb/misc/Config.help Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/misc/Config.help Fri Jul 26 19:58:51 2002 @@ -7,7 +7,7 @@ The module will be called auerswald.o. If you want to compile it as a module, say M here and read . -CONFIG_USB_BRLVOYAGER +CONFIG_USB_BRLVGER Say Y here if you want to use the Voyager USB Braille display from Tieman. See for more information. diff -Nru a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c --- a/drivers/usb/misc/emi26.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/misc/emi26.c Fri Jul 26 19:58:51 2002 @@ -212,10 +212,10 @@ } struct usb_driver emi26_driver = { -name: "emi26 - firmware loader", -probe: emi26_probe, -disconnect: emi26_disconnect, -id_table: NULL, +.name = "emi26 - firmware loader", +.probe = emi26_probe, +.disconnect = emi26_disconnect, +.id_table = NULL, }; static int __init emi26_init (void) diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c Fri Jul 26 19:58:52 2002 +++ b/drivers/usb/net/pegasus.c Fri Jul 26 19:58:52 2002 @@ -62,7 +62,7 @@ static struct usb_eth_dev usb_dev_id[] = { #define PEGASUS_DEV(pn, vid, pid, flags) \ - {name:pn, vendor:vid, device:pid, private:flags}, + {.name = pn, .vendor = vid, .device = pid, .private = flags}, #include "pegasus.h" #undef PEGASUS_DEV {NULL, 0, 0, 0} @@ -70,7 +70,7 @@ static struct usb_device_id pegasus_ids[] = { #define PEGASUS_DEV(pn, vid, pid, flags) \ - {match_flags: USB_DEVICE_ID_MATCH_DEVICE, idVendor:vid, idProduct:pid}, + {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid}, #include "pegasus.h" #undef PEGASUS_DEV {} diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/net/usbnet.c Fri Jul 26 19:58:50 2002 @@ -300,7 +300,7 @@ // no reset available! // no check_connect available! - .in = 2, out: 2, // direction distinguishes these + .in = 2, .out = 2, // direction distinguishes these .epsize =64, }; @@ -321,7 +321,7 @@ static const struct driver_info belkin_info = { .description = "Belkin, eTEK, or compatible", - .in = 1, out: 1, // direction distinguishes these + .in = 1, .out = 1, // direction distinguishes these .epsize =64, }; @@ -636,7 +636,7 @@ .rx_fixup = genelink_rx_fixup, .tx_fixup = genelink_tx_fixup, - .in = 1, out: 2, + .in = 1, .out = 2, .epsize =64, #ifdef GENELINK_ACK @@ -674,7 +674,7 @@ .description = "Linux Device", // no reset defined (yet?) .check_connect =linuxdev_check_connect, - .in = 2, out: 1, + .in = 2, .out = 1, .epsize =64, }; @@ -1125,7 +1125,7 @@ .rx_fixup = net1080_rx_fixup, .tx_fixup = net1080_tx_fixup, - .in = 1, out: 1, // direction distinguishes these + .in = 1, .out = 1, // direction distinguishes these .epsize =64, }; @@ -1192,7 +1192,7 @@ /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, - .in = 3, out: 2, + .in = 3, .out = 2, .epsize =64, }; diff -Nru a/drivers/usb/serial/Config.help b/drivers/usb/serial/Config.help --- a/drivers/usb/serial/Config.help Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/serial/Config.help Fri Jul 26 19:58:51 2002 @@ -268,6 +268,16 @@ The module will be called io_edgeport.o. If you want to compile it as a module, say M here and read . +CONFIG_USB_SERIAL_EDGEPORT_TI + Say Y here if you want to use any of the devices from Inside Out + Networks (Digi) that are not supported by the io_edgeport driver. + This includes the Edgeport/1 device. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called io_ti.o. If you want to compile it + as a module, say M here and read . + CONFIG_USB_SERIAL_KLSI Say Y here if you want to use a KL5KUSB105 - based single port serial adapter. The most widely known -- and currently the only diff -Nru a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in --- a/drivers/usb/serial/Config.in Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/serial/Config.in Fri Jul 26 19:58:50 2002 @@ -19,6 +19,7 @@ dep_tristate ' USB Compaq iPAQ / HP Jornada / Casio EM500 Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL dep_tristate ' USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Inside Out Edgeport Serial Driver' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL +dep_tristate ' USB Inside Out Edgeport Serial Driver (TI devices)' CONFIG_USB_SERIAL_EDGEPORT_TI $CONFIG_USB_SERIAL dep_tristate ' USB Keyspan PDA Single Port Serial Driver' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL dep_tristate ' USB Keyspan USA-xxx Serial Driver' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL dep_mbool ' USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 $CONFIG_USB_SERIAL_KEYSPAN diff -Nru a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile --- a/drivers/usb/serial/Makefile Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/serial/Makefile Fri Jul 26 19:58:50 2002 @@ -18,6 +18,7 @@ obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o +obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o diff -Nru a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c --- a/drivers/usb/serial/digi_acceleport.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/serial/digi_acceleport.c Fri Jul 26 19:58:51 2002 @@ -1263,7 +1263,7 @@ unsigned long flags = 0; -dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d", +dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%ld", priv->dp_port_num, count, from_user, in_interrupt() ); /* copy user data (which can sleep) before getting spin lock */ @@ -1744,7 +1744,7 @@ int i; -dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() ); +dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() ); /* stop reads and writes on all ports */ for( i=0; itype->num_ports+1; i++ ) { diff -Nru a/drivers/usb/serial/io_fw_down3.h b/drivers/usb/serial/io_fw_down3.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/serial/io_fw_down3.h Fri Jul 26 19:58:52 2002 @@ -0,0 +1,799 @@ +//************************************************************** +//* Edgeport Binary Image (for TI based products) +//* Generated by TIBin2C v1.00 +//* Copyright(c) 2001 Inside Out Networks, All rights reserved. +//************************************************************** + + +static int IMAGE_SIZE = 12166; + +struct EDGE_FIRMWARE_VERSION_INFO +{ + unsigned char MajorVersion; + unsigned char MinorVersion; + unsigned short BuildNumber; +}; + +static struct EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = +{ + 4, 1, 0 // Major, Minor, Build + +}; + +static unsigned char IMAGE_ARRAY_NAME[] = +{ +// struct ImageHdr +// { +// WORD Length; +// BYTE CheckSum; +// }; +0x83, 0x2f, +0x33, + +0x02, 0x24, 0x84, 0x02, 0x1f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x45, +0x8c, 0x85, 0x46, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, +0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x44, +0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x44, 0x75, +0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x92, 0xe5, 0x81, +0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x1a, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, +0xfa, 0x74, 0x08, 0x25, 0x44, 0xf8, 0x05, 0x44, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x44, +0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x44, 0x00, 0x80, 0xef, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0x86, +0x81, 0xe5, 0x44, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, +0x78, 0x92, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, +0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, +0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x30, 0x01, 0x4d, 0x30, 0xb4, 0x48, 0x10, +0x00, 0x45, 0x90, 0xff, 0x08, 0xe0, 0x54, 0x20, 0xf8, 0x90, 0xff, 0x48, 0xe0, 0x54, 0x20, 0xf9, +0x90, 0xff, 0x10, 0xe0, 0x54, 0x20, 0xfa, 0x90, 0xff, 0x50, 0xe0, 0x54, 0x20, 0xfb, 0x74, 0x00, +0xf5, 0x82, 0x74, 0xf8, 0xf5, 0x83, 0xe0, 0xc8, 0xf0, 0x68, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, +0xc9, 0xf0, 0x69, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, 0xca, 0xf0, 0x6a, 0x60, 0x02, 0x7e, 0x04, +0xa3, 0xe0, 0xcb, 0xf0, 0x6b, 0x60, 0x02, 0x7e, 0x04, 0x22, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, +0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, +0xc0, 0x06, 0xc0, 0x07, 0x90, 0xff, 0x93, 0x74, 0x01, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03, +0x02, 0x11, 0x1a, 0x85, 0x47, 0x8d, 0x85, 0x48, 0x8b, 0x74, 0xae, 0xf5, 0x82, 0x74, 0xfa, 0xf5, +0x83, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c, +0x90, 0xff, 0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, +0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, +0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, +0xa3, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c, +0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, +0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, +0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, +0x20, 0x02, 0x03, 0x30, 0x01, 0x7b, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, +0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, 0x7e, +0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x22, 0x12, 0x00, 0xc9, 0xee, 0x64, +0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, 0x02, +0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x22, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, 0x22, +0x7c, 0x0a, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, +0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, 0x80, +0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, 0xd2, +0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, 0x60, +0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x43, 0x60, +0x13, 0x14, 0xf5, 0x43, 0x70, 0x0e, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x10, 0x95, +0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, +0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x90, +0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb5, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, +0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, 0x01, +0x7f, 0x08, 0x8e, 0x34, 0x8f, 0x35, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff, +0xea, 0x90, 0xfa, 0xb9, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x18, 0x49, 0x78, 0x24, 0x7c, 0x00, 0x7d, +0x00, 0x12, 0x19, 0x6c, 0x7e, 0x00, 0x7f, 0x05, 0x12, 0x13, 0x8f, 0xe4, 0xf5, 0x53, 0xe5, 0x53, +0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x18, 0x2a, 0xe4, 0x12, 0x13, 0xfb, 0x05, 0x53, 0x04, 0x12, +0x18, 0x1b, 0x80, 0xea, 0x12, 0x18, 0x49, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, 0xc0, +0x70, 0x03, 0x02, 0x08, 0xb8, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, +0xfe, 0x54, 0x0f, 0xf5, 0x53, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, 0x90, +0xff, 0x01, 0xe0, 0x12, 0x15, 0x0f, 0x03, 0x55, 0x00, 0x04, 0x28, 0x01, 0x05, 0x2f, 0x03, 0x05, +0xf6, 0x05, 0x06, 0x38, 0x06, 0x07, 0x9a, 0x08, 0x07, 0xe2, 0x09, 0x08, 0x3e, 0x0a, 0x08, 0x7e, +0x0b, 0x00, 0x00, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, +0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x02, 0x45, 0x34, +0x60, 0x03, 0x02, 0x0e, 0xac, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, 0x02, +0x60, 0x03, 0x02, 0x0e, 0xac, 0xee, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0x2a, 0x74, 0x01, +0x12, 0x13, 0xfb, 0x78, 0x6d, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x18, 0x2a, 0x74, 0x02, 0x12, 0x13, +0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 0x60, +0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, +0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x60, +0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, +0xe5, 0x53, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, +0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 0x80, 0x19, 0x15, 0x53, 0x30, +0x0a, 0x0b, 0x12, 0x18, 0xbd, 0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x80, 0x09, 0x12, 0x18, 0xcb, +0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0x60, 0x05, 0x74, 0x01, +0x12, 0x13, 0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, +0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, +0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, +0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, +0xac, 0x78, 0x6d, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, +0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb5, 0xe0, +0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, +0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 0xb9, 0xe0, 0x70, +0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, +0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x07, +0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, 0x54, +0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x53, 0x24, 0xfe, 0x60, 0x1b, +0x04, 0x70, 0x2e, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, +0x80, 0x1f, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 0x80, 0x16, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, +0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 0xce, 0x80, 0x07, 0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2a, +0xce, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, +0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, +0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, +0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, +0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, +0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x78, 0x6d, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, +0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, +0x30, 0xe0, 0x07, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0a, 0xe5, +0x53, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, +0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xff, +0x12, 0x2f, 0x3b, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, +0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x19, 0x7a, 0x02, 0x19, 0x3e, +0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, +0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x44, 0x08, +0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, +0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, +0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0xac, +0x90, 0xfa, 0xba, 0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x2c, 0x01, 0x80, 0x03, +0x53, 0x2c, 0xfe, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, +0xe5, 0x35, 0x45, 0x34, 0x70, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, +0xac, 0x90, 0xfa, 0xb9, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, +0x75, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xed, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, +0x49, 0x12, 0x19, 0x73, 0x7d, 0x03, 0x12, 0x0e, 0xf3, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, +0xb0, 0x90, 0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, +0x04, 0xae, 0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x18, 0x49, 0x90, 0xf9, 0x65, 0xe0, 0x30, +0xe4, 0x0d, 0x12, 0x19, 0x73, 0x7d, 0x14, 0x12, 0x0e, 0xf3, 0x60, 0x10, 0x02, 0x0e, 0xac, 0x12, +0x19, 0x73, 0x7d, 0x04, 0x12, 0x0f, 0x47, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 0xb0, 0x90, +0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 0x04, 0xae, +0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x19, 0x73, 0x7d, 0x05, 0x12, 0x0f, 0x47, 0x60, 0x03, +0x02, 0x0e, 0xac, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x12, 0x18, 0x90, 0x7d, 0x01, 0x12, 0x23, +0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xba, 0xe0, 0x90, +0xfa, 0xb1, 0xf0, 0xe4, 0xf5, 0x52, 0x90, 0xfa, 0xb1, 0xe0, 0xff, 0xe5, 0x52, 0xc3, 0x9f, 0x50, +0x24, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0xff, 0xfd, 0x90, 0xfa, 0xb3, 0xe4, 0x8d, 0xf0, 0x12, +0x14, 0x2f, 0x90, 0xfa, 0xb2, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0e, +0xac, 0x05, 0x52, 0x80, 0xd1, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0x24, 0xfe, 0xff, 0x90, 0xfa, +0xb2, 0xf0, 0xfd, 0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0x7a, 0xf9, 0x79, 0x6e, 0x7b, +0x01, 0x8b, 0x2d, 0x8a, 0x2e, 0x89, 0x2f, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x18, +0x90, 0x12, 0x23, 0xee, 0x8f, 0x52, 0x05, 0x52, 0x05, 0x52, 0x12, 0x18, 0x2a, 0xe5, 0x52, 0x12, +0x13, 0xfb, 0x12, 0x18, 0x2a, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x14, 0x0d, 0xaf, 0x52, 0x7e, +0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x50, 0x02, 0x80, 0x04, 0xae, 0x34, 0xaf, 0x35, +0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, +0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, +0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, +0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, +0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x00, 0x75, 0x2f, 0x29, 0x02, +0x0f, 0x2f, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, +0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 0x90, 0xfa, 0xba, +0xe0, 0x94, 0x01, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, +0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0e, +0xac, 0x90, 0xfa, 0xba, 0xe0, 0xf5, 0x29, 0xe5, 0x29, 0x70, 0x08, 0x43, 0x2c, 0x01, 0x53, 0x2c, +0xfd, 0x80, 0x06, 0x53, 0x2c, 0xfe, 0x43, 0x2c, 0x02, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, +0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, +0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, +0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, +0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x7f, 0x01, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, +0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, +0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, +0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, +0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xff, 0x01, 0x12, 0x19, 0x8a, 0xef, 0x12, +0x13, 0xfb, 0x90, 0xfa, 0xb5, 0x12, 0x19, 0x8a, 0x90, 0x00, 0x01, 0xef, 0x12, 0x14, 0x0d, 0x90, +0x00, 0x02, 0xe4, 0x12, 0x14, 0x0d, 0x74, 0x03, 0x12, 0x18, 0x1b, 0x90, 0xfa, 0xb9, 0xe0, 0xff, +0xa3, 0xe0, 0x85, 0x2f, 0x82, 0x85, 0x2e, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, +0xe0, 0x12, 0x15, 0x0f, 0x09, 0x3d, 0x02, 0x09, 0x5f, 0x04, 0x09, 0x81, 0x05, 0x09, 0xad, 0x06, +0x09, 0xcb, 0x07, 0x09, 0xe9, 0x08, 0x0a, 0x07, 0x09, 0x0a, 0x25, 0x0b, 0x0a, 0xda, 0x80, 0x0c, +0xfa, 0x81, 0x0d, 0x1c, 0x82, 0x0b, 0x21, 0x83, 0x0b, 0x6a, 0x84, 0x0b, 0x89, 0x85, 0x0b, 0xc5, +0x86, 0x0c, 0x07, 0x87, 0x0c, 0x95, 0x88, 0x0c, 0xd0, 0x89, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, +0x0d, 0xcf, 0xc0, 0x0e, 0x00, 0xc1, 0x0e, 0x11, 0xc2, 0x00, 0x00, 0x0e, 0x9b, 0xe5, 0x2c, 0x20, +0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, +0xfd, 0x7c, 0x00, 0x7f, 0x07, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 0xc0, 0xe5, +0x2c, 0x20, 0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, +0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, +0xc0, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x19, 0x99, 0x50, 0x06, 0xe5, 0x35, +0x45, 0x34, 0x70, 0x05, 0x7f, 0x02, 0x02, 0x2e, 0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 0xfe, 0x24, +0xfd, 0x50, 0x02, 0x80, 0x03, 0x02, 0x2f, 0x28, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, +0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, +0x00, 0x7f, 0x08, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, +0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, +0x09, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, +0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, +0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, +0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x10, 0x9c, +0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, +0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x10, 0x9c, 0x7f, 0x07, +0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x56, 0x12, 0x18, 0xd9, 0x70, 0x4a, 0x90, 0xff, 0x02, +0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 0x80, 0x12, 0xe5, 0x52, 0xb4, +0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x52, 0x12, +0x17, 0x8b, 0x12, 0x19, 0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x05, +0x12, 0x2f, 0x76, 0x80, 0x06, 0x85, 0x2a, 0x30, 0x85, 0x2b, 0x31, 0x75, 0x2d, 0x01, 0x75, 0x2e, +0xf9, 0x75, 0x2f, 0x71, 0x02, 0x29, 0x2d, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x12, 0x18, +0xd9, 0x60, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x19, 0x99, 0x40, 0x05, 0x7f, 0x03, 0x02, +0x2e, 0xa5, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, +0x80, 0x12, 0xe5, 0x52, 0xb4, 0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, +0xf0, 0x04, 0xf5, 0x52, 0x12, 0x17, 0x8b, 0x02, 0x2f, 0x28, 0x12, 0x19, 0xa3, 0x12, 0x27, 0x19, +0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x78, +0x6e, 0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, +0xe4, 0x12, 0x14, 0x0d, 0x90, 0xfa, 0xb6, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x82, 0xe6, 0xfc, +0x08, 0xe6, 0x8c, 0x83, 0x12, 0x18, 0xa3, 0xef, 0xf0, 0x12, 0x2f, 0x80, 0xe4, 0xff, 0x02, 0x2e, +0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, +0x70, 0x06, 0xa3, 0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, +0xba, 0xe0, 0x42, 0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 0x70, +0x06, 0xa3, 0xe0, 0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xba, +0xe0, 0x42, 0xb0, 0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x49, 0x90, 0xfa, 0xb5, +0xe0, 0xb4, 0x01, 0x0a, 0x12, 0x18, 0x2a, 0xe5, 0x90, 0x12, 0x13, 0xfb, 0x80, 0x08, 0x12, 0x18, +0x2a, 0xe5, 0xb0, 0x12, 0x13, 0xfb, 0x02, 0x0f, 0x2f, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x30, +0x12, 0x18, 0x53, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, +0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x19, 0xad, 0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb6, +0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x04, 0x12, 0x19, 0xb4, 0xf0, +0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x36, 0x12, 0x18, 0x53, 0x60, +0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, +0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, +0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, +0xdf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x46, 0x04, 0x60, 0x03, 0x02, +0x0c, 0x90, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x04, 0xf0, 0x90, +0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x6a, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x61, 0x90, +0xff, 0xa4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x53, 0x30, 0x95, 0x09, +0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x47, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, +0x80, 0x3e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x04, 0xf0, 0x90, +0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x2a, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x21, 0x90, +0xff, 0xb4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x13, 0x30, 0x93, 0x09, +0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfd, 0xf0, +0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, +0xe0, 0x60, 0x09, 0x90, 0xff, 0xa2, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa2, 0xe0, +0x54, 0xbf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb2, 0xe0, 0x44, +0x40, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, +0x12, 0x18, 0x49, 0x12, 0x18, 0x5b, 0x60, 0x0f, 0x04, 0x70, 0x16, 0x90, 0xff, 0xa4, 0xe0, 0x12, +0x18, 0x2a, 0x12, 0x13, 0xfb, 0x80, 0x0a, 0x90, 0xff, 0xb4, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, +0xfb, 0x75, 0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x12, +0x19, 0x46, 0x7f, 0x03, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0xff, +0x7e, 0x00, 0x12, 0x2d, 0xee, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, 0xe4, 0xf5, 0x54, 0xf5, +0x55, 0x90, 0xfa, 0xbb, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, 0xb3, 0xf0, 0xa3, 0x74, +0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, 0xb8, 0xf0, 0xd3, 0x94, +0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, +0xd6, 0xe5, 0x23, 0x45, 0x22, 0x70, 0x73, 0x12, 0x18, 0x62, 0x90, 0xfa, 0xbb, 0x12, 0x19, 0x65, +0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, 0xfa, 0xb8, 0x74, 0x40, +0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 0xd6, 0xe5, 0x23, +0x45, 0x22, 0x70, 0x46, 0x12, 0x18, 0x62, 0x80, 0xd1, 0x75, 0x52, 0x02, 0x90, 0xfa, 0xbb, 0xe4, +0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb3, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, 0xf0, 0x7b, 0x00, 0x7a, +0x00, 0x79, 0x52, 0x90, 0xfa, 0xbc, 0xe0, 0xf5, 0x50, 0x7d, 0x0f, 0x7c, 0x00, 0x12, 0x26, 0x25, +0x75, 0x22, 0x00, 0x8f, 0x23, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, 0x40, 0xf5, 0x41, +0x7d, 0x01, 0x12, 0x23, 0xee, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0xaf, 0x23, 0x02, 0x2e, 0xa5, 0x90, +0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x62, +0xf0, 0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0f, +0x90, 0xf9, 0x61, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x2e, 0xa5, +0x12, 0x19, 0xa3, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x2e, +0xa5, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, +0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, +0x12, 0x19, 0xad, 0x12, 0x0e, 0xfe, 0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, +0x44, 0x10, 0x12, 0x0e, 0xfe, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, +0x19, 0xad, 0xf0, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, +0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, +0x92, 0x80, 0x23, 0x12, 0x19, 0xb4, 0x12, 0x0f, 0x1e, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, +0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x1e, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, +0xd2, 0x92, 0x12, 0x19, 0xb4, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x07, +0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x2f, 0x76, 0x22, +0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, +0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0xab, +0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x22, 0xaa, 0x54, 0xa9, 0x55, 0x7b, 0xff, 0x90, 0xfa, 0xb3, 0xe0, +0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xb8, 0xe0, 0xf5, 0x50, 0x12, 0x26, 0x25, 0x75, 0x22, 0x00, +0x8f, 0x23, 0x22, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 0xef, 0x22, 0xf0, 0x7f, +0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x12, +0x23, 0xee, 0x8f, 0x52, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x22, 0xf0, 0x7f, +0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x75, +0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x02, 0x2f, 0x3b, +0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, +0xef, 0x22, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb0, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, +0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, +0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, 0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, +0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, 0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, +0x04, 0xc0, 0x05, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, +0x0f, 0xfe, 0x7f, 0x00, 0x7e, 0x00, 0xe5, 0x49, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x19, 0xe0, 0x54, +0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, +0x49, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, +0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, +0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, +0x12, 0x10, 0x95, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, +0x4a, 0x75, 0xa8, 0x88, 0xec, 0x70, 0x02, 0x7c, 0x3f, 0x8c, 0x43, 0x22, 0xe5, 0x44, 0x24, 0x08, +0xf8, 0x76, 0x00, 0x12, 0x10, 0xec, 0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, +0xc0, 0x06, 0x7c, 0xff, 0x12, 0x0f, 0xfe, 0xe5, 0x49, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x19, 0xe0, +0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x49, 0x80, 0x07, +0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, 0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, +0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, +0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, +0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, 0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, +0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, 0xee, 0x12, 0x10, 0x95, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, +0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, 0x43, 0x00, 0x85, 0x4a, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, +0xc0, 0x83, 0xc3, 0xe5, 0x49, 0x24, 0xe8, 0x50, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf4, 0xef, 0x60, +0x31, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x0f, +0xfe, 0xd0, 0x04, 0x43, 0x07, 0x80, 0xe5, 0x49, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x19, 0xf5, 0x82, +0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, 0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x49, 0x12, +0x10, 0x95, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x02, 0x11, 0x1a, 0xc0, 0x04, 0x7c, 0x20, +0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, 0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, +0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, 0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, +0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, 0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, +0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, 0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, +0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, 0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, +0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0xd2, 0xb0, 0xd2, +0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, +0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, +0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x48, 0x8e, +0x47, 0x22, 0xc3, 0xef, 0x94, 0xbc, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, +0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x46, 0x8e, 0x45, 0x22, 0xef, +0x70, 0x01, 0x22, 0xc0, 0x00, 0xe5, 0x44, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x44, 0x24, 0x08, +0xf8, 0xc6, 0x54, 0x7f, 0xf6, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x10, 0xec, 0x80, +0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08, 0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5, +0x12, 0x10, 0xec, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, +0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0xa0, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, +0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78, +0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x0e, 0xf5, 0x82, +0xe5, 0xf0, 0x34, 0x2e, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, +0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24, 0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04, +0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x44, 0x00, 0x75, 0x49, +0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76, 0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90, +0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, +0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f, 0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75, +0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x91, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, +0xe5, 0x49, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x19, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, +0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6, 0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08, +0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x11, 0xc1, 0xad, 0x07, 0xaf, 0x02, +0x12, 0x11, 0xd8, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x10, 0xec, 0x80, 0xc1, 0xe7, +0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, +0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, +0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, +0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, +0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, +0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, +0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, +0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, +0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, +0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, +0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, +0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, +0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, +0xf0, 0xef, 0x60, 0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, +0x50, 0xb9, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, +0x23, 0x90, 0x13, 0x0f, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, +0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, +0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, +0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, +0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, +0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, +0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, +0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, +0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, +0x83, 0xe0, 0x38, 0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, +0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, +0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, +0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, +0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, +0xe9, 0x93, 0x22, 0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, +0x50, 0x06, 0xf7, 0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, +0x19, 0x22, 0xf8, 0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, +0xe8, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, +0xf0, 0x22, 0xbb, 0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, +0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, +0x08, 0xe6, 0xf9, 0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, +0xe0, 0xfa, 0xa3, 0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, +0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, +0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, +0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, +0xff, 0xf9, 0x74, 0x02, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, 0x00, +0x7a, 0x00, 0x79, 0x37, 0x75, 0x40, 0x00, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0xe5, 0x37, +0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x37, 0x64, 0x07, 0x60, 0x0b, 0xe5, 0x37, 0x64, 0x06, +0x60, 0x05, 0xe5, 0x37, 0xb4, 0x14, 0x1b, 0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0xe5, +0x37, 0xb4, 0x07, 0x08, 0x90, 0xf9, 0x65, 0x74, 0x02, 0xf0, 0x80, 0x06, 0x90, 0xf9, 0x65, 0x74, +0x01, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x17, 0x71, 0x90, 0xff, +0xf5, 0xe5, 0x37, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, +0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x12, 0x17, 0x71, 0xe5, 0x37, 0x30, 0xe7, +0x02, 0xd2, 0x02, 0xe4, 0xf5, 0x2c, 0xf5, 0x2a, 0xf5, 0x2b, 0xf5, 0x29, 0x12, 0x19, 0x92, 0x12, +0x18, 0x49, 0x12, 0x19, 0x6c, 0x90, 0xf9, 0x66, 0x12, 0x15, 0x06, 0x90, 0xf9, 0x6b, 0x12, 0x15, +0x06, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, 0x74, +0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0x12, +0x18, 0xbf, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x37, 0x12, 0x18, 0xcd, 0xf5, 0x83, 0xe4, 0xf0, 0x05, +0x37, 0xe5, 0x37, 0xb4, 0x07, 0xe7, 0x78, 0x80, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x2f, 0x06, +0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x2f, 0x13, 0xe4, 0x93, 0xff, 0x08, +0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x18, 0xaf, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, 0x08, +0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, 0x9f, +0x78, 0x81, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x18, 0x41, 0xce, 0xc3, 0x13, 0xce, 0x13, +0xd8, 0xf9, 0xff, 0xed, 0x12, 0x19, 0x07, 0xef, 0xf0, 0xed, 0x12, 0x19, 0x2d, 0xe4, 0xf5, 0x37, +0xe5, 0x37, 0x90, 0x2f, 0x00, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xe5, 0x37, 0x25, 0xe0, 0x24, +0x07, 0xf5, 0x82, 0xe4, 0x34, 0x2f, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, 0x53, +0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xaf, 0x12, 0x19, 0x15, 0x24, 0x47, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, 0x19, +0x07, 0xef, 0xf0, 0x12, 0x18, 0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, +0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x19, 0x2d, 0xe9, +0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, +0x02, 0x17, 0x46, 0x78, 0x7e, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xf9, 0x12, 0x19, 0x15, 0x24, +0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, +0x12, 0x19, 0x1a, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x18, +0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 0x24, 0x05, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5, 0x37, 0x64, 0x04, 0x60, 0x03, 0x02, 0x16, +0x70, 0x90, 0x2f, 0x05, 0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0x12, 0x18, 0xf7, 0xe4, 0xf0, 0x90, +0x2f, 0x04, 0x93, 0xff, 0xf6, 0x12, 0x18, 0xad, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, 0xf0, +0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, +0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, +0x2f, 0xe5, 0x52, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, +0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0x74, 0x11, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, +0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x06, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, +0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0xab, 0x2d, +0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, +0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, +0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x04, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, +0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x05, 0xe0, +0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, +0x35, 0x2e, 0xf5, 0x2e, 0x22, 0xf5, 0x83, 0xe0, 0x54, 0x08, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, +0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, 0x78, 0x81, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, +0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, 0x75, 0x2d, 0x01, 0x75, 0x2e, 0xf9, 0x75, +0x2f, 0x6e, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xfa, 0xb5, 0xe0, 0x24, +0xfc, 0x22, 0x90, 0xfa, 0xb8, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xbc, 0xe0, 0x9f, 0xf0, +0x90, 0xfa, 0xbb, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xb3, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, +0x25, 0x55, 0xf5, 0x55, 0xee, 0x35, 0x54, 0xf5, 0x54, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb0, +0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x22, 0x78, 0x82, 0xe6, 0xfe, 0x08, +0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, +0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x53, 0x75, +0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0xe5, 0x53, 0x75, 0xf0, 0x08, +0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, +0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x75, 0x2a, 0x00, 0x8f, 0x2b, 0x90, 0xf9, 0x6b, +0x12, 0x14, 0xfd, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, +0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, 0xe4, +0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, 0xa4, +0x22, 0x74, 0xae, 0x25, 0x36, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, +0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, 0xff, +0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, 0xfc, +0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x6d, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x65, +0xf0, 0x22, 0x12, 0x14, 0xdf, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xf9, +0x79, 0x6e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, +0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x66, 0x02, +0x14, 0xfd, 0x75, 0x30, 0x01, 0x75, 0x31, 0x09, 0x22, 0xd3, 0xe5, 0x35, 0x94, 0x08, 0xe5, 0x34, +0x94, 0x01, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x90, 0xfa, 0xb6, 0xf0, 0x22, 0x90, 0xff, 0xa4, +0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xef, 0x22, 0x8f, 0x38, 0x12, 0x27, 0x19, +0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xe0, 0xfd, +0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x12, 0x20, 0x7c, 0x24, +0x07, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x12, 0x20, 0xbe, 0x24, 0x09, 0x12, 0x20, 0x25, 0xef, 0xf0, +0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x20, 0x2f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, +0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, 0x82, 0xe0, 0x33, 0xd0, +0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xe0, 0xfc, 0xa3, 0xe0, +0xfd, 0xec, 0xff, 0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xef, 0xf0, 0xed, +0x12, 0x20, 0xbe, 0x24, 0x07, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, +0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x20, 0x69, 0xa3, 0xe0, +0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, +0x2f, 0x4d, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x12, 0x20, 0xae, 0x24, 0x06, 0x12, 0x20, 0x25, +0xe0, 0x60, 0x03, 0x43, 0x07, 0x04, 0x53, 0x07, 0xfc, 0x78, 0x86, 0x12, 0x20, 0x96, 0x24, 0x04, +0x12, 0x20, 0x25, 0xe0, 0x42, 0x07, 0x43, 0x07, 0x80, 0x12, 0x20, 0xa6, 0xf5, 0x82, 0x8a, 0x83, +0xa3, 0xa3, 0xef, 0xf0, 0x12, 0x20, 0xbe, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x8d, 0x82, +0x8c, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, +0x03, 0x43, 0x07, 0x20, 0xec, 0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, +0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 0x4c, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x42, +0x12, 0x20, 0xae, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 0x60, 0x31, 0x14, 0x60, 0x29, 0x14, +0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 0x38, 0xb4, 0x03, 0x0d, 0x30, 0x95, +0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, 0x43, 0x07, +0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, 0x07, 0xfd, +0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x20, 0x94, 0x24, 0x04, 0x12, 0x20, 0x25, 0xef, 0xf0, 0x8d, +0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, +0x4a, 0xee, 0x30, 0xe1, 0x43, 0x08, 0x12, 0x20, 0xb0, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, +0x60, 0x2c, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, +0x38, 0xb4, 0x03, 0x0d, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x1f, 0x43, 0x07, 0x80, 0x80, +0x1a, 0x30, 0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x12, 0x43, 0x07, 0x80, 0x80, 0x0d, 0x53, 0x07, +0x7f, 0x80, 0x08, 0x43, 0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x86, 0x12, 0x20, 0x65, +0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, +0xec, 0x30, 0xe3, 0x05, 0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, +0x43, 0x07, 0x10, 0x80, 0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, +0x03, 0x53, 0x07, 0xf7, 0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, +0xed, 0x30, 0xe6, 0x05, 0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, +0x43, 0x07, 0x02, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x78, 0x84, 0x12, 0x20, 0x65, 0xa3, 0xef, 0xf0, +0x12, 0x2f, 0x80, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x8e, 0xef, 0xf6, 0x12, 0x27, 0x19, +0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0xfd, 0x12, 0x20, 0x53, 0x90, +0x00, 0x0a, 0x12, 0x20, 0x78, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x14, +0x0d, 0x12, 0x20, 0x70, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x59, 0x12, 0x20, +0x7c, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xf5, 0x5a, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, +0xf5, 0x5b, 0xe5, 0x59, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x8e, 0xf6, 0xd3, 0x94, 0x00, +0x40, 0x06, 0xe5, 0x5a, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x8e, 0xe6, 0x12, 0x20, 0x52, 0x90, 0x00, +0x0c, 0xef, 0x12, 0x14, 0x0d, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, +0xff, 0x53, 0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x59, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, +0x5a, 0x20, 0xe5, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 0x20, 0xe7, 0x03, 0x43, +0x07, 0x02, 0xe5, 0x59, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x59, 0x30, 0xe2, 0x03, 0x43, +0x07, 0x20, 0xe5, 0x59, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x59, 0x30, 0xe1, 0x03, +0x43, 0x07, 0x80, 0xe5, 0x59, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x59, 0x30, 0xe6, 0x03, +0x43, 0x06, 0x08, 0xe5, 0x5a, 0x20, 0xe4, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, +0x20, 0xe7, 0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, +0x8f, 0xf0, 0x12, 0x14, 0xb2, 0xe5, 0x5b, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, +0x12, 0x20, 0x52, 0x90, 0x00, 0x08, 0xef, 0x12, 0x14, 0x0d, 0x80, 0x0a, 0x12, 0x20, 0x53, 0x90, +0x00, 0x08, 0xe4, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x03, 0x12, 0x20, 0x52, 0x90, 0x00, 0x07, +0xef, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x14, +0x0d, 0x90, 0x00, 0x07, 0x12, 0x13, 0xce, 0x70, 0x13, 0x12, 0x20, 0x53, 0xe9, 0x24, 0x09, 0xf9, +0xe4, 0x3a, 0xfa, 0x12, 0x13, 0xb5, 0xff, 0xc3, 0x13, 0x12, 0x13, 0xfb, 0x12, 0x20, 0x94, 0x24, +0x08, 0x12, 0x20, 0x25, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x20, +0x25, 0xe0, 0xfd, 0xee, 0xed, 0x12, 0x20, 0x52, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x14, +0xb2, 0x12, 0x2f, 0x80, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 0x90, 0xfa, +0xe2, 0xe0, 0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, +0xfa, 0xd6, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xff, 0x7e, 0x00, +0x90, 0xfa, 0xd2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, +0x12, 0x14, 0x5b, 0xff, 0x90, 0xfa, 0xd4, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, +0x01, 0x8e, 0x56, 0x8f, 0x57, 0x74, 0x0a, 0x25, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, +0x90, 0xfa, 0xd7, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd5, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, +0xff, 0x90, 0xfa, 0xd9, 0xf0, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0x90, 0xfa, 0xd2, 0xe0, 0x94, +0x00, 0x50, 0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 0x60, 0x03, 0xe0, 0xff, +0x22, 0x12, 0x2a, 0x80, 0x90, 0xfa, 0xd2, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, +0xfa, 0xd6, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, +0xfa, 0xd9, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, +0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, 0x2a, 0x80, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x58, +0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7f, 0x00, 0x22, 0xaa, 0x56, 0xa9, +0x57, 0x7b, 0x01, 0x90, 0xfa, 0xd4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xd9, 0xe0, 0xf5, +0x50, 0x12, 0x26, 0x25, 0x90, 0xfa, 0xd8, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, +0xfe, 0x60, 0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x1e, 0xed, 0x24, 0x06, 0x60, 0x03, 0x02, 0x1f, +0x35, 0x78, 0x77, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, +0x74, 0x33, 0x90, 0xfa, 0x90, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xae, 0x74, 0x01, 0xf0, +0x22, 0x78, 0x78, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, +0x74, 0x43, 0x90, 0xfa, 0x92, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, +0x22, 0x90, 0xfa, 0x9c, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x1f, 0x35, 0x90, 0xff, 0xa6, 0xe0, +0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, +0x90, 0xff, 0xa6, 0x12, 0x20, 0x83, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, +0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x57, 0x90, 0xfa, +0xca, 0xe0, 0xff, 0x74, 0x34, 0x90, 0xfa, 0x94, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa6, +0xe0, 0xa3, 0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, +0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x20, 0x83, 0x90, +0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, +0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, +0x96, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, +0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, +0x06, 0xc0, 0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc8, 0xf0, 0x90, 0xff, 0x92, 0xe4, +0xf0, 0xef, 0x12, 0x15, 0x0f, 0x1f, 0xed, 0x26, 0x1f, 0xed, 0x2e, 0x1f, 0x90, 0x30, 0x1f, 0x90, +0x32, 0x1f, 0x9e, 0x38, 0x1f, 0xb0, 0x3a, 0x1f, 0xe2, 0x3e, 0x1f, 0xcd, 0x44, 0x1f, 0xc2, 0x46, +0x1f, 0xd8, 0x50, 0x1f, 0xd8, 0x52, 0x1f, 0xd8, 0x54, 0x1f, 0xd8, 0x56, 0x00, 0x00, 0x1f, 0xf2, +0x90, 0xfa, 0xc8, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x10, 0x9c, 0x80, 0x62, 0x7c, 0x00, +0x7d, 0x01, 0x7f, 0x03, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, +0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x02, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, +0x80, 0x3e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x10, 0x9c, 0x80, 0x33, 0x7c, 0x00, 0x7d, +0x01, 0x7f, 0x06, 0x12, 0x10, 0x9c, 0x80, 0x28, 0x90, 0xfa, 0xc8, 0xe0, 0xff, 0x12, 0x1e, 0x4a, +0x80, 0x1e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x10, 0x9c, 0x80, 0x13, 0x12, 0x25, 0x13, +0x80, 0x0e, 0x90, 0xfa, 0xc8, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x29, 0xda, +0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, +0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x82, 0xe6, 0xfe, 0x08, +0xe6, 0x24, 0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x78, 0x82, 0xe6, +0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, +0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, 0xff, 0x7a, 0x2f, 0x79, 0x52, 0x7e, 0x00, 0x7f, 0x0a, 0x02, +0x13, 0x8f, 0xff, 0x90, 0xf9, 0x6b, 0x02, 0x14, 0xfd, 0x90, 0xf9, 0x66, 0x12, 0x14, 0xfd, 0x90, +0x00, 0x04, 0x02, 0x13, 0xce, 0xe6, 0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, +0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xed, 0x12, 0x14, 0x0d, 0x8f, 0x82, 0x8e, 0x83, +0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, +0xf0, 0x4e, 0xf0, 0x22, 0x78, 0x84, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, 0x83, 0x22, 0xa6, 0x07, +0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x22, 0x78, 0x84, 0xe6, 0xfa, 0x08, 0xe6, 0xfb, 0x22, 0x78, 0x86, +0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, +0x8a, 0x83, 0xe5, 0x82, 0x22, 0x8b, 0x38, 0x8a, 0x39, 0x89, 0x3a, 0x8d, 0x3b, 0x90, 0xfa, 0xce, +0xe4, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe0, +0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xcd, 0xe0, 0x65, +0x3b, 0x60, 0x46, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x21, +0x54, 0x90, 0xfa, 0xcd, 0xe0, 0xff, 0x90, 0xfa, 0xd0, 0xe4, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0x12, +0x21, 0x54, 0x90, 0xfa, 0xd0, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xce, 0xcf, 0xf0, 0xa3, 0xef, +0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xa3, 0x75, 0xf0, 0x00, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xce, 0xe4, +0x75, 0xf0, 0x04, 0x12, 0x14, 0x2f, 0x02, 0x20, 0xd6, 0x90, 0xfa, 0xcf, 0xe0, 0x24, 0x01, 0xff, +0x90, 0xfa, 0xce, 0xe0, 0x34, 0x00, 0xab, 0x38, 0xaa, 0x39, 0xa9, 0x3a, 0x8f, 0xf0, 0x12, 0x14, +0x93, 0x7f, 0x00, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe4, 0x75, 0xf0, +0x01, 0x12, 0x14, 0x2f, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x8f, 0x68, +0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xfb, +0xf0, 0x44, 0x02, 0xf0, 0x08, 0x12, 0x20, 0x65, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x20, 0x7c, +0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x82, 0xe6, 0xfe, 0x08, 0xe6, 0xff, +0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x68, 0x24, 0xfe, 0x44, 0x20, 0xfc, +0x4d, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, +0x82, 0x8e, 0x83, 0xa3, 0x74, 0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, +0x05, 0x12, 0x20, 0x25, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x95, 0x25, 0x68, 0xf5, 0x82, +0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, +0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, +0x25, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x68, 0xf8, 0x74, 0x04, 0x46, +0xf6, 0x7f, 0x00, 0x22, 0x8b, 0x62, 0x8a, 0x63, 0x89, 0x64, 0x12, 0x2a, 0x62, 0x90, 0xfa, 0xbf, +0x12, 0x15, 0x06, 0xaa, 0x63, 0xa9, 0x64, 0x90, 0xfa, 0xc2, 0x12, 0x15, 0x06, 0x90, 0xfa, 0xc3, +0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xc2, 0x12, 0x14, 0xfd, 0xe9, 0x24, 0x01, +0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc5, 0x12, 0x15, 0x06, 0xab, 0x62, 0xaa, 0x63, 0xa9, 0x64, +0x12, 0x2a, 0x6e, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x88, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, +0xff, 0x78, 0x88, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xbf, 0x12, 0x2a, 0x43, 0xff, 0x78, +0x89, 0xf6, 0x90, 0xfa, 0xc2, 0x12, 0x2a, 0x43, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x89, 0xf6, 0x12, +0x2a, 0x40, 0x5e, 0x4f, 0xff, 0x78, 0x89, 0xf6, 0x12, 0x2a, 0x49, 0x75, 0xf0, 0x02, 0x12, 0x14, +0x2f, 0x90, 0xfa, 0xc3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0xab, 0x62, 0xaa, 0x63, 0xa9, +0x64, 0x90, 0x00, 0x04, 0x12, 0x13, 0xce, 0x30, 0xe4, 0x03, 0x12, 0x2a, 0x58, 0x78, 0x88, 0x06, +0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x22, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x90, 0xfa, +0xbe, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbd, 0xf0, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x26, +0x14, 0x70, 0x70, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x22, 0x14, 0x80, +0x62, 0x12, 0x2a, 0x79, 0x12, 0x1d, 0x5e, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0x80, 0x55, 0x90, 0xfa, +0xbe, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, 0x12, +0x29, 0x85, 0x80, 0x3f, 0xe5, 0x5e, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5d, 0xfa, 0x7b, 0x01, 0xc0, +0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xfd, 0x90, +0x00, 0x08, 0x12, 0x14, 0x5b, 0xf5, 0x41, 0x85, 0xf0, 0x40, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, +0x12, 0x23, 0xee, 0x90, 0xfa, 0xbd, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, 0xbe, +0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbe, 0xe0, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x02, 0x12, 0x14, 0x0d, +0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0x89, 0x7f, 0x02, 0x12, 0x11, 0x9f, 0x78, 0x6d, +0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, 0xb1, 0xd2, 0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, +0x7a, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, +0x78, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, +0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, 0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, +0xe3, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, 0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, +0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7a, +0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x78, +0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x15, +0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe3, 0xe0, 0xf5, 0xa8, 0x02, 0x10, 0x0c, 0x8b, 0x3c, +0x8a, 0x3d, 0x89, 0x3e, 0x8d, 0x3f, 0xe5, 0x3f, 0x70, 0x03, 0xaf, 0x3f, 0x22, 0x12, 0x2a, 0xa8, +0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x40, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x2e, 0xd4, 0x50, 0xf2, +0x12, 0x24, 0x7b, 0x40, 0x0b, 0x7f, 0x00, 0x22, 0x12, 0x2a, 0xc7, 0x12, 0x24, 0x7b, 0x50, 0xf8, +0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, 0x3f, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, +0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, 0xf5, 0x42, 0xe5, 0x3f, 0x14, 0xff, 0xe5, 0x42, 0xc3, +0x9f, 0x50, 0x2a, 0x12, 0x2e, 0xbd, 0x40, 0x03, 0xaf, 0x42, 0x22, 0xc3, 0xe5, 0x3f, 0x95, 0x42, +0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2a, 0xba, 0x05, 0x42, +0x74, 0x01, 0x25, 0x3e, 0xf5, 0x3e, 0xe4, 0x35, 0x3d, 0xf5, 0x3d, 0x80, 0xcc, 0x12, 0x2e, 0xbd, +0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xba, 0xaf, 0x3f, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x41, +0xf0, 0x02, 0x2e, 0xd4, 0x75, 0xa8, 0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x91, +0x02, 0x24, 0xce, 0x02, 0x2e, 0x88, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, +0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, +0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, +0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x28, +0xcb, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, +0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, +0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, +0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, +0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x36, 0x12, 0x19, 0x21, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x36, 0x24, +0x03, 0xff, 0x12, 0x2d, 0x4f, 0x12, 0x19, 0x21, 0xe4, 0xf0, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, +0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x36, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x90, 0x12, 0x19, +0x62, 0x60, 0x2c, 0x12, 0x29, 0xda, 0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, +0x90, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x36, 0x90, 0xfa, 0x9c, +0x12, 0x14, 0xdf, 0xe0, 0xa3, 0x30, 0xe6, 0x33, 0x12, 0x19, 0x21, 0x74, 0x04, 0xf0, 0x22, 0x75, +0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x19, 0x62, 0x60, 0x16, 0x12, 0x29, 0xda, 0xef, +0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, +0xf0, 0x22, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, +0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, +0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xfb, 0x0f, 0x12, 0x18, 0x19, 0x80, +0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x31, 0x9d, 0xf5, 0x31, 0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0xd3, +0xe5, 0x31, 0x94, 0x00, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, +0x12, 0x19, 0x3e, 0x12, 0x19, 0x92, 0x12, 0x19, 0x8c, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x1e, +0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x13, 0xce, 0xff, 0x24, 0xfc, +0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x10, 0x9c, 0x12, 0x19, +0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, +0xff, 0x12, 0x2f, 0x6a, 0x22, 0x8b, 0x4b, 0x8a, 0x4c, 0x89, 0x4d, 0x8c, 0x4e, 0x8d, 0x4f, 0xd2, +0x00, 0x12, 0x2a, 0xa8, 0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x4e, 0x90, 0xff, 0xf1, 0xf0, 0x12, +0x2e, 0xd4, 0x50, 0xf2, 0x12, 0x26, 0x9a, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xc7, 0x12, +0x26, 0x9a, 0x50, 0xf8, 0xe4, 0xf5, 0x51, 0xe5, 0x50, 0x14, 0xff, 0xe5, 0x51, 0xc3, 0x9f, 0x50, +0x17, 0x12, 0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x05, 0x51, 0x74, 0x01, 0x25, 0x4d, 0xf5, +0x4d, 0xe4, 0x35, 0x4c, 0xf5, 0x4c, 0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, +0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x7f, 0x00, 0x22, 0xab, 0x4b, 0xaa, 0x4c, 0xa9, 0x4d, +0x12, 0x13, 0xb5, 0x90, 0xff, 0xf1, 0xf0, 0x02, 0x2e, 0xd4, 0x90, 0xff, 0xf1, 0xe5, 0x4f, 0xf0, +0x02, 0x2e, 0xd4, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 0xfa, +0xcb, 0xe4, 0x75, 0xf0, 0x09, 0x12, 0x14, 0x2f, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, +0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x12, +0x23, 0xee, 0x90, 0xff, 0xf7, 0xe5, 0x37, 0x12, 0x26, 0xfe, 0x90, 0xff, 0xf6, 0xe5, 0x37, 0xf0, +0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x06, 0x12, 0x26, 0xfe, 0xe5, 0x37, 0x30, 0xe0, 0x07, +0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, 0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, +0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, +0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x15, 0x6b, 0xa8, 0x6b, 0xa6, 0x07, 0x30, +0x08, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x6b, 0xe6, 0xff, 0xb4, 0x03, 0x0f, +0x78, 0x82, 0x76, 0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, +0x82, 0x76, 0xff, 0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x86, 0x76, 0xfa, +0x08, 0x76, 0x9a, 0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x20, 0xb7, 0x7b, +0x01, 0x7a, 0xff, 0x79, 0x48, 0x78, 0x6e, 0x12, 0x14, 0xf4, 0xa8, 0x6b, 0xe6, 0x24, 0xfd, 0x75, +0xf0, 0x08, 0xa4, 0xff, 0xae, 0xf0, 0x78, 0x70, 0x12, 0x20, 0xb7, 0x79, 0x08, 0x78, 0x71, 0x12, +0x14, 0xf4, 0x78, 0x73, 0xef, 0x12, 0x20, 0xb7, 0x05, 0x6b, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, +0xab, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe2, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, +0x79, 0xcb, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7e, 0x00, 0x90, 0xfa, +0xe0, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x52, +0x09, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe0, 0xe0, 0x70, 0x04, +0xa3, 0xe0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x65, +0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe2, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x65, 0xe0, +0x54, 0xef, 0xf0, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x90, 0xff, 0x93, 0x74, 0x2a, +0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, 0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, +0xe0, 0x44, 0x90, 0xf0, 0x12, 0x27, 0x8b, 0x12, 0x15, 0x35, 0x12, 0x2d, 0xa5, 0x7e, 0x07, 0x7f, +0xd0, 0x12, 0x11, 0x68, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0x82, 0xe4, 0x78, 0x7d, 0xf6, 0x78, +0x7d, 0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x74, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x7d, +0x06, 0x80, 0xec, 0x7f, 0x03, 0x12, 0x2c, 0x5b, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe4, 0x05, 0x7f, +0x04, 0x12, 0x2c, 0x5b, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, +0xe0, 0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x90, 0xef, 0xf6, 0x12, 0x27, +0x19, 0x12, 0x20, 0x59, 0x30, 0xe0, 0x25, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x7f, 0xf0, 0x78, 0x71, +0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, 0xe4, +0x12, 0x14, 0x0d, 0x80, 0xe9, 0x12, 0x20, 0x2d, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x20, 0x59, 0x30, +0xe1, 0x1e, 0x12, 0x20, 0x1b, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x2f, 0x15, 0x78, 0x6e, 0x12, 0x14, +0xeb, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x14, 0x0d, 0x12, 0x20, 0x1b, 0xe0, 0x44, 0x80, 0xf0, +0x12, 0x2f, 0x80, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x03, 0x6e, 0x01, 0xff, 0x48, +0x03, 0x71, 0x01, 0xff, 0x08, 0x02, 0x6c, 0x00, 0x00, 0x44, 0xfa, 0x94, 0x00, 0x00, 0x00, 0x00, +0x44, 0xfa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xae, 0x00, 0x00, 0x42, 0xfa, 0x7a, 0x00, +0x00, 0x42, 0xfa, 0x78, 0x00, 0x00, 0x42, 0xf9, 0x69, 0xff, 0xff, 0x42, 0xfa, 0x76, 0x00, 0x00, +0x43, 0xf9, 0x16, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x63, 0x20, 0x41, 0xf9, 0x64, 0x20, 0x41, 0xf9, +0x61, 0x00, 0x41, 0xf9, 0x62, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf9, 0x65, +0x00, 0x41, 0xf9, 0x15, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, 0x19, 0x82, +0xe5, 0x31, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x31, 0x94, +0x08, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x11, 0x7f, 0x08, 0xef, 0xe5, 0x31, 0x94, 0x08, 0xf5, 0x31, +0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0x80, 0x05, 0xaf, 0x31, 0x12, 0x19, 0x92, 0xe4, 0xfe, 0xee, +0xc3, 0x9f, 0x50, 0x19, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, +0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, 0xf0, 0x0e, 0x12, 0x18, 0x19, 0x80, 0xe2, 0xef, 0x54, 0x7f, +0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, 0x5f, 0x8a, 0x60, 0x89, 0x61, 0x12, 0x2a, 0x6e, 0x70, 0x05, +0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, 0x5f, 0xaa, 0x60, 0xa9, 0x61, 0x12, 0x2a, 0x62, 0x90, 0xfa, +0xc5, 0x12, 0x15, 0x06, 0xe5, 0x61, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x60, 0xfa, 0x90, 0xfa, 0xbf, +0x12, 0x15, 0x06, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x78, 0x91, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 0xff, +0x78, 0x91, 0xe6, 0xc3, 0x9f, 0x50, 0x12, 0x12, 0x2a, 0x40, 0xff, 0x12, 0x2a, 0x49, 0x12, 0x2a, +0x5c, 0x78, 0x91, 0x06, 0x12, 0x2a, 0x58, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x2f, +0x06, 0xe4, 0x93, 0xff, 0x78, 0x7a, 0xf6, 0x54, 0x0f, 0x12, 0x19, 0x07, 0xe0, 0x08, 0x76, 0x00, +0x08, 0xf6, 0x18, 0x12, 0x18, 0x42, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x7b, +0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, 0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, +0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, 0x22, 0x78, 0x7b, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, +0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, +0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0x00, 0x03, 0x12, 0x13, 0xce, 0x54, 0xf0, 0x24, 0xa0, 0x22, +0x90, 0xfa, 0xc5, 0x12, 0x14, 0xfd, 0x02, 0x13, 0xb5, 0x90, 0xfa, 0xbf, 0x12, 0x14, 0xfd, 0xef, +0x12, 0x13, 0xfb, 0x90, 0xfa, 0xc6, 0xe4, 0x22, 0x90, 0xfa, 0xc0, 0xe4, 0x75, 0xf0, 0x01, 0x02, +0x14, 0x2f, 0x90, 0x00, 0x08, 0x12, 0x14, 0x5b, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, +0x05, 0x12, 0x13, 0xce, 0x90, 0xfa, 0xbd, 0xf0, 0x22, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x22, +0x90, 0xfa, 0xd9, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, +0xd2, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xd4, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 0x25, 0x57, +0xf5, 0x57, 0xee, 0x35, 0x56, 0xf5, 0x56, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, +0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe2, 0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x3c, +0xaa, 0x3d, 0xa9, 0x3e, 0x02, 0x13, 0xfb, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x6a, +0xed, 0x70, 0x0f, 0xe5, 0x6a, 0xb4, 0x03, 0x05, 0x7f, 0x01, 0x02, 0x2e, 0xeb, 0x7f, 0x02, 0x02, +0x2e, 0xeb, 0xaf, 0x6a, 0x12, 0x27, 0x19, 0x74, 0x74, 0x25, 0x6a, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, +0xd2, 0x09, 0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x6a, 0xb4, +0x03, 0x07, 0x7f, 0x81, 0x12, 0x2e, 0xeb, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x2e, 0xeb, 0x30, 0x09, +0x07, 0x12, 0x18, 0x9b, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x22, 0x12, 0x0f, 0x89, 0x90, +0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, 0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, +0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, 0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x2c, 0x80, +0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0d, 0x12, 0x19, 0x3e, 0x53, 0x2c, 0x7f, 0x90, +0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, 0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0x9f, +0x12, 0x19, 0x46, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 0x8a, 0x12, 0x20, 0x9e, 0x30, 0xe1, +0x07, 0x7f, 0x13, 0x12, 0x2e, 0xa5, 0x80, 0x34, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 0x16, +0x78, 0x8a, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, 0x90, +0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x04, 0xf0, 0x78, 0x8a, +0xe6, 0xff, 0x12, 0x20, 0x59, 0xfd, 0x12, 0x2d, 0x21, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, +0x0f, 0x89, 0x78, 0x8f, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x27, 0x19, 0x90, 0xf9, 0x66, 0x12, 0x14, +0xfd, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, +0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x20, 0x4b, 0x12, 0x2f, 0x80, 0x78, +0x8f, 0xe6, 0xff, 0x12, 0x19, 0xbb, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, +0x8b, 0xef, 0xf6, 0x12, 0x2e, 0x4c, 0x12, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, +0x16, 0x78, 0x8b, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, +0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x14, 0xf0, 0xe0, 0x70, 0x02, +0xd2, 0xb3, 0x02, 0x10, 0x0c, 0x8f, 0x69, 0x12, 0x27, 0x19, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x3f, +0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, +0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0x74, +0x74, 0x25, 0x69, 0xf8, 0x74, 0xfb, 0x56, 0xf6, 0x7f, 0x00, 0x22, 0x8f, 0x37, 0xc2, 0x08, 0x12, +0x27, 0x19, 0x12, 0x20, 0x38, 0x78, 0x84, 0x12, 0x20, 0x1d, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x20, +0x70, 0x12, 0x20, 0x21, 0xe0, 0x20, 0xe0, 0xf6, 0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, +0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0xaf, 0x37, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, +0x89, 0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x24, 0x06, 0x12, 0x20, 0x23, 0xe0, 0xfd, 0x12, 0x20, +0x53, 0x90, 0x00, 0x03, 0x12, 0x20, 0x78, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x04, +0x12, 0x14, 0x0d, 0x12, 0x2f, 0x80, 0x7d, 0x02, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, +0xae, 0x05, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x35, +0xe4, 0x95, 0x34, 0x40, 0x02, 0xae, 0x35, 0xee, 0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, +0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, 0x12, 0x14, 0x0d, 0xaf, 0x06, 0x12, 0x2f, 0x6a, +0x22, 0x12, 0x0f, 0x89, 0x78, 0x8c, 0x12, 0x20, 0x9e, 0x30, 0xe2, 0x07, 0x7f, 0x13, 0x12, 0x2e, +0xa5, 0x80, 0x1b, 0x78, 0x8c, 0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x20, 0xe1, 0x07, 0x7f, 0x12, 0x12, +0x2e, 0xa5, 0x80, 0x0a, 0x78, 0x8c, 0xe6, 0xff, 0x12, 0x21, 0x6e, 0x12, 0x2e, 0xa5, 0x02, 0x10, +0x0c, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, 0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, +0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, 0x74, 0x74, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, +0x74, 0x95, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, +0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, 0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, +0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x80, 0xf0, 0x74, +0x74, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 0x64, +0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, +0xc3, 0xe5, 0x31, 0x9f, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x05, 0x12, 0x25, 0x9c, 0x80, 0x03, 0x12, +0x2f, 0x76, 0x02, 0x10, 0x0c, 0x90, 0xff, 0xfc, 0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, +0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, 0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, +0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0x80, 0xef, 0x22, 0x12, 0x0f, 0x89, 0x78, +0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, 0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, +0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x11, 0x9f, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x8e, 0x65, +0x8f, 0x66, 0xe5, 0x66, 0x15, 0x66, 0xae, 0x65, 0x70, 0x02, 0x15, 0x65, 0xd3, 0x94, 0x00, 0xee, +0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, 0x12, 0x0f, 0x62, 0x80, 0xe5, 0x22, 0x11, 0x1a, +0x2b, 0x1c, 0x23, 0x56, 0x2f, 0x5c, 0x2d, 0xcc, 0x2d, 0x7a, 0x2e, 0x6b, 0x2c, 0x8e, 0x2b, 0x66, +0x2b, 0xec, 0x2c, 0xf1, 0x2e, 0x2d, 0x1b, 0xe6, 0x2b, 0xaf, 0x28, 0x67, 0x0e, 0x12, 0x0f, 0x89, +0x78, 0x8d, 0x12, 0x20, 0x9e, 0x20, 0xe2, 0x07, 0x7f, 0x11, 0x12, 0x2e, 0xa5, 0x80, 0x0a, 0x78, +0x8d, 0xe6, 0xff, 0x12, 0x2c, 0x25, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x8f, 0x67, 0x12, 0x2c, +0x25, 0xaf, 0x67, 0x12, 0x27, 0x19, 0x12, 0x20, 0x38, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x67, +0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x67, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, +0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x05, 0x12, 0x29, 0x2d, 0x80, 0x06, 0x12, +0x19, 0x7a, 0x12, 0x19, 0x82, 0x02, 0x10, 0x0c, 0x12, 0x27, 0xfb, 0x12, 0x12, 0x3b, 0x90, 0xf8, +0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x11, 0xd8, 0x12, 0x26, 0xa3, 0x12, 0x12, 0x77, +0x12, 0x10, 0xfa, 0x80, 0xe3, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0xe4, 0xf5, 0x2a, 0xf5, +0x2b, 0xef, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 0xff, 0x12, 0x2f, 0x6a, 0x22, 0x90, 0xff, 0xf0, +0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, +0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, +0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, +0x18, 0xad, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, 0x18, 0xf7, 0xe0, 0x54, 0xdf, 0xf0, 0x22, +0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, +0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x84, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, +0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, 0x34, 0x30, 0x85, 0x35, 0x31, 0x90, 0xff, +0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x2f, +0x00, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, 0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, +0x38, 0x28, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x89, 0x7f, +0x02, 0x12, 0x10, 0x18, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x12, +0x18, 0x49, 0x12, 0x29, 0x2d, 0x22, 0x12, 0x19, 0x82, 0x12, 0x19, 0x3e, 0x12, 0x19, 0x7a, 0x22, +0xc2, 0x08, 0x22, +}; + +#undef IMAGE_VERSION_NAME + +#undef IMAGE_ARRAY_NAME + diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/serial/io_ti.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,2684 @@ +/* + * Edgeport USB Serial Converter driver + * + * Copyright(c) 2000-2002 Inside Out Networks, All rights reserved. + * Copyright(c) 2001-2002 Greg Kroah-Hartman + * + * 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. + * + * Supports the following devices: + * EP/1 EP/2 EP/4 + * + * Version history: + * + * July 11, 2002 Removed 4 port device structure since all TI UMP + * chips have only 2 ports + * David Iacovelli (davidi@ionetworks.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +#include "usb-serial.h" + +#include "io_16654.h" +#include "io_usbvend.h" +#include "io_ti.h" + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.2" +#define DRIVER_AUTHOR "Greg Kroah-Hartman and David Iacovelli" +#define DRIVER_DESC "Edgeport USB Serial Driver" + + +/* firmware image code */ +#define IMAGE_VERSION_NAME PagableOperationalCodeImageVersion +#define IMAGE_ARRAY_NAME PagableOperationalCodeImage +#define IMAGE_SIZE PagableOperationalCodeSize +#include "io_fw_down3.h" /* Define array OperationalCodeImage[] */ + +#define EPROM_PAGE_SIZE 64 + + +struct edgeport_uart_buf_desc { + __u32 count; // Number of bytes currently in buffer +}; + +/* different hardware types */ +#define HARDWARE_TYPE_930 0 +#define HARDWARE_TYPE_TIUMP 1 + +// IOCTL_PRIVATE_TI_GET_MODE Definitions +#define TI_MODE_CONFIGURING 0 // Device has not entered start device +#define TI_MODE_BOOT 1 // Staying in boot mode +#define TI_MODE_DOWNLOAD 2 // Made it to download mode +#define TI_MODE_TRANSITIONING 3 // Currently in boot mode but transitioning to download mode + + +/* Product information read from the Edgeport */ +struct product_info +{ + int TiMode; // Current TI Mode + __u8 hardware_type; // Type of hardware +} __attribute__((packed)); + + +struct edgeport_port { + __u16 uart_base; + __u16 dma_address; + __u8 shadow_msr; + __u8 shadow_mcr; + __u8 shadow_lsr; + __u8 lsr_mask; + __u32 ump_read_timeout; /* Number of miliseconds the UMP will + wait without data before completing + a read short */ + int baud_rate; + int close_pending; + int lsr_event; + struct edgeport_uart_buf_desc tx; + struct async_icount icount; + wait_queue_head_t delta_msr_wait; /* for handling sleeping while + waiting for msr change to + happen */ + struct edgeport_serial *edge_serial; + struct usb_serial_port *port; +}; + +struct edgeport_serial { + struct product_info product_info; + u8 TI_I2C_Type; // Type of I2C in UMP + u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode + int num_ports_open; + struct usb_serial *serial; +}; + + +/* Devices that this driver supports */ +static struct usb_device_id edgeport_1port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, + { } +}; + +static struct usb_device_id edgeport_2port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) }, + { } +}; + +/* Devices that this driver supports */ +static __devinitdata struct usb_device_id id_table_combined [] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) }, + { } +}; + +MODULE_DEVICE_TABLE (usb, id_table_combined); + + +static struct EDGE_FIRMWARE_VERSION_INFO OperationalCodeImageVersion; + +static int TIStayInBootMode = 0; +static int ignore_cpu_rev = 0; + + + +static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); + +static int TIReadVendorRequestSync (struct usb_device *dev, + __u8 request, + __u16 value, + __u16 index, + u8 *data, + int size) +{ + int status; + + status = usb_control_msg (dev, + usb_rcvctrlpipe(dev, 0), + request, + (USB_TYPE_VENDOR | + USB_RECIP_DEVICE | + USB_DIR_IN), + value, + index, + data, + size, + HZ); + if (status < 0) + return status; + if (status != size) { + dbg ("%s - wanted to write %d, but only wrote %d", + __FUNCTION__, size, status); + return -ECOMM; + } + return 0; +} + +static int TISendVendorRequestSync (struct usb_device *dev, + __u8 request, + __u16 value, + __u16 index, + u8 *data, + int size) +{ + int status; + + status = usb_control_msg (dev, + usb_sndctrlpipe(dev, 0), + request, + (USB_TYPE_VENDOR | + USB_RECIP_DEVICE | + USB_DIR_OUT), + value, + index, + data, + size, + HZ); + + if (status < 0) + return status; + if (status != size) { + dbg ("%s - wanted to write %d, but only wrote %d", + __FUNCTION__, size, status); + return -ECOMM; + } + return 0; +} + +static int TIWriteCommandSync (struct usb_device *dev, __u8 command, + __u8 moduleid, __u16 value, u8 *data, + int size) +{ + return TISendVendorRequestSync (dev, + command, // Request + value, // wValue + moduleid, // wIndex + data, // TransferBuffer + size); // TransferBufferLength + +} + + +/* clear tx/rx buffers and fifo in TI UMP */ +static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask) +{ + int port_number = port->number - port->serial->minor; + + dbg ("%s - port %d, mask %x", __FUNCTION__, port_number, mask); + + return TIWriteCommandSync (port->serial->dev, + UMPC_PURGE_PORT, + (__u8)(UMPM_UART1_PORT + port_number), + mask, + NULL, + 0); +} + +/** + * TIReadDownloadMemory - Read edgeport memory from TI chip + * @dev: usb device pointer + * @address: Device CPU address at which to read + * @length: Length of above data + * @address_type: Can read both XDATA and I2C + * @buffer: pointer to input data buffer + */ +int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length, + __u8 address_type, __u8 *buffer) +{ + int status = 0; + __u8 read_length; + __u16 be_start_address; + + dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length); + + /* Read in blocks of 64 bytes + * (TI firmware can't handle more than 64 byte reads) + */ + while (length) { + if (length > 64) + read_length= 64; + else + read_length = (__u8)length; + + if (read_length > 1) { + dbg ("%s - @ %x for %d", __FUNCTION__, + start_address, read_length); + } + be_start_address = cpu_to_be16 (start_address); + status = TIReadVendorRequestSync (dev, + UMPC_MEMORY_READ, // Request + (__u16)address_type, // wValue (Address type) + be_start_address, // wIndex (Address to read) + buffer, // TransferBuffer + read_length); // TransferBufferLength + + if (status) { + dbg ("%s - ERROR %x", __FUNCTION__, status); + return status; + } + + if (read_length > 1) { + usb_serial_debug_data (__FILE__, __FUNCTION__, + read_length, buffer); + } + + /* Update pointers/length */ + start_address += read_length; + buffer += read_length; + length -= read_length; + } + + return status; +} + +int TIReadRam (struct usb_device *dev, int start_address, int length, __u8 *buffer) +{ + return TIReadDownloadMemory (dev, + start_address, + length, + DTK_ADDR_SPACE_XDATA, + buffer); +} + +/* Read edgeport memory to a given block */ +static int TIReadBootMemory (struct edgeport_serial *serial, int start_address, int length, __u8 * buffer) +{ + int status = 0; + int i; + + for (i=0; i< length; i++) { + status = TIReadVendorRequestSync (serial->serial->dev, + UMPC_MEMORY_READ, // Request + serial->TI_I2C_Type, // wValue (Address type) + (__u16)(start_address+i), // wIndex + &buffer[i], // TransferBuffer + 0x01); // TransferBufferLength + if (status) { + dbg ("%s - ERROR %x", __FUNCTION__, status); + return status; + } + } + + dbg ("%s - start_address = %x, length = %d", __FUNCTION__, start_address, length); + usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); + + serial->TiReadI2C = 1; + + return status; +} + +/* Write given block to TI EPROM memory */ +static int TIWriteBootMemory (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer) +{ + int status = 0; + int i; + __u8 temp; + + /* Must do a read before write */ + if (!serial->TiReadI2C) { + status = TIReadBootMemory(serial, 0, 1, &temp); + if (status) + return status; + } + + for (i=0; i < length; ++i) { + status = TISendVendorRequestSync (serial->serial->dev, + UMPC_MEMORY_WRITE, // Request + buffer[i], // wValue + (__u16)(i+start_address), // wIndex + NULL, // TransferBuffer + 0); // TransferBufferLength + if (status) + return status; + } + + dbg ("%s - start_sddr = %x, length = %d", __FUNCTION__, start_address, length); + usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); + + return status; +} + + +/* Write edgeport I2C memory to TI chip */ +static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address, int length, __u8 address_type, __u8 *buffer) +{ + int status = 0; + int write_length; + __u16 be_start_address; + + /* We can only send a maximum of 1 aligned byte page at a time */ + + /* calulate the number of bytes left in the first page */ + write_length = EPROM_PAGE_SIZE - (start_address & (EPROM_PAGE_SIZE - 1)); + + if (write_length > length) + write_length = length; + + dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __FUNCTION__, start_address, write_length); + usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer); + + /* Write first page */ + be_start_address = cpu_to_be16 (start_address); + status = TISendVendorRequestSync (serial->serial->dev, + UMPC_MEMORY_WRITE, // Request + (__u16)address_type, // wValue + be_start_address, // wIndex + buffer, // TransferBuffer + write_length); + if (status) { + dbg ("%s - ERROR %d", __FUNCTION__, status); + return status; + } + + length -= write_length; + start_address += write_length; + buffer += write_length; + + /* We should be aligned now -- can write max page size bytes at a time */ + while (length) { + if (length > EPROM_PAGE_SIZE) + write_length = EPROM_PAGE_SIZE; + else + write_length = length; + + dbg ("%s - Page Write Addr = %x, length = %d", __FUNCTION__, start_address, write_length); + usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer); + + /* Write next page */ + be_start_address = cpu_to_be16 (start_address); + status = TISendVendorRequestSync (serial->serial->dev, + UMPC_MEMORY_WRITE, // Request + (__u16)address_type, // wValue + be_start_address, // wIndex + buffer, // TransferBuffer + write_length); // TransferBufferLength + if (status) { + dbg ("%s - ERROR %d", __FUNCTION__, status); + return status; + } + + length -= write_length; + start_address += write_length; + buffer += write_length; + } + return status; +} + +/* Examine the UMP DMA registers and LSR + * + * Check the MSBit of the X and Y DMA byte count registers. + * A zero in this bit indicates that the TX DMA buffers are empty + * then check the TX Empty bit in the UART. + */ +static int TIIsTxActive (struct edgeport_port *port) +{ + int status; + struct out_endpoint_desc_block *oedb; + __u8 lsr; + int bytes_left = 0; + + oedb = kmalloc (sizeof (* oedb), GFP_KERNEL); + if (!oedb) { + err ("%s - out of memory", __FUNCTION__); + return -ENOMEM; + } + + /* Read the DMA Count Registers */ + status = TIReadRam (port->port->serial->dev, + port->dma_address, + sizeof( *oedb), + (void *)oedb); + + if (status) + goto exit_is_tx_active; + + dbg ("%s - XByteCount 0x%X", __FUNCTION__, oedb->XByteCount); + + /* and the LSR */ + status = TIReadRam (port->port->serial->dev, + port->uart_base + UMPMEM_OFFS_UART_LSR, + 1, + &lsr); + + if (status) + goto exit_is_tx_active; + dbg ("%s - LSR = 0x%X", __FUNCTION__, lsr); + + /* If either buffer has data or we are transmitting then return TRUE */ + if ((oedb->XByteCount & 0x80 ) != 0 ) + bytes_left += 64; + + if ((lsr & UMP_UART_LSR_TX_MASK ) == 0 ) + bytes_left += 1; + + /* We return Not Active if we get any kind of error */ +exit_is_tx_active: + dbg ("%s - return %d", __FUNCTION__, bytes_left ); + return bytes_left; +} + +static void TIChasePort(struct edgeport_port *port) +{ + int loops; + int last_count; + int write_size; + +restart_tx_loop: + // Base the LoopTime on the baud rate + if (port->baud_rate == 0) + port->baud_rate = 1200; + + write_size = port->tx.count; + loops = max(100, (100*write_size)/(port->baud_rate/10)); + dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, + write_size, port->baud_rate, loops); + + while (1) { + // Save Last count + last_count = port->tx.count; + + dbg ("%s - Tx Buffer Size = %d loops = %d", __FUNCTION__, + last_count, loops); + + /* Is the Edgeport Buffer empty? */ + if (port->tx.count == 0) + break; + + /* Block the thread for 10ms */ + wait_ms (10); + + if (last_count == port->tx.count) { + /* No activity.. count down. */ + --loops; + if (loops == 0) { + dbg ("%s - Wait for TxEmpty - TIMEOUT", + __FUNCTION__); + return; + } + } else { + /* Reset timeout value back to a minimum of 1 second */ + dbg ("%s - Wait for TxEmpty Reset Count", __FUNCTION__); + goto restart_tx_loop; + } + } + + dbg ("%s - Local Tx Buffer Empty -- Waiting for TI UMP to EMPTY X/Y and FIFO", + __FUNCTION__); + + write_size = TIIsTxActive (port); + loops = max(50, (100*write_size)/(port->baud_rate/10)); + dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, + write_size, port->baud_rate, loops); + + while (1) { + /* This function takes 4 ms; */ + if (!TIIsTxActive (port)) { + /* Delay a few char times */ + wait_ms (50); + dbg ("%s - Empty", __FUNCTION__); + return; + } + + --loops; + if (loops == 0) { + dbg ("%s - TIMEOUT", __FUNCTION__); + return; + } + } +} + +static int TIChooseConfiguration (struct usb_device *dev) +{ + // There may be multiple configurations on this device, in which case + // we would need to read and parse all of them to find out which one + // we want. However, we just support one config at this point, + // configuration # 1, which is Config Descriptor 0. + + dbg ("%s - Number of Interfaces = %d", __FUNCTION__, dev->config->bNumInterfaces); + dbg ("%s - MAX Power = %d", __FUNCTION__, dev->config->MaxPower*2); + + if (dev->config->bNumInterfaces != 1) { + err ("%s - bNumInterfaces is not 1, ERROR!", __FUNCTION__); + return -ENODEV; + } + + return 0; +} + +int TIReadRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer) +{ + int status; + + if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { + status = TIReadDownloadMemory (serial->serial->dev, + start_address, + length, + serial->TI_I2C_Type, + buffer); + } else { + status = TIReadBootMemory (serial, + start_address, + length, + buffer); + } + + return status; +} + +int TIWriteRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer) +{ + if (serial->product_info.TiMode == TI_MODE_BOOT) + return TIWriteBootMemory (serial, + start_address, + length, + buffer); + + if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) + return TIWriteDownloadI2C (serial, + start_address, + length, + serial->TI_I2C_Type, + buffer); + + return -EINVAL; +} + + + +/* Read a descriptor header from I2C based on type */ +static int TIGetDescriptorAddress (struct edgeport_serial *serial, int desc_type, struct ti_i2c_desc *rom_desc) +{ + int start_address; + int status; + + /* Search for requested descriptor in I2C */ + start_address = 2; + do { + status = TIReadRom (serial, + start_address, + sizeof(struct ti_i2c_desc), + (__u8 *)rom_desc ); + if (status) + return 0; + + if (rom_desc->Type == desc_type) + return start_address; + + start_address = start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size; + + } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); + + return 0; +} + +/* Validate descriptor checksum */ +static int ValidChecksum(struct ti_i2c_desc *rom_desc, __u8 *buffer) +{ + __u16 i; + __u8 cs = 0; + + for (i=0; i < rom_desc->Size; i++) { + cs = (__u8)(cs + buffer[i]); + } + if (cs != rom_desc->CheckSum) { + dbg ("%s - Mismatch %x - %x", __FUNCTION__, rom_desc->CheckSum, cs); + return -EINVAL; + } + return 0; +} + +/* Make sure that the I2C image is good */ +static int TiValidateI2cImage (struct edgeport_serial *serial) +{ + int status = 0; + struct ti_i2c_desc *rom_desc; + int start_address = 2; + __u8 *buffer; + + rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); + if (!rom_desc) { + err ("%s - out of memory", __FUNCTION__); + return -ENOMEM; + } + buffer = kmalloc (TI_MAX_I2C_SIZE, GFP_KERNEL); + if (!buffer) { + err ("%s - out of memory when allocating buffer", __FUNCTION__); + kfree (rom_desc); + return -ENOMEM; + } + + // Read the first byte (Signature0) must be 0x52 + status = TIReadRom (serial, 0, 1, buffer); + if (status) + goto ExitTiValidateI2cImage; + + if (*buffer != 0x52) { + err ("%s - invalid buffer signature", __FUNCTION__); + status = -ENODEV; + goto ExitTiValidateI2cImage; + } + + do { + // Validate the I2C + status = TIReadRom (serial, + start_address, + sizeof(struct ti_i2c_desc), + (__u8 *)rom_desc); + if (status) + break; + + if ((start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size) > TI_MAX_I2C_SIZE) { + status = -ENODEV; + dbg ("%s - structure too big, erroring out.", __FUNCTION__); + break; + } + + dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type); + + // Skip type 2 record + if ((rom_desc->Type & 0x0f) != I2C_DESC_TYPE_FIRMWARE_BASIC) { + // Read the descriptor data + status = TIReadRom(serial, + start_address+sizeof(struct ti_i2c_desc), + rom_desc->Size, + buffer); + if (status) + break; + + status = ValidChecksum(rom_desc, buffer); + if (status) + break; + } + start_address = start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size; + + } while ((rom_desc->Type != I2C_DESC_TYPE_ION) && (start_address < TI_MAX_I2C_SIZE)); + + if ((rom_desc->Type != I2C_DESC_TYPE_ION) || (start_address > TI_MAX_I2C_SIZE)) + status = -ENODEV; + +ExitTiValidateI2cImage: + kfree (buffer); + kfree (rom_desc); + return status; +} + +static int TIReadManufDescriptor (struct edgeport_serial *serial, __u8 *buffer) +{ + int status; + int start_address; + struct ti_i2c_desc *rom_desc; + struct edge_ti_manuf_descriptor *desc; + + rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); + if (!rom_desc) { + err ("%s - out of memory", __FUNCTION__); + return -ENOMEM; + } + start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_ION, rom_desc); + + if (!start_address) { + dbg ("%s - Edge Descriptor not found in I2C", __FUNCTION__); + status = -ENODEV; + goto exit; + } + + // Read the descriptor data + status = TIReadRom (serial, + start_address+sizeof(struct ti_i2c_desc), + rom_desc->Size, + buffer); + if (status) + goto exit; + + status = ValidChecksum(rom_desc, buffer); + + desc = (struct edge_ti_manuf_descriptor *)buffer; + dbg ( "%s - IonConfig 0x%x", __FUNCTION__, desc->IonConfig ); + dbg ( "%s - Version %d", __FUNCTION__, desc->Version ); + dbg ( "%s - Cpu/Board 0x%x", __FUNCTION__, desc->CpuRev_BoardRev ); + dbg ( "%s - NumPorts %d", __FUNCTION__, desc->NumPorts ); + dbg ( "%s - NumVirtualPorts %d", __FUNCTION__, desc->NumVirtualPorts ); + dbg ( "%s - TotalPorts %d", __FUNCTION__, desc->TotalPorts ); + +exit: + kfree (rom_desc); + return status; +} + +/* Build firmware header used for firmware update */ +static int BuildI2CFirmwareHeader (__u8 *header) +{ + __u8 *buffer; + int buffer_size; + int i; + __u8 cs = 0; + struct ti_i2c_desc *i2c_header; + struct ti_i2c_image_header *img_header; + struct ti_i2c_firmware_rec *firmware_rec; + + // In order to update the I2C firmware we must change the type 2 record to type 0xF2. + // This will force the UMP to come up in Boot Mode. Then while in boot mode, the driver + // will download the latest firmware (padded to 15.5k) into the UMP ram. + // And finally when the device comes back up in download mode the driver will cause + // the new firmware to be copied from the UMP Ram to I2C and the firmware will update + // the record type from 0xf2 to 0x02. + + // Allocate a 15.5k buffer + 2 bytes for version number (Firmware Record) + buffer_size = (((1024 * 16) - 512 )+ sizeof(struct ti_i2c_firmware_rec)); + + buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!buffer) { + err ("%s - out of memory", __FUNCTION__); + return -ENOMEM; + } + + // Set entire image of 0xffs + memset (buffer, 0xff, buffer_size); + + // Copy version number into firmware record + firmware_rec = (struct ti_i2c_firmware_rec *)buffer; + + firmware_rec->Ver_Major = OperationalCodeImageVersion.MajorVersion; + firmware_rec->Ver_Minor = OperationalCodeImageVersion.MinorVersion; + + // Pointer to fw_down memory image + img_header = (struct ti_i2c_image_header *)&PagableOperationalCodeImage[0]; + + memcpy (buffer + sizeof(struct ti_i2c_firmware_rec), + &PagableOperationalCodeImage[sizeof(struct ti_i2c_image_header)], + img_header->Length); + + for (i=0; i < buffer_size; i++) { + cs = (__u8)(cs + buffer[i]); + } + + kfree (buffer); + + // Build new header + i2c_header = (struct ti_i2c_desc *)header; + firmware_rec = (struct ti_i2c_firmware_rec*)i2c_header->Data; + + i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK; + i2c_header->Size = (__u16)buffer_size; + i2c_header->CheckSum = cs; + firmware_rec->Ver_Major = OperationalCodeImageVersion.MajorVersion; + firmware_rec->Ver_Minor = OperationalCodeImageVersion.MinorVersion; + + return 0; +} + +/* Try to figure out what type of I2c we have */ +static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial) +{ + int status; + __u8 data; + + // Try to read type 2 + status = TIReadVendorRequestSync (serial->serial->dev, + UMPC_MEMORY_READ, // Request + DTK_ADDR_SPACE_I2C_TYPE_II, // wValue (Address type) + 0, // wIndex + &data, // TransferBuffer + 0x01); // TransferBufferLength + if (status) + dbg ("%s - read 2 status error = %d", __FUNCTION__, status); + else + dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data); + if ((!status) && data == 0x52) { + dbg ("%s - ROM_TYPE_II", __FUNCTION__); + serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; + return 0; + } + + // Try to read type 3 + status = TIReadVendorRequestSync (serial->serial->dev, + UMPC_MEMORY_READ, // Request + DTK_ADDR_SPACE_I2C_TYPE_III, // wValue (Address type) + 0, // wIndex + &data, // TransferBuffer + 0x01); // TransferBufferLength + if (status) + dbg ("%s - read 3 status error = %d", __FUNCTION__, status); + else + dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data); + if ((!status) && data == 0x52) { + dbg ("%s - ROM_TYPE_III", __FUNCTION__); + serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III; + return 0; + } + + dbg ("%s - Unknown", __FUNCTION__); + serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; + return -ENODEV; +} + +static int TISendBulkTransferSync (struct usb_serial *serial, void *buffer, int length, int *num_sent) +{ + int status; + + status = usb_bulk_msg (serial->dev, + usb_sndbulkpipe(serial->dev, + serial->port[0].bulk_out_endpointAddress), + buffer, + length, + num_sent, + HZ); + return status; +} + +/* Download given firmware image to the device (IN BOOT MODE) */ +static int TIDownloadCodeImage (struct edgeport_serial *serial, __u8 *image, int image_length) +{ + int status = 0; + int pos; + int transfer; + int done; + + // Transfer firmware image + for (pos = 0; pos < image_length; ) { + // Read the next buffer from file + transfer = image_length - pos; + if (transfer > EDGE_FW_BULK_MAX_PACKET_SIZE) + transfer = EDGE_FW_BULK_MAX_PACKET_SIZE; + + // Transfer data + status = TISendBulkTransferSync (serial->serial, &image[pos], transfer, &done); + if (status) + break; + // Advance buffer pointer + pos += done; + } + + return status; +} + +// FIXME!!! +static int TIConfigureBootDevice (struct usb_device *dev) +{ + return 0; +} + +/** + * DownloadTIFirmware - Download run-time operating firmware to the TI5052 + * + * This routine downloads the main operating code into the TI5052, using the + * boot code already burned into E2PROM or ROM. + */ +static int TIDownloadFirmware (struct edgeport_serial *serial) +{ + int status = 0; + int start_address; + struct edge_ti_manuf_descriptor *ti_manuf_desc; + struct usb_interface_descriptor *interface; + int download_cur_ver; + int download_new_ver; + + /* This routine is entered by both the BOOT mode and the Download mode + * We can determine which code is running by the reading the config + * descriptor and if we have only one bulk pipe it is in boot mode + */ + serial->product_info.hardware_type = HARDWARE_TYPE_TIUMP; + + /* Default to type 2 i2c */ + serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; + + status = TIChooseConfiguration (serial->serial->dev); + if (status) + return status; + + interface = serial->serial->dev->config->interface->altsetting; + if (!interface) { + err ("%s - no interface set, error!", __FUNCTION__); + return -ENODEV; + } + + // Setup initial mode -- the default mode 0 is TI_MODE_CONFIGURING + // if we have more than one endpoint we are definitely in download mode + if (interface->bNumEndpoints > 1) + serial->product_info.TiMode = TI_MODE_DOWNLOAD; + else + // Otherwise we will remain in configuring mode + serial->product_info.TiMode = TI_MODE_CONFIGURING; + + // Save Download Version Number + OperationalCodeImageVersion.MajorVersion = PagableOperationalCodeImageVersion.MajorVersion; + OperationalCodeImageVersion.MinorVersion = PagableOperationalCodeImageVersion.MinorVersion; + OperationalCodeImageVersion.BuildNumber = PagableOperationalCodeImageVersion.BuildNumber; + + /********************************************************************/ + /* Download Mode */ + /********************************************************************/ + if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { + struct ti_i2c_desc *rom_desc; + + dbg ("%s - <<<<<<<<<<<<<<>>>>>>>>>", __FUNCTION__); + + status = TiValidateI2cImage (serial); + if (status) { + dbg ("%s - <<<<<<<<<<<<<<>>>>>>>>>", + __FUNCTION__); + return status; + } + + /* Validate Hardware version number + * Read Manufacturing Descriptor from TI Based Edgeport + */ + ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL); + if (!ti_manuf_desc) { + err ("%s - out of memory.", __FUNCTION__); + return -ENOMEM; + } + status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc); + if (status) { + kfree (ti_manuf_desc); + return status; + } + + // Check version number of ION descriptor + if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) { + dbg ( "%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__, + TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev)); + kfree (ti_manuf_desc); + return -EINVAL; + } + + rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); + if (!rom_desc) { + err ("%s - out of memory.", __FUNCTION__); + kfree (ti_manuf_desc); + return -ENOMEM; + } + + // Search for type 2 record (firmware record) + if ((start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc)) != 0) { + struct ti_i2c_firmware_rec *firmware_version; + __u8 record; + + dbg ("%s - Found Type FIRMWARE (Type 2) record", __FUNCTION__); + + firmware_version = kmalloc (sizeof (*firmware_version), GFP_KERNEL); + if (!firmware_version) { + err ("%s - out of memory.", __FUNCTION__); + kfree (rom_desc); + kfree (ti_manuf_desc); + return -ENOMEM; + } + + // Validate version number + // Read the descriptor data + status = TIReadRom (serial, + start_address+sizeof(struct ti_i2c_desc), + sizeof(struct ti_i2c_firmware_rec), + (__u8 *)firmware_version); + if (status) { + kfree (firmware_version); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + + // Check version number of download with current version in I2c + download_cur_ver = (firmware_version->Ver_Major << 8) + + (firmware_version->Ver_Minor); + download_new_ver = (OperationalCodeImageVersion.MajorVersion << 8) + + (OperationalCodeImageVersion.MinorVersion); + + dbg ("%s - >>>Firmware Versions Device %d.%d Driver %d.%d", + __FUNCTION__, + firmware_version->Ver_Major, + firmware_version->Ver_Minor, + OperationalCodeImageVersion.MajorVersion, + OperationalCodeImageVersion.MinorVersion); + + // Check if we have an old version in the I2C and update if necessary + if (download_cur_ver != download_new_ver) { + dbg ("%s - Update I2C Download from %d.%d to %d.%d", + __FUNCTION__, + firmware_version->Ver_Major, + firmware_version->Ver_Minor, + OperationalCodeImageVersion.MajorVersion, + OperationalCodeImageVersion.MinorVersion); + + // In order to update the I2C firmware we must change the type 2 record to type 0xF2. + // This will force the UMP to come up in Boot Mode. Then while in boot mode, the driver + // will download the latest firmware (padded to 15.5k) into the UMP ram. + // And finally when the device comes back up in download mode the driver will cause + // the new firmware to be copied from the UMP Ram to I2C and the firmware will update + // the record type from 0xf2 to 0x02. + + record = I2C_DESC_TYPE_FIRMWARE_BLANK; + + // Change the I2C Firmware record type to 0xf2 to trigger an update + status = TIWriteRom (serial, + start_address, + sizeof(record), + &record); + if (status) { + kfree (firmware_version); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + + // verify the write -- must do this in order for write to + // complete before we do the hardware reset + status = TIReadRom (serial, + start_address, + sizeof(record), + &record); + + if (status) { + kfree (firmware_version); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + + if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) { + err ("%s - error resetting device", __FUNCTION__); + kfree (firmware_version); + kfree (rom_desc); + kfree (ti_manuf_desc); + return -ENODEV; + } + + dbg ("%s - HARDWARE RESET", __FUNCTION__); + + // Reset UMP -- Back to BOOT MODE + status = TISendVendorRequestSync (serial->serial->dev, + UMPC_HARDWARE_RESET, // Request + 0, // wValue + 0, // wIndex + NULL, // TransferBuffer + 0); // TransferBufferLength + + dbg ( "%s - HARDWARE RESET return %d", __FUNCTION__, status); + + /* return an error on purpose. */ + return -ENODEV; + } + } + // Search for type 0xF2 record (firmware blank record) + else if ((start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc)) != 0) { + #define HEADER_SIZE (sizeof(struct ti_i2c_desc) + sizeof(struct ti_i2c_firmware_rec)) + __u8 *header; + __u8 *vheader; + + header = kmalloc (HEADER_SIZE, GFP_KERNEL); + if (!header) { + err ("%s - out of memory.", __FUNCTION__); + kfree (rom_desc); + kfree (ti_manuf_desc); + return -ENOMEM; + } + + vheader = kmalloc (HEADER_SIZE, GFP_KERNEL); + if (!vheader) { + err ("%s - out of memory.", __FUNCTION__); + kfree (header); + kfree (rom_desc); + kfree (ti_manuf_desc); + return -ENOMEM; + } + + dbg ("%s - Found Type BLANK FIRMWARE (Type F2) record", __FUNCTION__); + + // In order to update the I2C firmware we must change the type 2 record to type 0xF2. + // This will force the UMP to come up in Boot Mode. Then while in boot mode, the driver + // will download the latest firmware (padded to 15.5k) into the UMP ram. + // And finally when the device comes back up in download mode the driver will cause + // the new firmware to be copied from the UMP Ram to I2C and the firmware will update + // the record type from 0xf2 to 0x02. + status = BuildI2CFirmwareHeader(header); + if (status) { + kfree (vheader); + kfree (header); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + + // Update I2C with type 0xf2 record with correct size and checksum + status = TIWriteRom (serial, + start_address, + HEADER_SIZE, + header); + if (status) { + kfree (vheader); + kfree (header); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + + // verify the write -- must do this in order for write to + // complete before we do the hardware reset + status = TIReadRom (serial, + start_address, + HEADER_SIZE, + vheader); + + if (status) { + dbg ("%s - can't read header back", __FUNCTION__); + kfree (vheader); + kfree (header); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + if (memcmp(vheader, header, HEADER_SIZE)) { + dbg ("%s - write download record failed", __FUNCTION__); + kfree (vheader); + kfree (header); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + + kfree (vheader); + kfree (header); + + dbg ("%s - Start firmware update", __FUNCTION__); + + // Tell firmware to copy download image into I2C + status = TISendVendorRequestSync (serial->serial->dev, + UMPC_COPY_DNLD_TO_I2C, // Request + 0, // wValue + 0, // wIndex + NULL, // TransferBuffer + 0); // TransferBufferLength + + dbg ("%s - Update complete 0x%x", __FUNCTION__, status); + if (status) { + dbg ("%s - UMPC_COPY_DNLD_TO_I2C failed", __FUNCTION__); + kfree (rom_desc); + kfree (ti_manuf_desc); + return status; + } + } + + // The device is running the download code + kfree (rom_desc); + kfree (ti_manuf_desc); + return 0; + } + + /********************************************************************/ + /* Boot Mode */ + /********************************************************************/ + dbg ("%s - <<<<<<<<<<<<<<>>>>>>>>>>>>>>", + __FUNCTION__); + + // Configure the TI device so we can use the BULK pipes for download + status = TIConfigureBootDevice (serial->serial->dev); + if (status) + return status; + + if (serial->serial->dev->descriptor.idVendor != USB_VENDOR_ID_ION) { + dbg ("%s - VID = 0x%x", __FUNCTION__, + serial->serial->dev->descriptor.idVendor); + serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; + goto StayInBootMode; + } + + // We have an ION device (I2c Must be programmed) + // Determine I2C image type + if (TIGetI2cTypeInBootMode(serial)) { + goto StayInBootMode; + } + + // Registry variable set? + if (TIStayInBootMode) { + dbg ("%s - TIStayInBootMode", __FUNCTION__); + goto StayInBootMode; + } + + // Check for ION Vendor ID and that the I2C is valid + if (!TiValidateI2cImage(serial)) { + struct ti_i2c_image_header *header; + int i; + __u8 cs = 0; + __u8 *buffer; + int buffer_size; + + /* Validate Hardware version number + * Read Manufacturing Descriptor from TI Based Edgeport + */ + ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL); + if (!ti_manuf_desc) { + err ("%s - out of memory.", __FUNCTION__); + return -ENOMEM; + } + status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc); + if (status) { + kfree (ti_manuf_desc); + goto StayInBootMode; + } + + // Check for version 2 + if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) { + dbg ("%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__, + TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev)); + kfree (ti_manuf_desc); + goto StayInBootMode; + } + + kfree (ti_manuf_desc); + + // In order to update the I2C firmware we must change the type 2 record to type 0xF2. + // This will force the UMP to come up in Boot Mode. Then while in boot mode, the driver + // will download the latest firmware (padded to 15.5k) into the UMP ram. + // And finally when the device comes back up in download mode the driver will cause + // the new firmware to be copied from the UMP Ram to I2C and the firmware will update + // the record type from 0xf2 to 0x02. + + /* + * Do we really have to copy the whole firmware image, + * or could we do this in place! + */ + + // Allocate a 15.5k buffer + 3 byte header + buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header)); + buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!buffer) { + err ("%s - out of memory", __FUNCTION__); + return -ENOMEM; + } + + // Initialize the buffer to 0xff (pad the buffer) + memset (buffer, 0xff, buffer_size); + + memcpy (buffer, &PagableOperationalCodeImage[0], PagableOperationalCodeSize); + + for(i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) { + cs = (__u8)(cs + buffer[i]); + } + + header = (struct ti_i2c_image_header *)buffer; + + // update length and checksum after padding + header->Length = (__u16)(buffer_size - sizeof(struct ti_i2c_image_header)); + header->CheckSum = cs; + + // Download the operational code + dbg ("%s - Downloading operational code image (TI UMP)", __FUNCTION__); + status = TIDownloadCodeImage (serial, buffer, buffer_size); + + kfree (buffer); + + if (status) { + dbg ("%s - Error downloading operational code image", __FUNCTION__); + return status; + } + + // Device will reboot + serial->product_info.TiMode = TI_MODE_TRANSITIONING; + + dbg ("%s - Download successful -- Device rebooting...", __FUNCTION__); + + /* return an error on purpose */ + return -ENODEV; + } + +StayInBootMode: + // Eprom is invalid or blank stay in boot mode + dbg ("%s - <<<<<<<<<<<<<<>>>>>>>>>>>", __FUNCTION__); + serial->product_info.TiMode = TI_MODE_BOOT; + + return 0; +} + + +static int TISetDtr (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + port->shadow_mcr |= MCR_DTR; + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_DTR, + (__u8)(UMPM_UART1_PORT + port_number), + 1, /* set */ + NULL, + 0); +} + +static int TIClearDtr (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + port->shadow_mcr &= ~MCR_DTR; + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_DTR, + (__u8)(UMPM_UART1_PORT + port_number), + 0, /* clear */ + NULL, + 0); +} + +static int TISetRts (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + port->shadow_mcr |= MCR_RTS; + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_RTS, + (__u8)(UMPM_UART1_PORT + port_number), + 1, /* set */ + NULL, + 0); +} + +static int TIClearRts (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + port->shadow_mcr &= ~MCR_RTS; + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_RTS, + (__u8)(UMPM_UART1_PORT + port_number), + 0, /* clear */ + NULL, + 0); +} + +static int TISetLoopBack (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_LOOPBACK, + (__u8)(UMPM_UART1_PORT + port_number), + 1, /* set */ + NULL, + 0); +} + +static int TIClearLoopBack (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_LOOPBACK, + (__u8)(UMPM_UART1_PORT + port_number), + 0, /* clear */ + NULL, + 0); +} + +static int TISetBreak (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_BREAK, + (__u8)(UMPM_UART1_PORT + port_number), + 1, /* set */ + NULL, + 0); +} + +static int TIClearBreak (struct edgeport_port *port) +{ + int port_number = port->port->number - port->port->serial->minor; + + dbg ("%s", __FUNCTION__); + + return TIWriteCommandSync (port->port->serial->dev, + UMPC_SET_CLR_BREAK, + (__u8)(UMPM_UART1_PORT + port_number), + 0, /* clear */ + NULL, + 0); +} + +static int TIRestoreMCR (struct edgeport_port *port, __u8 mcr) +{ + int status = 0; + + dbg ("%s - %x", __FUNCTION__, mcr); + + if (mcr & MCR_DTR) + status = TISetDtr (port); + else + status = TIClearDtr (port); + + if (status) + return status; + + if (mcr & MCR_RTS) + status = TISetRts (port); + else + status = TIClearRts (port); + + if (status) + return status; + + if (mcr & MCR_LOOPBACK) + status = TISetLoopBack (port); + else + status = TIClearLoopBack (port); + + return status; +} + + + +/* Convert TI LSR to standard UART flags */ +static __u8 MapLineStatus (__u8 ti_lsr) +{ + __u8 lsr = 0; + +#define MAP_FLAG(flagUmp, flagUart) \ + if (ti_lsr & flagUmp) lsr |= flagUart; + + MAP_FLAG(UMP_UART_LSR_OV_MASK, LSR_OVER_ERR) /* overrun */ + MAP_FLAG(UMP_UART_LSR_PE_MASK, LSR_PAR_ERR) /* parity error */ + MAP_FLAG(UMP_UART_LSR_FE_MASK, LSR_FRM_ERR) /* framing error */ + MAP_FLAG(UMP_UART_LSR_BR_MASK, LSR_BREAK) /* break detected */ + MAP_FLAG(UMP_UART_LSR_RX_MASK, LSR_RX_AVAIL) /* receive data available */ + MAP_FLAG(UMP_UART_LSR_TX_MASK, LSR_TX_EMPTY) /* transmit holding register empty */ + +#undef MAP_FLAG + + return lsr; +} + +static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr) +{ + struct async_icount *icount; + + dbg ("%s - %02x", __FUNCTION__, msr); + + if (msr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) { + icount = &edge_port->icount; + + /* update input line counters */ + if (msr & MSR_DELTA_CTS) + icount->cts++; + if (msr & MSR_DELTA_DSR) + icount->dsr++; + if (msr & MSR_DELTA_CD) + icount->dcd++; + if (msr & MSR_DELTA_RI) + icount->rng++; + wake_up_interruptible (&edge_port->delta_msr_wait); + } + + /* Save the new modem status */ + edge_port->shadow_msr = msr & 0xf0; + + return; +} + +static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8 lsr, __u8 data) +{ + struct async_icount *icount; + __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); + + dbg ("%s - %02x", __FUNCTION__, new_lsr); + + edge_port->shadow_lsr = lsr; + + if (new_lsr & LSR_BREAK) { + /* + * Parity and Framing errors only count if they + * occur exclusive of a break being received. + */ + new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); + } + + /* Place LSR data byte into Rx buffer */ + if (lsr_data && edge_port->port->tty) { + tty_insert_flip_char(edge_port->port->tty, data, 0); + tty_flip_buffer_push(edge_port->port->tty); + } + + /* update input line counters */ + icount = &edge_port->icount; + if (new_lsr & LSR_BREAK) + icount->brk++; + if (new_lsr & LSR_OVER_ERR) + icount->overrun++; + if (new_lsr & LSR_PAR_ERR) + icount->parity++; + if (new_lsr & LSR_FRM_ERR) + icount->frame++; +} + + +static void edge_interrupt_callback (struct urb *urb) +{ + struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; + struct usb_serial_port *port; + struct edgeport_port *edge_port; + unsigned char *data = urb->transfer_buffer; + int length = urb->actual_length; + int port_number; + int function; + __u8 lsr; + __u8 msr; + + dbg("%s", __FUNCTION__); + + if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) { + return; + } + + if (urb->status) { + dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status); + return; + } + + if (!length) { + dbg ("%s - no data in urb", __FUNCTION__); + return; + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, length, data); + + if (length != 2) { + dbg ("%s - expecting packet of size 2, got %d", __FUNCTION__, length); + return; + } + + port_number = TIUMP_GET_PORT_FROM_CODE (data[0]); + function = TIUMP_GET_FUNC_FROM_CODE (data[0]); + dbg ("%s - port_number %d, function %d, info 0x%x", + __FUNCTION__, port_number, function, data[1]); + port = &edge_serial->serial->port[port_number]; + if (port_paranoia_check (port, __FUNCTION__)) { + dbg ("%s - change found for port that is not present", + __FUNCTION__); + return; + } + edge_port = port->private; + if (!edge_port) { + dbg ("%s - edge_port not found", __FUNCTION__); + return; + } + switch (function) { + case TIUMP_INTERRUPT_CODE_LSR: + lsr = MapLineStatus(data[1]); + if (lsr & UMP_UART_LSR_DATA_MASK) { + /* Save the LSR event for bulk read completion routine */ + dbg ("%s - LSR Event Port %u LSR Status = %02x", + __FUNCTION__, port_number, lsr); + edge_port->lsr_event = 1; + edge_port->lsr_mask = lsr; + } else { + dbg ("%s - ===== Port %d LSR Status = %02x ======", + __FUNCTION__, port_number, lsr); + handle_new_lsr (edge_port, 0, lsr, 0); + } + break; + + case TIUMP_INTERRUPT_CODE_MSR: // MSR + /* Copy MSR from UMP */ + msr = data[1]; + dbg ("%s - ===== Port %u MSR Status = %02x ======\n", + __FUNCTION__, port_number, msr); + handle_new_msr (edge_port, msr); + break; + + default: + err ("%s - Unknown Interrupt code from UMP %x\n", + __FUNCTION__, data[1]); + break; + + } +} + +static void edge_bulk_in_callback (struct urb *urb) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; + unsigned char *data = urb->transfer_buffer; + struct tty_struct *tty; + int status; + int i; + int port_number; + + dbg("%s", __FUNCTION__); + + if (port_paranoia_check (edge_port->port, __FUNCTION__)) + return; + + if (urb->status) { + dbg ("%s - nonzero read bulk status received: %d", + __FUNCTION__, urb->status); + + if (urb->status == -EPIPE) { + /* clear any problem that might have happened on this pipe */ + usb_clear_halt (edge_port->port->serial->dev, urb->pipe); + goto exit; + } + return; + } + + port_number = edge_port->port->number - edge_port->port->serial->minor; + + if (edge_port->lsr_event) { + edge_port->lsr_event = 0; + dbg ("%s ===== Port %u LSR Status = %02x, Data = %02x ======", + __FUNCTION__, port_number, edge_port->lsr_mask, *data); + handle_new_lsr (edge_port, 1, edge_port->lsr_mask, *data); + /* Adjust buffer length/pointer */ + --urb->actual_length; + ++data; + } + + tty = edge_port->port->tty; + if (tty && urb->actual_length) { + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + if (edge_port->close_pending) { + dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__); + } else { + for (i = 0; i < urb->actual_length ; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, + * we drop them. */ + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through unless + * tty->low_latency is set */ + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + edge_port->icount.rx += urb->actual_length; + } + +exit: + /* continue always trying to read */ + urb->dev = edge_port->port->serial->dev; + status = usb_submit_urb (urb, GFP_ATOMIC); + if (status) + err ("%s - usb_submit_urb failed with result %d", + __FUNCTION__, status); +} + +static void edge_bulk_out_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct tty_struct *tty; + + dbg ("%s - port %d", __FUNCTION__, port->number); + + if (!serial) { + dbg ("%s - bad serial pointer, exiting", __FUNCTION__); + return; + } + + if (urb->status) { + dbg ("%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); + + if (urb->status == -EPIPE) { + /* clear any problem that might have happened on this pipe */ + usb_clear_halt (serial->dev, urb->pipe); + } + return; + } + + tty = port->tty; + if (tty) { + /* let the tty driver wakeup if it has a special write_wakeup function */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { + (tty->ldisc.write_wakeup)(tty); + } + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&tty->write_wait); + } +} + +static int edge_open (struct usb_serial_port *port, struct file * filp) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)port->private; + struct edgeport_serial *edge_serial; + struct usb_device *dev; + struct urb *urb; + int port_number; + int status; + u16 open_settings; + u8 transaction_timeout; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (edge_port == NULL) + return -ENODEV; + + /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates (like with OHCI) data + can get lost. */ + if (port->tty) + port->tty->low_latency = 1; + + port_number = port->number - port->serial->minor; + switch (port_number) { + case 0: + edge_port->uart_base = UMPMEM_BASE_UART1; + edge_port->dma_address = UMPD_OEDB1_ADDRESS; + break; + case 1: + edge_port->uart_base = UMPMEM_BASE_UART2; + edge_port->dma_address = UMPD_OEDB2_ADDRESS; + break; + default: + err ("Unknown port number!!!"); + return -ENODEV; + } + + dbg ("%s - port_number = %d, uart_base = %04x, dma_address = %04x", + __FUNCTION__, port_number, edge_port->uart_base, edge_port->dma_address); + + dev = port->serial->dev; + + memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount)); + init_waitqueue_head (&edge_port->delta_msr_wait); + + /* turn off loopback */ + status = TIClearLoopBack (edge_port); + if (status) + return status; + + /* set up the port settings */ + edge_set_termios (port, NULL); + + /* open up the port */ + + /* milliseconds to timeout for DMA transfer */ + transaction_timeout = 2; + + edge_port->ump_read_timeout = max (20, ((transaction_timeout * 3) / 2) ); + + // milliseconds to timeout for DMA transfer + open_settings = (u8)(UMP_DMA_MODE_CONTINOUS | + UMP_PIPE_TRANS_TIMEOUT_ENA | + (transaction_timeout << 2)); + + dbg ("%s - Sending UMPC_OPEN_PORT", __FUNCTION__); + + /* Tell TI to open and start the port */ + status = TIWriteCommandSync (dev, + UMPC_OPEN_PORT, + (u8)(UMPM_UART1_PORT + port_number), + open_settings, + NULL, + 0); + if (status) + return status; + + /* Start the DMA? */ + status = TIWriteCommandSync (dev, + UMPC_START_PORT, + (u8)(UMPM_UART1_PORT + port_number), + 0, + NULL, + 0); + if (status) + return status; + + /* Clear TX and RX buffers in UMP */ + status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN); + if (status) + return status; + + /* Read Initial MSR */ + status = TIReadVendorRequestSync (dev, + UMPC_READ_MSR, // Request + 0, // wValue + (__u16)(UMPM_UART1_PORT + port_number), // wIndex (Address) + &edge_port->shadow_msr, // TransferBuffer + 1); // TransferBufferLength + if (status) + return status; + + dbg ("ShadowMSR 0x%X", edge_port->shadow_msr); + + edge_serial = edge_port->edge_serial; + if (edge_serial->num_ports_open == 0) { + /* we are the first port to be opened, let's post the interrupt urb */ + urb = edge_serial->serial->port[0].interrupt_in_urb; + if (!urb) { + err ("%s - no interrupt urb present, exiting", __FUNCTION__); + return -EINVAL; + } + urb->complete = edge_interrupt_callback; + urb->context = edge_serial; + urb->dev = dev; + status = usb_submit_urb (urb, GFP_KERNEL); + if (status) { + err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status); + return status; + } + } + + /* + * reset the data toggle on the bulk endpoints to work around bug in + * host controllers where things get out of sync some times + */ + usb_clear_halt (dev, port->write_urb->pipe); + usb_clear_halt (dev, port->read_urb->pipe); + + /* start up our bulk read urb */ + urb = port->read_urb; + if (!urb) { + err ("%s - no read urb present, exiting", __FUNCTION__); + return -EINVAL; + } + urb->complete = edge_bulk_in_callback; + urb->context = edge_port; + urb->dev = dev; + status = usb_submit_urb (urb, GFP_KERNEL); + if (status) { + err ("%s - read bulk usb_submit_urb failed with value %d", __FUNCTION__, status); + return status; + } + + ++edge_serial->num_ports_open; + + dbg("%s - exited", __FUNCTION__); + + return 0; +} + +static void edge_close (struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial; + struct edgeport_serial *edge_serial; + struct edgeport_port *edge_port; + int port_number; + int status; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + edge_serial = (struct edgeport_serial *)serial->private; + edge_port = (struct edgeport_port *)port->private; + if ((edge_serial == NULL) || (edge_port == NULL)) + return; + + if (serial->dev) { + /* The bulkreadcompletion routine will check + * this flag and dump add read data */ + edge_port->close_pending = 1; + + /* chase the port close */ + TIChasePort (edge_port); + + usb_unlink_urb (port->read_urb); + + /* assuming we can still talk to the device, + * send a close port command to it */ + dbg("%s - send umpc_close_port", __FUNCTION__); + port_number = port->number - port->serial->minor; + status = TIWriteCommandSync (port->serial->dev, + UMPC_CLOSE_PORT, + (__u8)(UMPM_UART1_PORT + port_number), + 0, + NULL, + 0); + --edge_port->edge_serial->num_ports_open; + if (edge_port->edge_serial->num_ports_open <= 0) { + /* last port is now closed, let's shut down our interrupt urb */ + usb_unlink_urb (serial->port[0].interrupt_in_urb); + edge_port->edge_serial->num_ports_open = 0; + } + edge_port->close_pending = 0; + } + + dbg(__FUNCTION__" exited"); +} + +static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count) +{ + struct usb_serial *serial = port->serial; + struct edgeport_port *edge_port = port->private; + int result; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (count == 0) { + dbg("%s - write request of 0 bytes", __FUNCTION__); + return 0; + } + + if (edge_port == NULL) + return -ENODEV; + if (edge_port->close_pending == 1) + return -ENODEV; + + if (port->write_urb->status == -EINPROGRESS) { + dbg ("%s - already writing", __FUNCTION__); + return 0; + } + + count = min (count, port->bulk_out_size); + + if (from_user) { + if (copy_from_user(port->write_urb->transfer_buffer, data, count)) + return -EFAULT; + } else { + memcpy (port->write_urb->transfer_buffer, data, count); + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + + /* set up our urb */ + usb_fill_bulk_urb (port->write_urb, serial->dev, + usb_sndbulkpipe (serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, + edge_bulk_out_callback, + port); + + /* send the data out the bulk port */ + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (result) + err(__FUNCTION__ " - failed submitting write urb, error %d", result); + else + result = count; + + if (result > 0) + edge_port->icount.tx += count; + + return result; +} + +static int edge_write_room (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + int room = 0; + + dbg(__FUNCTION__); + + if (edge_port == NULL) + return -ENODEV; + if (edge_port->close_pending == 1) + return -ENODEV; + + dbg(__FUNCTION__" - port %d", port->number); + + if (port->write_urb->status != -EINPROGRESS) + room = port->bulk_out_size; + + dbg(__FUNCTION__ " - returns %d", room); + return room; +} + +static int edge_chars_in_buffer (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + int chars = 0; + + dbg(__FUNCTION__); + + if (edge_port == NULL) + return -ENODEV; + if (edge_port->close_pending == 1) + return -ENODEV; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (port->write_urb->status == -EINPROGRESS) + chars = port->write_urb->transfer_buffer_length; + + dbg ("%s - returns %d", __FUNCTION__, chars); + return chars; +} + +static void edge_throttle (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct tty_struct *tty; + int status; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (edge_port == NULL) + return; + + tty = port->tty; + if (!tty) { + dbg ("%s - no tty available", __FUNCTION__); + return; + } + /* if we are implementing XON/XOFF, send the stop character */ + if (I_IXOFF(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + status = edge_write (port, 0, &stop_char, 1); + if (status <= 0) { + return; + } + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + status = TIClearRts (edge_port); + } + + usb_unlink_urb (port->read_urb); +} + +static void edge_unthrottle (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct tty_struct *tty; + int status; + + dbg(__FUNCTION__" - port %d", port->number); + + if (edge_port == NULL) + return; + + tty = port->tty; + if (!tty) { + dbg ("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the start character */ + if (I_IXOFF(tty)) { + unsigned char start_char = START_CHAR(tty); + status = edge_write (port, 0, &start_char, 1); + if (status <= 0) { + return; + } + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + status = TISetRts (edge_port); + } + + port->read_urb->dev = port->serial->dev; + status = usb_submit_urb (port->read_urb, GFP_ATOMIC); + if (status) { + err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status); + } +} + + +static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +{ + struct ump_uart_config *config; + struct tty_struct *tty; + int baud; + int round; + unsigned cflag; + int status; + int port_number = edge_port->port->number - edge_port->port->serial->minor; + + dbg("%s - port %d", __FUNCTION__, edge_port->port->number); + + tty = edge_port->port->tty; + if ((!tty) || + (!tty->termios)) { + dbg("%s - no tty structures", __FUNCTION__); + return; + } + + config = kmalloc (sizeof (*config), GFP_KERNEL); + if (!config) { + err ("%s - out of memory", __FUNCTION__); + return; + } + + cflag = tty->termios->c_cflag; + + config->wFlags = 0; + + /* These flags must be set */ + config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT; + config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR; + config->bUartMode = 0; + + switch (cflag & CSIZE) { + case CS5: + config->bDataBits = UMP_UART_CHAR5BITS; + dbg ("%s - data bits = 5", __FUNCTION__); + break; + case CS6: + config->bDataBits = UMP_UART_CHAR6BITS; + dbg ("%s - data bits = 6", __FUNCTION__); + break; + case CS7: + config->bDataBits = UMP_UART_CHAR7BITS; + dbg ("%s - data bits = 7", __FUNCTION__); + break; + default: + case CS8: + config->bDataBits = UMP_UART_CHAR8BITS; + dbg ("%s - data bits = 8", __FUNCTION__); + break; + } + + if (cflag & PARENB) { + if (cflag & PARODD) { + config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; + config->bParity = UMP_UART_ODDPARITY; + dbg(__FUNCTION__" - parity = odd"); + } else { + config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; + config->bParity = UMP_UART_EVENPARITY; + dbg(__FUNCTION__" - parity = even"); + } + } else { + config->bParity = UMP_UART_NOPARITY; + dbg(__FUNCTION__" - parity = none"); + } + + if (cflag & CSTOPB) { + config->bStopBits = UMP_UART_STOPBIT2; + dbg(__FUNCTION__" - stop bits = 2"); + } else { + config->bStopBits = UMP_UART_STOPBIT1; + dbg(__FUNCTION__" - stop bits = 1"); + } + + /* figure out the flow control settings */ + if (cflag & CRTSCTS) { + config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW; + config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW; + dbg(__FUNCTION__" - RTS/CTS is enabled"); + } else { + dbg(__FUNCTION__" - RTS/CTS is disabled"); + } + + /* if we are implementing XON/XOFF, set the start and stop character in the device */ + if (I_IXOFF(tty) || I_IXON(tty)) { + config->cXon = START_CHAR(tty); + config->cXoff = STOP_CHAR(tty); + + /* if we are implementing INBOUND XON/XOFF */ + if (I_IXOFF(tty)) { + config->wFlags |= UMP_MASK_UART_FLAGS_IN_X; + dbg ("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", + __FUNCTION__, config->cXon, config->cXoff); + } else { + dbg ("%s - INBOUND XON/XOFF is disabled", __FUNCTION__); + } + + /* if we are implementing OUTBOUND XON/XOFF */ + if (I_IXON(tty)) { + config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X; + dbg ("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", + __FUNCTION__, config->cXon, config->cXoff); + } else { + dbg ("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__); + } + } + + /* Round the baud rate */ + baud = tty_get_baud_rate(tty); + if (!baud) { + /* pick a default, any default... */ + baud = 9600; + } + config->wBaudRate = (__u16)(461550L / baud); + round = 4615500L / baud; + if ((round - (config->wBaudRate * 10)) >= 5) + config->wBaudRate++; + + dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate); + + dbg ("wBaudRate: %d", (int)(461550L / config->wBaudRate)); + dbg ("wFlags: 0x%x", config->wFlags); + dbg ("bDataBits: %d", config->bDataBits); + dbg ("bParity: %d", config->bParity); + dbg ("bStopBits: %d", config->bStopBits); + dbg ("cXon: %d", config->cXon); + dbg ("cXoff: %d", config->cXoff); + dbg ("bUartMode: %d", config->bUartMode); + + /* move the word values into big endian mode */ + cpu_to_be16s (&config->wFlags); + cpu_to_be16s (&config->wBaudRate); + + status = TIWriteCommandSync (edge_port->port->serial->dev, + UMPC_SET_CONFIG, + (__u8)(UMPM_UART1_PORT + port_number), + 0, + (__u8 *)config, + sizeof(*config)); + if (status) { + dbg ("%s - error %d when trying to write config to device", + __FUNCTION__, status); + } + + kfree (config); + + return; +} + +static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct tty_struct *tty = port->tty; + unsigned int cflag; + + if (!port->tty || !port->tty->termios) { + dbg ("%s - no tty or termios", __FUNCTION__); + return; + } + + cflag = tty->termios->c_cflag; + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg ("%s - nothing to change", __FUNCTION__); + return; + } + } + + dbg("%s - clfag %08x iflag %08x", __FUNCTION__, + tty->termios->c_cflag, + RELEVANT_IFLAG(tty->termios->c_iflag)); + if (old_termios) { + dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, + RELEVANT_IFLAG(old_termios->c_iflag)); + } + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (edge_port == NULL) + return; + + /* change the port settings to the new ones specified */ + change_port_settings (edge_port, old_termios); + + return; +} + +static int set_modem_info (struct edgeport_port *edge_port, unsigned int cmd, unsigned int *value) +{ + unsigned int mcr = edge_port->shadow_mcr; + unsigned int arg; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + mcr |= MCR_RTS; + if (arg & TIOCM_DTR) + mcr |= MCR_RTS; + if (arg & TIOCM_LOOP) + mcr |= MCR_LOOPBACK; + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + mcr &= ~MCR_RTS; + if (arg & TIOCM_DTR) + mcr &= ~MCR_RTS; + if (arg & TIOCM_LOOP) + mcr &= ~MCR_LOOPBACK; + break; + + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK); + mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0); + break; + } + + edge_port->shadow_mcr = mcr; + + TIRestoreMCR (edge_port, mcr); + + return 0; +} + +static int get_modem_info (struct edgeport_port *edge_port, unsigned int *value) +{ + unsigned int result = 0; + unsigned int msr = edge_port->shadow_msr; + unsigned int mcr = edge_port->shadow_mcr; + + result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ + | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ + | ((msr & MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + + + dbg(__FUNCTION__" -- %x", result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int get_serial_info (struct edgeport_port *edge_port, struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + tmp.type = PORT_16550A; + tmp.line = edge_port->port->serial->minor; + tmp.port = edge_port->port->number; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = edge_port->port->bulk_out_size; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; +// tmp.custom_divisor = state->custom_divisor; +// tmp.hub6 = state->hub6; +// tmp.io_type = state->io_type; + + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct async_icount cnow; + struct async_icount cprev; + + dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd); + + switch (cmd) { + case TIOCINQ: + dbg(__FUNCTION__" (%d) TIOCINQ", port->number); +// return get_number_bytes_avail(edge_port, (unsigned int *) arg); + break; + + case TIOCSERGETLSR: + dbg(__FUNCTION__" (%d) TIOCSERGETLSR", port->number); +// return get_lsr_info(edge_port, (unsigned int *) arg); + break; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET", port->number); + return set_modem_info(edge_port, cmd, (unsigned int *) arg); + break; + + case TIOCMGET: + dbg(__FUNCTION__" (%d) TIOCMGET", port->number); + return get_modem_info(edge_port, (unsigned int *) arg); + break; + + case TIOCGSERIAL: + dbg(__FUNCTION__" (%d) TIOCGSERIAL", port->number); + return get_serial_info(edge_port, (struct serial_struct *) arg); + break; + + case TIOCSSERIAL: + dbg(__FUNCTION__" (%d) TIOCSSERIAL", port->number); + break; + + case TIOCMIWAIT: + dbg(__FUNCTION__" (%d) TIOCMIWAIT", port->number); + cprev = edge_port->icount; + while (1) { + interruptible_sleep_on(&edge_port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + cnow = edge_port->icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* not reached */ + break; + + case TIOCGICOUNT: + dbg ("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, + port->number, edge_port->icount.rx, edge_port->icount.tx); + if (copy_to_user((void *)arg, &edge_port->icount, sizeof(edge_port->icount))) + return -EFAULT; + return 0; + } + + return -ENOIOCTLCMD; +} + +static void edge_break (struct usb_serial_port *port, int break_state) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + int status; + + dbg ("%s - state = %d", __FUNCTION__, break_state); + + /* chase the port close */ + TIChasePort (edge_port); + + if (break_state == -1) { + status = TISetBreak (edge_port); + } else { + status = TIClearBreak (edge_port); + } + if (status) { + dbg ("%s - error %d sending break set/clear command.", + __FUNCTION__, status); + } +} + +static int edge_startup (struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial; + struct edgeport_port *edge_port; + struct usb_device *dev; + int status; + int i; + + dev = serial->dev; + + /* create our private serial structure */ + edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); + if (edge_serial == NULL) { + err(__FUNCTION__" - Out of memory"); + return -ENOMEM; + } + memset (edge_serial, 0, sizeof(struct edgeport_serial)); + edge_serial->serial = serial; + serial->private = edge_serial; + + status = TIDownloadFirmware (edge_serial); + if (status) { + kfree (edge_serial); + return status; + } + + /* set up our port private structures */ + for (i = 0; i < serial->num_ports; ++i) { + edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); + if (edge_port == NULL) { + err(__FUNCTION__" - Out of memory"); + return -ENOMEM; + } + memset (edge_port, 0, sizeof(struct edgeport_port)); + edge_port->port = &serial->port[i]; + edge_port->edge_serial = edge_serial; + serial->port[i].private = edge_port; + } + + return 0; +} + +static void edge_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + for (i=0; i < serial->num_ports; ++i) { + kfree (serial->port[i].private); + serial->port[i].private = NULL; + } + kfree (serial->private); + serial->private = NULL; +} + + +static struct usb_serial_device_type edgeport_1port_device = { + owner: THIS_MODULE, + name: "Edgeport TI 1 port adapter", + id_table: edgeport_1port_id_table, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + attach: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +static struct usb_serial_device_type edgeport_2port_device = { + owner: THIS_MODULE, + name: "Edgeport TI 2 port adapter", + id_table: edgeport_2port_id_table, + num_interrupt_in: 1, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + attach: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + + +static int __init edgeport_init(void) +{ + usb_serial_register (&edgeport_1port_device); + usb_serial_register (&edgeport_2port_device); + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +} + +static void __exit edgeport_exit (void) +{ + usb_serial_deregister (&edgeport_1port_device); + usb_serial_deregister (&edgeport_2port_device); +} + +module_init(edgeport_init); +module_exit(edgeport_exit); + +/* Module information */ +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +MODULE_PARM(ignore_cpu_rev, "i"); +MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device"); + diff -Nru a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/serial/io_ti.h Fri Jul 26 19:58:52 2002 @@ -0,0 +1,180 @@ +/***************************************************************************** + * + * Copyright (c) 1997-2002 Inside Out Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + * Feb-16-2001 DMI Added I2C structure definitions + * May-29-2002 gkh Ported to Linux + * + * + ******************************************************************************/ + +#ifndef _IO_TI_H_ +#define _IO_TI_H_ + +/* Address Space */ +#define DTK_ADDR_SPACE_XDATA 0x03 /* Addr is placed in XDATA space */ +#define DTK_ADDR_SPACE_I2C_TYPE_II 0x82 /* Addr is placed in I2C area */ +#define DTK_ADDR_SPACE_I2C_TYPE_III 0x83 /* Addr is placed in I2C area */ + +// UART Defines +#define UMPMEM_BASE_UART1 0xFFA0 /* UMP UART1 base address */ +#define UMPMEM_BASE_UART2 0xFFB0 /* UMP UART2 base address */ +#define UMPMEM_OFFS_UART_LSR 0x05 /* UMP UART LSR register offset */ + +/* Bits per character */ +#define UMP_UART_CHAR5BITS 0x00 +#define UMP_UART_CHAR6BITS 0x01 +#define UMP_UART_CHAR7BITS 0x02 +#define UMP_UART_CHAR8BITS 0x03 + +/* Parity */ +#define UMP_UART_NOPARITY 0x00 +#define UMP_UART_ODDPARITY 0x01 +#define UMP_UART_EVENPARITY 0x02 +#define UMP_UART_MARKPARITY 0x03 +#define UMP_UART_SPACEPARITY 0x04 + +/* Stop bits */ +#define UMP_UART_STOPBIT1 0x00 +#define UMP_UART_STOPBIT15 0x01 +#define UMP_UART_STOPBIT2 0x02 + +/* Line status register masks */ +#define UMP_UART_LSR_OV_MASK 0x01 +#define UMP_UART_LSR_PE_MASK 0x02 +#define UMP_UART_LSR_FE_MASK 0x04 +#define UMP_UART_LSR_BR_MASK 0x08 +#define UMP_UART_LSR_ER_MASK 0x0F +#define UMP_UART_LSR_RX_MASK 0x10 +#define UMP_UART_LSR_TX_MASK 0x20 + +#define UMP_UART_LSR_DATA_MASK ( LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK ) + +/* Port Settings Constants) */ +#define UMP_MASK_UART_FLAGS_RTS_FLOW 0x0001 +#define UMP_MASK_UART_FLAGS_RTS_DISABLE 0x0002 +#define UMP_MASK_UART_FLAGS_PARITY 0x0008 +#define UMP_MASK_UART_FLAGS_OUT_X_DSR_FLOW 0x0010 +#define UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW 0x0020 +#define UMP_MASK_UART_FLAGS_OUT_X 0x0040 +#define UMP_MASK_UART_FLAGS_OUT_XA 0x0080 +#define UMP_MASK_UART_FLAGS_IN_X 0x0100 +#define UMP_MASK_UART_FLAGS_DTR_FLOW 0x0800 +#define UMP_MASK_UART_FLAGS_DTR_DISABLE 0x1000 +#define UMP_MASK_UART_FLAGS_RECEIVE_MS_INT 0x2000 +#define UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR 0x4000 + +#define UMP_DMA_MODE_CONTINOUS 0x01 +#define UMP_PIPE_TRANS_TIMEOUT_ENA 0x80 +#define UMP_PIPE_TRANSFER_MODE_MASK 0x03 +#define UMP_PIPE_TRANS_TIMEOUT_MASK 0x7C + +/* Purge port Direction Mask Bits */ +#define UMP_PORT_DIR_OUT 0x01 +#define UMP_PORT_DIR_IN 0x02 + +// Address of Port 0 +#define UMPM_UART1_PORT 0x03 + +// Commands +#define UMPC_SET_CONFIG 0x05 +#define UMPC_OPEN_PORT 0x06 +#define UMPC_CLOSE_PORT 0x07 +#define UMPC_START_PORT 0x08 +#define UMPC_STOP_PORT 0x09 +#define UMPC_TEST_PORT 0x0A +#define UMPC_PURGE_PORT 0x0B + +#define UMPC_COMPLETE_READ 0x80 // Force the Firmware to complete the current Read +#define UMPC_HARDWARE_RESET 0x81 // Force UMP back into BOOT Mode +#define UMPC_COPY_DNLD_TO_I2C 0x82 // Copy current download image to type 0xf2 record in 16k I2C + // firmware will change 0xff record to type 2 record when complete + + // Special function register commands + // wIndex is register address + // wValue is MSB/LSB mask/data +#define UMPC_WRITE_SFR 0x83 // Write SFR Register + + // wIndex is register address +#define UMPC_READ_SFR 0x84 // Read SRF Register + + // Set or Clear DTR (wValue bit 0 Set/Clear) wIndex ModuleID (port) +#define UMPC_SET_CLR_DTR 0x85 + + // Set or Clear RTS (wValue bit 0 Set/Clear) wIndex ModuleID (port) +#define UMPC_SET_CLR_RTS 0x86 + + // Set or Clear LOOPBACK (wValue bit 0 Set/Clear) wIndex ModuleID (port) +#define UMPC_SET_CLR_LOOPBACK 0x87 + + // Set or Clear BREAK (wValue bit 0 Set/Clear) wIndex ModuleID (port) +#define UMPC_SET_CLR_BREAK 0x88 + + // Read MSR wIndex ModuleID (port) +#define UMPC_READ_MSR 0x89 + + /* Toolkit commands */ + /* Read-write group */ +#define UMPC_MEMORY_READ 0x92 +#define UMPC_MEMORY_WRITE 0x93 + +/* + * UMP DMA Definitions + */ +#define UMPD_OEDB1_ADDRESS 0xFF08 +#define UMPD_OEDB2_ADDRESS 0xFF10 + +struct out_endpoint_desc_block +{ + __u8 Configuration; + __u8 XBufAddr; + __u8 XByteCount; + __u8 Unused1; + __u8 Unused2; + __u8 YBufAddr; + __u8 YByteCount; + __u8 BufferSize; +} __attribute__((packed)); + + +/* + * TYPE DEFINITIONS + * Structures for Firmware commands + */ +struct ump_uart_config /* UART settings */ +{ + __u16 wBaudRate; /* Baud rate */ + __u16 wFlags; /* Bitmap mask of flags */ + __u8 bDataBits; /* 5..8 - data bits per character */ + __u8 bParity; /* Parity settings */ + __u8 bStopBits; /* Stop bits settings */ + char cXon; /* XON character */ + char cXoff; /* XOFF character */ + __u8 bUartMode; /* Will be updated when a user */ + /* interface is defined */ +} __attribute__((packed)); + + +/* + * TYPE DEFINITIONS + * Structures for USB interrupts + */ +struct ump_interrupt /* Interrupt packet structure */ +{ + __u8 bICode; /* Interrupt code (interrupt num) */ + __u8 bIInfo; /* Interrupt information */ +} __attribute__((packed)); + + +#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 4) - 3) +#define TIUMP_GET_FUNC_FROM_CODE(c) ((c) & 0x0f) +#define TIUMP_INTERRUPT_CODE_LSR 0x03 +#define TIUMP_INTERRUPT_CODE_MSR 0x04 + +#endif diff -Nru a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h --- a/drivers/usb/serial/io_usbvend.h Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/serial/io_usbvend.h Fri Jul 26 19:58:51 2002 @@ -106,11 +106,23 @@ #define ION_DEVICE_ID_BB_EDGEPORT_4_DIN 0x011 // Edgeport/4 RS232 with Apple DIN connector #define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) #define ION_DEVICE_ID_BB_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) -// These IDs are used by the Edgeport.exe program for uninstalling. -// -#define EDGEPORT_DEVICE_IDS {0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \ - 0x00C, 0x00D, 0x00E, 0x00F, 0x010, 0x011, 0x012, \ - 0x013, 0x014 } + + +/* Edgeport TI based devices */ +#define ION_DEVICE_ID_TI_EDGEPORT_4 0x0201 /* Edgeport/4 RS232 */ +#define ION_DEVICE_ID_TI_EDGEPORT_2 0x0205 /* Edgeport/2 RS232 */ +#define ION_DEVICE_ID_TI_EDGEPORT_4I 0x0206 /* Edgeport/4i RS422 */ +#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 /* Edgeport/2i RS422/RS485 */ +#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C /* Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) */ +#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D /* Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) */ +#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 /* Edgeport/1 RS232 */ +#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 /* Edgeport/42 4 hub 2 RS232 */ +#define ION_DEVICE_ID_TI_EDGEPORT_22 0x021A /* Edgeport/22 Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */ + +#define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT 0x0240 /* Edgeport/421 in boot mode */ +#define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN 0x0241 /* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ +#define ION_DEVICE_ID_TI_EDGEPORT_21_BOOT 0x0242 /* Edgeport/21 in boot mode */ +#define ION_DEVICE_ID_TI_EDGEPORT_21_DOWN 0x0243 /*Edgeport/42 in download mode: first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ #define MAKE_USB_PRODUCT_ID( OemId, DeviceId ) \ @@ -217,7 +229,7 @@ // descriptor format, so that they may be separately retrieved, // if necessary, with a minimum of work on the 930. This also // requires them to be in UNICODE format, which, for English at -// least, simply means extending each UCHAR into a USHORT. +// least, simply means extending each __u8 into a __u16. // 3. For all fields, 00 means 'uninitialized'. // 4. All unused areas should be set to 00 for future expansion. // @@ -384,5 +396,92 @@ #define BOOT_CAP_RESET_CMD 0x0001 // If set, boot correctly supports ION_RESET_DEVICE -#endif // if !defined() + +/************************************************************************ + T I U M P D E F I N I T I O N S + ***********************************************************************/ + +//************************************************************************ +// TI I2C Format Definitions +//************************************************************************ +#define I2C_DESC_TYPE_INFO_BASIC 1 +#define I2C_DESC_TYPE_FIRMWARE_BASIC 2 +#define I2C_DESC_TYPE_DEVICE 3 +#define I2C_DESC_TYPE_CONFIG 4 +#define I2C_DESC_TYPE_STRING 5 +#define I2C_DESC_TYPE_FIRMWARE_BLANK 0xf2 + +#define I2C_DESC_TYPE_MAX 5 +// 3410 may define types 6, 7 for other firmware downloads + +// Special section defined by ION +#define I2C_DESC_TYPE_ION 0 // Not defined by TI + + +struct ti_i2c_desc +{ + __u8 Type; // Type of descriptor + __u16 Size; // Size of data only not including header + __u8 CheckSum; // Checksum (8 bit sum of data only) + __u8 Data[0]; // Data starts here +}__attribute__((packed)); + +struct ti_i2c_firmware_rec +{ + __u8 Ver_Major; // Firmware Major version number + __u8 Ver_Minor; // Firmware Minor version number + __u8 Data[0]; // Download starts here +}__attribute__((packed)); + + +// Structure of header of download image in fw_down.h +struct ti_i2c_image_header +{ + __u16 Length; + __u8 CheckSum; +}__attribute__((packed)); + +struct ti_basic_descriptor +{ + __u8 Power; // Self powered + // bit 7: 1 - power switching supported + // 0 - power switching not supported + // + // bit 0: 1 - self powered + // 0 - bus powered + // + // + __u16 HubVid; // VID HUB + __u16 HubPid; // PID HUB + __u16 DevPid; // PID Edgeport + __u8 HubTime; // Time for power on to power good + __u8 HubCurrent; // HUB Current = 100ma +} __attribute__((packed)); + + +#define TI_GET_CPU_REVISION(x) (__u8)((((x)>>4)&0x0f)) +#define TI_GET_BOARD_REVISION(x) (__u8)(((x)&0x0f)) + +#define TI_I2C_SIZE_MASK 0x1f // 5 bits +#define TI_GET_I2C_SIZE(x) ((((x) & TI_I2C_SIZE_MASK)+1)*256) + +#define TI_MAX_I2C_SIZE ( 16 * 1024 ) + +/* TI USB 5052 definitions */ +struct edge_ti_manuf_descriptor +{ + __u8 IonConfig; // Config byte for ION manufacturing use + __u8 IonConfig2; // Expansion + __u8 Version; // Verqsion + __u8 CpuRev_BoardRev; // CPU revision level (0xF0) and Board Rev Level (0x0F) + __u8 NumPorts; // Number of ports for this UMP + __u8 NumVirtualPorts; // Number of Virtual ports + __u8 HubConfig1; // Used to configure the Hub + __u8 HubConfig2; // Used to configure the Hub + __u8 TotalPorts; // Total Number of Com Ports for the entire device (All UMPs) + __u8 Reserved; +}__attribute__((packed)); + + +#endif // if !defined() diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c --- a/drivers/usb/serial/usbserial.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/serial/usbserial.c Fri Jul 26 19:58:51 2002 @@ -15,6 +15,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (06/05/2002) gkh + * moved location of startup() call in serial_probe() until after all + * of the port information and endpoints are initialized. This makes + * things easier for some drivers. + * * (04/10/2002) gkh * added serial_read_proc function which creates a * /proc/tty/driver/usb-serial file. @@ -341,7 +346,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.5" +#define DRIVER_VERSION "v1.6" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/" #define DRIVER_DESC "USB Serial Driver core" diff -Nru a/drivers/usb/storage/Config.help b/drivers/usb/storage/Config.help --- a/drivers/usb/storage/Config.help Fri Jul 26 19:58:50 2002 +++ b/drivers/usb/storage/Config.help Fri Jul 26 19:58:50 2002 @@ -1,6 +1,9 @@ CONFIG_USB_STORAGE Say Y here if you want to connect USB mass storage devices to your - computer's USB port. + computer's USB port. This is the driver you need for USB floppy drives, + USB hard disks, USB tape drives and USB CD-ROMs, along with + similar devices. This driver may also be used for some cameras and + card readers. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -44,3 +47,11 @@ CONFIG_USB_STORAGE_SDDR55 Say Y here to include additional code to support the Sandisk SDDR-55 SmartMedia reader in the USB Mass Storage driver. + +CONFIG_USB_STORAGE_HP8200e + Say Y here to include additional code to support Hewlett-Packard + 8200e/8210e/8230e CD-Writer Plus drives. + +CONFIG_USB_STORAGE_JUMPSHOT + Say Y here to include additional code to support the Lexar Jumpshot + USB CompactFlash reader. diff -Nru a/drivers/usb/storage/Config.in b/drivers/usb/storage/Config.in --- a/drivers/usb/storage/Config.in Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/storage/Config.in Fri Jul 26 19:58:51 2002 @@ -6,11 +6,11 @@ fi dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE - dep_mbool ' Datafab Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' Datafab Compact Flash Reader support (EXPERIMENTAL)' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE - dep_mbool ' HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' SanDisk SDDR-55 SmartMedia support' CONFIG_USB_STORAGE_SDDR55 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' HP CD-Writer 82xx support (EXPERIMENTAL)' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)' CONFIG_USB_STORAGE_SDDR55 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' Lexar Jumpshot Compact Flash Reader (EXPERIMENTAL)' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Fri Jul 26 19:58:51 2002 +++ b/drivers/usb/storage/usb.c Fri Jul 26 19:58:51 2002 @@ -182,46 +182,46 @@ # include "unusual_devs.h" # undef UNUSUAL_DEV /* Control/Bulk transport for all SubClass values */ - { useProtocol: US_SC_RBC, - useTransport: US_PR_CB}, - { useProtocol: US_SC_8020, - useTransport: US_PR_CB}, - { useProtocol: US_SC_QIC, - useTransport: US_PR_CB}, - { useProtocol: US_SC_UFI, - useTransport: US_PR_CB}, - { useProtocol: US_SC_8070, - useTransport: US_PR_CB}, - { useProtocol: US_SC_SCSI, - useTransport: US_PR_CB}, + { .useProtocol = US_SC_RBC, + .useTransport = US_PR_CB}, + { .useProtocol = US_SC_8020, + .useTransport = US_PR_CB}, + { .useProtocol = US_SC_QIC, + .useTransport = US_PR_CB}, + { .useProtocol = US_SC_UFI, + .useTransport = US_PR_CB}, + { .useProtocol = US_SC_8070, + .useTransport = US_PR_CB}, + { .useProtocol = US_SC_SCSI, + .useTransport = US_PR_CB}, /* Control/Bulk/Interrupt transport for all SubClass values */ - { useProtocol: US_SC_RBC, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_8020, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_QIC, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_UFI, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_8070, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_SCSI, - useTransport: US_PR_CBI}, + { .useProtocol = US_SC_RBC, + .useTransport = US_PR_CBI}, + { .useProtocol = US_SC_8020, + .useTransport = US_PR_CBI}, + { .useProtocol = US_SC_QIC, + .useTransport = US_PR_CBI}, + { .useProtocol = US_SC_UFI, + .useTransport = US_PR_CBI}, + { .useProtocol = US_SC_8070, + .useTransport = US_PR_CBI}, + { .useProtocol = US_SC_SCSI, + .useTransport = US_PR_CBI}, /* Bulk-only transport for all SubClass values */ - { useProtocol: US_SC_RBC, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_8020, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_QIC, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_UFI, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_8070, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_SCSI, - useTransport: US_PR_BULK}, + { .useProtocol = US_SC_RBC, + .useTransport = US_PR_BULK}, + { .useProtocol = US_SC_8020, + .useTransport = US_PR_BULK}, + { .useProtocol = US_SC_QIC, + .useTransport = US_PR_BULK}, + { .useProtocol = US_SC_UFI, + .useTransport = US_PR_BULK}, + { .useProtocol = US_SC_8070, + .useTransport = US_PR_BULK}, + { .useProtocol = US_SC_SCSI, + .useTransport = US_PR_BULK}, /* Terminating entry */ { 0 } diff -Nru a/fs/attr.c b/fs/attr.c --- a/fs/attr.c Fri Jul 26 19:58:50 2002 +++ b/fs/attr.c Fri Jul 26 19:58:50 2002 @@ -12,6 +12,7 @@ #include #include #include +#include /* Taken over from the old code... */ @@ -151,10 +152,14 @@ } } - if (inode->i_op && inode->i_op->setattr) - error = inode->i_op->setattr(dentry, attr); - else { + if (inode->i_op && inode->i_op->setattr) { + error = security_ops->inode_setattr(dentry, attr); + if (!error) + error = inode->i_op->setattr(dentry, attr); + } else { error = inode_change_ok(inode, attr); + if (!error) + error = security_ops->inode_setattr(dentry, attr); if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) diff -Nru a/fs/dnotify.c b/fs/dnotify.c --- a/fs/dnotify.c Fri Jul 26 19:58:51 2002 +++ b/fs/dnotify.c Fri Jul 26 19:58:51 2002 @@ -68,6 +68,7 @@ struct dnotify_struct **prev; struct inode *inode; fl_owner_t id = current->files; + int error; if ((arg & ~DN_MULTISHOT) == 0) { dnotify_flush(filp, id); @@ -93,6 +94,13 @@ } prev = &odn->dn_next; } + + error = security_ops->file_set_fowner(filp); + if (error) { + write_unlock(&dn_lock); + return error; + } + filp->f_owner.pid = current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; diff -Nru a/fs/dquot.c b/fs/dquot.c --- a/fs/dquot.c Fri Jul 26 19:58:50 2002 +++ b/fs/dquot.c Fri Jul 26 19:58:50 2002 @@ -1316,6 +1316,9 @@ error = -EIO; if (!f->f_op || !f->f_op->read || !f->f_op->write) goto out_f; + error = security_ops->quota_on(f); + if (error) + goto out_f; inode = f->f_dentry->d_inode; error = -EACCES; if (!S_ISREG(inode->i_mode)) diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c --- a/fs/driverfs/inode.c Fri Jul 26 19:58:50 2002 +++ b/fs/driverfs/inode.c Fri Jul 26 19:58:50 2002 @@ -33,7 +33,6 @@ #include #include #include -#include #include @@ -51,7 +50,6 @@ static struct super_operations driverfs_ops; static struct file_operations driverfs_file_operations; static struct inode_operations driverfs_dir_inode_operations; -static struct dentry_operations driverfs_dentry_dir_ops; static struct dentry_operations driverfs_dentry_file_ops; static struct address_space_operations driverfs_aops; @@ -136,6 +134,9 @@ struct inode *inode = driverfs_get_inode(dir->i_sb, mode, dev); int error = -EPERM; + if (dentry->d_inode) + return -EEXIST; + /* only allow create if ->d_fsdata is not NULL (so we can assume it * comes from the driverfs API below. */ if (dentry->d_fsdata && inode) { @@ -149,22 +150,19 @@ static int driverfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int res; - lock_kernel(); - dentry->d_op = &driverfs_dentry_dir_ops; - res = driverfs_mknod(dir, dentry, mode | S_IFDIR, 0); + mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR; + res = driverfs_mknod(dir, dentry, mode, 0); if (!res) dir->i_nlink++; - unlock_kernel(); return res; } static int driverfs_create(struct inode *dir, struct dentry *dentry, int mode) { int res; - lock_kernel(); + mode = (mode & S_IALLUGO) | S_IFREG; dentry->d_op = &driverfs_dentry_file_ops; - res = driverfs_mknod(dir, dentry, mode | S_IFREG, 0); - unlock_kernel(); + res = driverfs_mknod(dir, dentry, mode, 0); return res; } @@ -173,6 +171,9 @@ struct inode *inode; int error = -ENOSPC; + if (dentry->d_inode) + return -EEXIST; + inode = driverfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); if (inode) { int l = strlen(symname)+1; @@ -212,24 +213,49 @@ static int driverfs_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; - - lock_kernel(); - inode->i_nlink--; - unlock_kernel(); + down(&inode->i_sem); + dentry->d_inode->i_nlink--; dput(dentry); + up(&inode->i_sem); + d_delete(dentry); return 0; } +static void d_unhash(struct dentry *dentry) +{ + dget(dentry); + spin_lock(&dcache_lock); + switch (atomic_read(&dentry->d_count)) { + default: + spin_unlock(&dcache_lock); + shrink_dcache_parent(dentry); + spin_lock(&dcache_lock); + if (atomic_read(&dentry->d_count) != 2) + break; + case 2: + list_del_init(&dentry->d_hash); + } + spin_unlock(&dcache_lock); +} + static int driverfs_rmdir(struct inode *dir, struct dentry *dentry) { int error = -ENOTEMPTY; + struct inode * inode = dentry->d_inode; + down(&inode->i_sem); + d_unhash(dentry); if (driverfs_empty(dentry)) { - dentry->d_inode->i_nlink--; - driverfs_unlink(dir, dentry); + dentry->d_inode->i_nlink -= 2; + dput(dentry); + inode->i_flags |= S_DEAD; dir->i_nlink--; error = 0; } + up(&inode->i_sem); + if (!error) + d_delete(dentry); + dput(dentry); return error; } @@ -365,7 +391,7 @@ { loff_t retval = -EINVAL; - lock_kernel(); + down(&file->f_dentry->d_inode->i_sem); switch(orig) { case 0: if (offset > 0) { @@ -382,7 +408,7 @@ default: break; } - unlock_kernel(); + up(&file->f_dentry->d_inode->i_sem); return retval; } @@ -424,36 +450,31 @@ } static struct file_operations driverfs_file_operations = { - read: driverfs_read_file, - write: driverfs_write_file, - llseek: driverfs_file_lseek, - open: driverfs_open_file, - release: driverfs_release, + .read = driverfs_read_file, + .write = driverfs_write_file, + .llseek = driverfs_file_lseek, + .open = driverfs_open_file, + .release = driverfs_release, }; static struct inode_operations driverfs_dir_inode_operations = { - create: driverfs_create, - lookup: simple_lookup, - unlink: driverfs_unlink, - symlink: driverfs_symlink, - mkdir: driverfs_mkdir, - rmdir: driverfs_rmdir, + .lookup = simple_lookup, }; static struct address_space_operations driverfs_aops = { - readpage: driverfs_readpage, - writepage: fail_writepage, - prepare_write: driverfs_prepare_write, - commit_write: driverfs_commit_write + .readpage = driverfs_readpage, + .writepage = fail_writepage, + .prepare_write = driverfs_prepare_write, + .commit_write = driverfs_commit_write }; static struct dentry_operations driverfs_dentry_file_ops = { - d_delete: driverfs_d_delete_file, + .d_delete = driverfs_d_delete_file, }; static struct super_operations driverfs_ops = { - statfs: simple_statfs, - drop_inode: generic_delete_inode, + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, }; static int driverfs_fill_super(struct super_block *sb, void *data, int silent) @@ -489,10 +510,10 @@ } static struct file_system_type driverfs_fs_type = { - owner: THIS_MODULE, - name: "driverfs", - get_sb: driverfs_get_sb, - kill_sb: kill_litter_super, + .owner = THIS_MODULE, + .name = "driverfs", + .get_sb = driverfs_get_sb, + .kill_sb = kill_litter_super, }; static int get_mount(void) @@ -589,7 +610,7 @@ if (!IS_ERR(dentry)) { dentry->d_fsdata = (void *) entry; entry->dentry = dentry; - error = vfs_mkdir(parent_dentry->d_inode,dentry,entry->mode); + error = driverfs_mkdir(parent_dentry->d_inode,dentry,entry->mode); } else error = PTR_ERR(dentry); up(&parent_dentry->d_inode->i_sem); @@ -630,7 +651,7 @@ dentry = lookup_hash(&qstr,parent->dentry); if (!IS_ERR(dentry)) { dentry->d_fsdata = (void *)entry; - error = vfs_create(parent->dentry->d_inode,dentry,entry->mode); + error = driverfs_create(parent->dentry->d_inode,dentry,entry->mode); /* Still good? Ok, then fill in the blanks: */ if (!error) { @@ -678,7 +699,7 @@ dentry = lookup_hash(&qstr,parent->dentry); if (!IS_ERR(dentry)) { dentry->d_fsdata = (void *)entry; - error = vfs_symlink(parent->dentry->d_inode,dentry,target); + error = driverfs_symlink(parent->dentry->d_inode,dentry,target); if (!error) { dentry->d_inode->u.generic_ip = (void *)entry; entry->dentry = dentry; @@ -717,7 +738,7 @@ entry = list_entry(node,struct driver_file_entry,node); if (!strcmp(entry->name,name)) { list_del_init(node); - vfs_unlink(entry->dentry->d_parent->d_inode,entry->dentry); + driverfs_unlink(entry->dentry->d_parent->d_inode,entry->dentry); dput(entry->dentry); put_mount(); break; @@ -752,14 +773,14 @@ entry = list_entry(node,struct driver_file_entry,node); list_del_init(node); - vfs_unlink(dentry->d_inode,entry->dentry); + driverfs_unlink(dentry->d_inode,entry->dentry); dput(entry->dentry); put_mount(); node = dir->files.next; } up(&dentry->d_inode->i_sem); - vfs_rmdir(dentry->d_parent->d_inode,dentry); + driverfs_rmdir(dentry->d_parent->d_inode,dentry); up(&dentry->d_parent->d_inode->i_sem); dput(dentry); done: diff -Nru a/fs/fcntl.c b/fs/fcntl.c --- a/fs/fcntl.c Fri Jul 26 19:58:50 2002 +++ b/fs/fcntl.c Fri Jul 26 19:58:50 2002 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -305,6 +306,13 @@ break; case F_SETOWN: lock_kernel(); + + err = security_ops->file_set_fowner(filp); + if (err) { + unlock_kernel(); + break; + } + filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; @@ -353,6 +361,12 @@ if (!filp) goto out; + err = security_ops->file_fcntl(filp, cmd, arg); + if (err) { + fput(filp); + return err; + } + err = do_fcntl(fd, cmd, arg, filp); fput(filp); @@ -371,6 +385,13 @@ if (!filp) goto out; + err = security_ops->file_fcntl(filp, cmd, arg); + if (err) { + fput(filp); + return err; + } + err = -EBADF; + switch (cmd) { case F_GETLK64: err = fcntl_getlk64(filp, (struct flock64 *) arg); @@ -409,6 +430,10 @@ (fown->euid ^ p->suid) && (fown->euid ^ p->uid) && (fown->uid ^ p->suid) && (fown->uid ^ p->uid)) return; + + if (security_ops->file_send_sigiotask(p, fown, fd, reason)) + return; + switch (fown->signum) { siginfo_t si; default: diff -Nru a/fs/file_table.c b/fs/file_table.c --- a/fs/file_table.c Fri Jul 26 19:58:50 2002 +++ b/fs/file_table.c Fri Jul 26 19:58:50 2002 @@ -13,6 +13,7 @@ #include #include #include +#include /* sysctl tunables... */ struct files_stat_struct files_stat = {0, 0, NR_FILE}; @@ -43,6 +44,12 @@ files_stat.nr_free_files--; new_one: memset(f, 0, sizeof(*f)); + if (security_ops->file_alloc_security(f)) { + list_add(&f->f_list, &free_list); + files_stat.nr_free_files++; + file_list_unlock(); + return NULL; + } atomic_set(&f->f_count,1); f->f_version = ++event; f->f_uid = current->fsuid; @@ -117,6 +124,7 @@ if (file->f_op && file->f_op->release) file->f_op->release(inode, file); + security_ops->file_free_security(file); fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) put_write_access(inode); @@ -149,6 +157,7 @@ void put_filp(struct file *file) { if(atomic_dec_and_test(&file->f_count)) { + security_ops->file_free_security(file); file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &free_list); diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Fri Jul 26 19:58:52 2002 +++ b/fs/inode.c Fri Jul 26 19:58:52 2002 @@ -16,6 +16,7 @@ #include #include #include +#include /* * This is needed for the following functions: @@ -100,6 +101,14 @@ if (inode) { struct address_space * const mapping = &inode->i_data; + inode->i_security = NULL; + if (security_ops->inode_alloc_security(inode)) { + if (inode->i_sb->s_op->destroy_inode) + inode->i_sb->s_op->destroy_inode(inode); + else + kmem_cache_free(inode_cachep, (inode)); + return NULL; + } inode->i_sb = sb; inode->i_dev = sb->s_dev; inode->i_blkbits = sb->s_blocksize_bits; @@ -137,6 +146,7 @@ { if (inode_has_buffers(inode)) BUG(); + security_ops->inode_free_security(inode); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else @@ -792,6 +802,8 @@ if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); + + security_ops->inode_delete(inode); if (op && op->delete_inode) { void (*delete)(struct inode *) = op->delete_inode; diff -Nru a/fs/ioctl.c b/fs/ioctl.c --- a/fs/ioctl.c Fri Jul 26 19:58:51 2002 +++ b/fs/ioctl.c Fri Jul 26 19:58:51 2002 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,13 @@ if (!filp) goto out; error = 0; + + error = security_ops->file_ioctl(filp, cmd, arg); + if (error) { + fput(filp); + goto out; + } + lock_kernel(); switch (cmd) { case FIOCLEX: diff -Nru a/fs/locks.c b/fs/locks.c --- a/fs/locks.c Fri Jul 26 19:58:52 2002 +++ b/fs/locks.c Fri Jul 26 19:58:52 2002 @@ -1309,6 +1309,11 @@ fl->fl_next = *before; *before = fl; list_add(&fl->fl_link, &file_lock_list); + + error = security_ops->file_set_fowner(filp); + if (error) + goto out_unlock; + filp->f_owner.pid = current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; @@ -1354,6 +1359,11 @@ if (error < 0) goto out_putf; + error = security_ops->file_lock(filp, cmd, + (cmd & LOCK_NB) ? 0 : 1); + if (error) + goto out_putf; + error = flock_lock_file(filp, lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); @@ -1484,6 +1494,11 @@ goto out; } + error = security_ops->file_lock(filp, file_lock->fl_type, + cmd == F_SETLKW); + if (error) + goto out; + if (filp->f_op && filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, file_lock); if (error < 0) @@ -1602,6 +1617,11 @@ error = -EINVAL; goto out; } + + error = security_ops->file_lock(filp, file_lock->fl_type, + cmd == F_SETLKW64); + if (error) + goto out; if (filp->f_op && filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, file_lock); diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Fri Jul 26 19:58:51 2002 +++ b/fs/namei.c Fri Jul 26 19:58:51 2002 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -204,9 +205,20 @@ int permission(struct inode * inode,int mask) { + int retval; + int submask; + + /* Ordinary permission routines do not understand MAY_APPEND. */ + submask = mask & ~MAY_APPEND; + if (inode->i_op && inode->i_op->permission) - return inode->i_op->permission(inode, mask); - return vfs_permission(inode, mask); + retval = inode->i_op->permission(inode, submask); + else + retval = vfs_permission(inode, submask); + if (retval) + return retval; + + return security_ops->inode_permission(inode, mask); } /* @@ -318,15 +330,17 @@ mode >>= 3; if (mode & MAY_EXEC) - return 0; + goto ok; if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE)) - return 0; + goto ok; if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_READ_SEARCH)) - return 0; + goto ok; return -EACCES; +ok: + return security_ops->inode_permission_lite(inode, MAY_EXEC); } /* @@ -358,8 +372,10 @@ result = dir->i_op->lookup(dir, dentry); if (result) dput(dentry); - else + else { result = dentry; + security_ops->inode_post_lookup(dir, result); + } } up(&dir->i_sem); return result; @@ -388,7 +404,7 @@ */ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) { - int err; + int err = -ELOOP; if (current->link_count >= 5) goto loop; if (current->total_link_count >= 40) @@ -397,6 +413,9 @@ current->state = TASK_RUNNING; schedule(); } + err = security_ops->inode_follow_link(dentry, nd); + if (err) + goto loop; current->link_count++; current->total_link_count++; UPDATE_ATIME(dentry->d_inode); @@ -405,7 +424,7 @@ return err; loop: path_release(nd); - return -ELOOP; + return err; } int follow_up(struct vfsmount **mnt, struct dentry **dentry) @@ -897,9 +916,10 @@ if (!new) goto out; dentry = inode->i_op->lookup(inode, new); - if (!dentry) + if (!dentry) { dentry = new; - else + security_ops->inode_post_lookup(inode, dentry); + } else dput(new); } out: @@ -1103,14 +1123,17 @@ if (!dir->i_op || !dir->i_op->create) return -EACCES; /* shouldn't it be ENOSYS? */ - - DQUOT_INIT(dir); - mode &= S_IALLUGO; mode |= S_IFREG; + error = security_ops->inode_create(dir, dentry, mode); + if (error) + return error; + DQUOT_INIT(dir); error = dir->i_op->create(dir, dentry, mode); - if (!error) + if (!error) { inode_dir_notify(dir, DN_CREATE); + security_ops->inode_post_create(dir, dentry, mode); + } return error; } @@ -1211,6 +1234,11 @@ acc_mode = ACC_MODE(flag); + /* Allow the LSM permission hook to distinguish append + access from general write access. */ + if (flag & O_APPEND) + acc_mode |= MAY_APPEND; + /* * The simplest case - just a plain lookup. */ @@ -1316,6 +1344,9 @@ * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ + error = security_ops->inode_follow_link(dentry, nd); + if (error) + goto exit_dput; UPDATE_ATIME(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); @@ -1379,10 +1410,16 @@ if (!dir->i_op || !dir->i_op->mknod) return -EPERM; + error = security_ops->inode_mknod(dir, dentry, mode, dev); + if (error) + return error; + DQUOT_INIT(dir); error = dir->i_op->mknod(dir, dentry, mode, dev); - if (!error) + if (!error) { inode_dir_notify(dir, DN_CREATE); + security_ops->inode_post_mknod(dir, dentry, mode, dev); + } return error; } @@ -1440,11 +1477,17 @@ if (!dir->i_op || !dir->i_op->mkdir) return -EPERM; - DQUOT_INIT(dir); mode &= (S_IRWXUGO|S_ISVTX); + error = security_ops->inode_mkdir(dir, dentry, mode); + if (error) + return error; + + DQUOT_INIT(dir); error = dir->i_op->mkdir(dir, dentry, mode); - if (!error) + if (!error) { inode_dir_notify(dir, DN_CREATE); + security_ops->inode_post_mkdir(dir,dentry, mode); + } return error; } @@ -1527,9 +1570,12 @@ if (d_mountpoint(dentry)) error = -EBUSY; else { - error = dir->i_op->rmdir(dir, dentry); - if (!error) - dentry->d_inode->i_flags |= S_DEAD; + error = security_ops->inode_rmdir(dir, dentry); + if (!error) { + error = dir->i_op->rmdir(dir, dentry); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; + } } up(&dentry->d_inode->i_sem); if (!error) { @@ -1597,8 +1643,12 @@ down(&dentry->d_inode->i_sem); if (d_mountpoint(dentry)) error = -EBUSY; - else - error = dir->i_op->unlink(dir, dentry); + else { + error = security_ops->inode_unlink(dir, dentry); + if (!error) { + error = dir->i_op->unlink(dir, dentry); + } + } up(&dentry->d_inode->i_sem); if (!error) { d_delete(dentry); @@ -1659,10 +1709,16 @@ if (!dir->i_op || !dir->i_op->symlink) return -EPERM; + error = security_ops->inode_symlink(dir, dentry, oldname); + if (error) + return error; + DQUOT_INIT(dir); error = dir->i_op->symlink(dir, dentry, oldname); - if (!error) + if (!error) { inode_dir_notify(dir, DN_CREATE); + security_ops->inode_post_symlink(dir, dentry, oldname); + } return error; } @@ -1724,12 +1780,18 @@ if (S_ISDIR(old_dentry->d_inode->i_mode)) return -EPERM; + error = security_ops->inode_link(old_dentry, dir, new_dentry); + if (error) + return error; + down(&old_dentry->d_inode->i_sem); DQUOT_INIT(dir); error = dir->i_op->link(old_dentry, dir, new_dentry); up(&old_dentry->d_inode->i_sem); - if (!error) + if (!error) { inode_dir_notify(dir, DN_CREATE); + security_ops->inode_post_link(old_dentry, dir, new_dentry); + } return error; } @@ -1821,9 +1883,13 @@ * If we are going to change the parent - check write permissions, * we'll need to flip '..'. */ - if (new_dir != old_dir) + if (new_dir != old_dir) { error = permission(old_dentry->d_inode, MAY_WRITE); + if (error) + return error; + } + error = security_ops->inode_rename(old_dir, old_dentry, new_dir, new_dentry); if (error) return error; @@ -1844,8 +1910,11 @@ d_rehash(new_dentry); dput(new_dentry); } - if (!error) + if (!error) { d_move(old_dentry,new_dentry); + security_ops->inode_post_rename(old_dir, old_dentry, + new_dir, new_dentry); + } return error; } @@ -1855,6 +1924,10 @@ struct inode *target; int error; + error = security_ops->inode_rename(old_dir, old_dentry, new_dir, new_dentry); + if (error) + return error; + dget(new_dentry); target = new_dentry->d_inode; if (target) @@ -1867,6 +1940,7 @@ /* The following d_move() should become unconditional */ if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) d_move(old_dentry, new_dentry); + security_ops->inode_post_rename(old_dir, old_dentry, new_dir, new_dentry); } if (target) up(&target->i_sem); diff -Nru a/fs/namespace.c b/fs/namespace.c --- a/fs/namespace.c Fri Jul 26 19:58:52 2002 +++ b/fs/namespace.c Fri Jul 26 19:58:52 2002 @@ -288,6 +288,10 @@ struct super_block * sb = mnt->mnt_sb; int retval = 0; + retval = security_ops->sb_umount(mnt, flags); + if (retval) + return retval; + /* * If we may have to abort operations to get out of this * mount, and they will themselves hold resources we must @@ -337,6 +341,7 @@ DQUOT_OFF(sb); acct_auto_close(sb); unlock_kernel(); + security_ops->sb_umount_close(mnt); spin_lock(&dcache_lock); } retval = -EBUSY; @@ -346,6 +351,8 @@ retval = 0; } spin_unlock(&dcache_lock); + if (retval) + security_ops->sb_umount_busy(mnt); up_write(¤t->namespace->sem); return retval; } @@ -463,6 +470,10 @@ if (IS_DEADDIR(nd->dentry->d_inode)) goto out_unlock; + err = security_ops->sb_check_sb(mnt, nd); + if (err) + goto out_unlock; + spin_lock(&dcache_lock); if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) { struct list_head head; @@ -475,6 +486,8 @@ spin_unlock(&dcache_lock); out_unlock: up(&nd->dentry->d_inode->i_sem); + if (!err) + security_ops->sb_post_addmount(mnt, nd); return err; } @@ -544,6 +557,8 @@ if (!err) nd->mnt->mnt_flags=mnt_flags; up_write(&sb->s_umount); + if (!err) + security_ops->sb_post_remount(nd->mnt, flags, data); return err; } @@ -726,6 +741,10 @@ if (retval) return retval; + retval = security_ops->sb_mount(dev_name, &nd, type_page, flags, data_page); + if (retval) + goto dput_out; + if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, data_page); @@ -736,6 +755,7 @@ else retval = do_add_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page); +dput_out: path_release(&nd); return retval; } @@ -919,6 +939,12 @@ if (error) goto out1; + error = security_ops->sb_pivotroot(&old_nd, &new_nd); + if (error) { + path_release(&old_nd); + goto out1; + } + read_lock(¤t->fs->lock); user_nd.mnt = mntget(current->fs->rootmnt); user_nd.dentry = dget(current->fs->root); @@ -963,6 +989,7 @@ attach_mnt(new_nd.mnt, &root_parent); spin_unlock(&dcache_lock); chroot_fs_refs(&user_nd, &new_nd); + security_ops->sb_post_pivotroot(&user_nd, &new_nd); error = 0; path_release(&root_parent); path_release(&parent_nd); diff -Nru a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile --- a/fs/ncpfs/Makefile Fri Jul 26 19:58:51 2002 +++ b/fs/ncpfs/Makefile Fri Jul 26 19:58:51 2002 @@ -5,7 +5,13 @@ obj-$(CONFIG_NCP_FS) += ncpfs.o ncpfs-objs := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \ - symlink.o ncpsign_kernel.o + ncpsign_kernel.o +ifeq ($(CONFIG_NCPFS_EXTRAS),y) +ncpfs-objs += symlink.o +endif +ifeq ($(CONFIG_NCPFS_NFS_NS),y) +ncpfs-objs += symlink.o +endif # If you want debugging output, please uncomment the following line # EXTRA_CFLAGS += -DDEBUG_NCP=1 diff -Nru a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c --- a/fs/ncpfs/dir.c Fri Jul 26 19:58:51 2002 +++ b/fs/ncpfs/dir.c Fri Jul 26 19:58:51 2002 @@ -6,6 +6,7 @@ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache * Modified 1998, 1999 Wolfram Pienkoss for NLS * Modified 1999 Wolfram Pienkoss for directory caching + * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info * */ @@ -40,8 +41,12 @@ static int ncp_rmdir(struct inode *, struct dentry *); static int ncp_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); -#ifdef CONFIG_NCPFS_EXTRAS +static int ncp_mknod(struct inode * dir, struct dentry *dentry, + int mode, int rdev); +#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) extern int ncp_symlink(struct inode *, struct dentry *, const char *); +#else +#define ncp_symlink NULL #endif struct file_operations ncp_dir_operations = @@ -56,11 +61,10 @@ create: ncp_create, lookup: ncp_lookup, unlink: ncp_unlink, -#ifdef CONFIG_NCPFS_EXTRAS symlink: ncp_symlink, -#endif mkdir: ncp_mkdir, rmdir: ncp_rmdir, + mknod: ncp_mknod, rename: ncp_rename, setattr: ncp_notify_change, }; @@ -73,7 +77,7 @@ static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); static int ncp_delete_dentry(struct dentry *); -struct dentry_operations ncp_dentry_operations = +static struct dentry_operations ncp_dentry_operations = { d_revalidate: ncp_lookup_validate, d_hash: ncp_hash_dentry, @@ -81,6 +85,13 @@ d_delete: ncp_delete_dentry, }; +struct dentry_operations ncp_root_dentry_operations = +{ + d_hash: ncp_hash_dentry, + d_compare: ncp_compare_dentry, + d_delete: ncp_delete_dentry, +}; + /* * Note: leave the hash unchanged if the directory @@ -300,6 +311,7 @@ if (!res) res = ncp_obtain_info(server, dir, __name, &(finfo.i)); } + finfo.volume = finfo.i.volNumber; DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n", dentry->d_parent->d_name.name, __name, res); /* @@ -663,6 +675,7 @@ info.volume_name); continue; } + entry.volume = entry.i.volNumber; if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) return; } @@ -678,6 +691,9 @@ struct nw_search_sequence seq; struct ncp_entry_info entry; int err; + void* buf; + int more; + size_t bufsize; DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", dentry->d_parent->d_name.name, dentry->d_name.name, @@ -691,15 +707,57 @@ DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); return; } +#ifdef USE_OLD_SLOW_DIRECTORY_LISTING for (;;) { err = ncp_search_for_file_or_subdir(server, &seq, &entry.i); if (err) { DPRINTK("ncp_do_readdir: search failed, err=%d\n", err); - return; + break; } + entry.volume = entry.i.volNumber; if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) - return; + break; } +#else + /* We MUST NOT use server->buffer_size handshaked with server if we are + using UDP, as for UDP server uses max. buffer size determined by + MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). + So we use 128KB, just to be sure, as there is no way how to know + this value in advance. */ + bufsize = 131072; + buf = vmalloc(bufsize); + if (!buf) + return; + do { + int cnt; + char* rpl; + size_t rpls; + + err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls); + if (err) /* Error */ + break; + if (!cnt) /* prevent endless loop */ + break; + while (cnt--) { + size_t onerpl; + + if (rpls < offsetof(struct nw_info_struct, entryName)) + break; /* short packet */ + ncp_extract_file_info(rpl, &entry.i); + onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen; + if (rpls < onerpl) + break; /* short packet */ + (void)ncp_obtain_nfs_info(server, &entry.i); + rpl += onerpl; + rpls -= onerpl; + entry.volume = entry.i.volNumber; + if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) + break; + } + } while (more); + vfree(buf); +#endif + return; } int ncp_conn_logged_in(struct super_block *sb) @@ -781,6 +839,7 @@ */ finfo.opened = 0; finfo.ino = iunique(dir->i_sb, 2); + finfo.volume = finfo.i.volNumber; error = -EACCES; inode = ncp_iget(dir->i_sb, &finfo); @@ -824,7 +883,7 @@ } int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, - int attributes) + int rdev, int attributes) { struct ncp_server *server = NCP_SERVER(dir); struct ncp_entry_info finfo; @@ -870,6 +929,15 @@ opmode = O_WRONLY; } finfo.access = opmode; + if (ncp_is_nfs_extras(server, finfo.volume)) { + finfo.i.nfs.mode = mode; + finfo.i.nfs.rdev = rdev; + if (ncp_modify_nfs_info(server, finfo.volume, + finfo.i.dirEntNum, + mode, rdev) != 0) + goto out; + } + error = ncp_instantiate(dir, dentry, &finfo); out: unlock_kernel(); @@ -878,7 +946,7 @@ static int ncp_create(struct inode *dir, struct dentry *dentry, int mode) { - return ncp_create_new(dir, dentry, mode, 0); + return ncp_create_new(dir, dentry, mode, 0, 0); } static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) @@ -906,6 +974,15 @@ OC_MODE_CREATE, aDIR, 0xffff, &finfo) == 0) { + if (ncp_is_nfs_extras(server, finfo.volume)) { + mode |= S_IFDIR; + finfo.i.nfs.mode = mode; + if (ncp_modify_nfs_info(server, + finfo.volume, + finfo.i.dirEntNum, + mode, 0) != 0) + goto out; + } error = ncp_instantiate(dir, dentry, &finfo); } out: @@ -1089,6 +1166,16 @@ out: unlock_kernel(); return error; +} + +static int ncp_mknod(struct inode * dir, struct dentry *dentry, + int mode, int rdev) +{ + if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) { + DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode); + return ncp_create_new(dir, dentry, mode, rdev, 0); + } + return -EPERM; /* Strange, but true */ } /* The following routines are taken directly from msdos-fs */ diff -Nru a/fs/ncpfs/file.c b/fs/ncpfs/file.c --- a/fs/ncpfs/file.c Fri Jul 26 19:58:50 2002 +++ b/fs/ncpfs/file.c Fri Jul 26 19:58:50 2002 @@ -51,12 +51,10 @@ struct ncp_entry_info finfo; int result; - finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum; - finfo.i.volNumber = NCP_FINFO(inode)->volNumber; /* tries max. rights */ finfo.access = O_RDWR; result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), - NULL, NULL, OC_MODE_OPEN, + inode, NULL, OC_MODE_OPEN, 0, AR_READ | AR_WRITE, &finfo); if (!result) goto update; @@ -65,13 +63,13 @@ case O_RDONLY: finfo.access = O_RDONLY; result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), - NULL, NULL, OC_MODE_OPEN, + inode, NULL, OC_MODE_OPEN, 0, AR_READ, &finfo); break; case O_WRONLY: finfo.access = O_WRONLY; result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), - NULL, NULL, OC_MODE_OPEN, + inode, NULL, OC_MODE_OPEN, 0, AR_WRITE, &finfo); break; } @@ -115,30 +113,31 @@ DPRINTK("ncp_file_read: enter %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - error = -EIO; if (!ncp_conn_valid(NCP_SERVER(inode))) - goto out; - error = -EINVAL; + return -EIO; if (!S_ISREG(inode->i_mode)) { DPRINTK("ncp_file_read: read from non-file, mode %07o\n", inode->i_mode); - goto out; + return -EINVAL; } pos = *ppos; -/* leave it out on server ... - if (pos + count > inode->i_size) { - count = inode->i_size - pos; + + if ((ssize_t) count < 0) { + return -EINVAL; + } + if (!count) + return 0; + if (pos > inode->i_sb->s_maxbytes) + return 0; + if (pos + count > inode->i_sb->s_maxbytes) { + count = inode->i_sb->s_maxbytes - pos; } -*/ - error = 0; - if (!count) /* size_t is never < 0 */ - goto out; error = ncp_make_open(inode, O_RDONLY); if (error) { DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error); - goto out; + return error; } bufsize = NCP_SERVER(inode)->buffer_size; @@ -184,7 +183,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name); outrel: ncp_inode_close(inode); -out: return already_read ? already_read : error; } @@ -201,28 +199,46 @@ DPRINTK("ncp_file_write: enter %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - errno = -EIO; if (!ncp_conn_valid(NCP_SERVER(inode))) - goto out; + return -EIO; if (!S_ISREG(inode->i_mode)) { DPRINTK("ncp_file_write: write to non-file, mode %07o\n", inode->i_mode); return -EINVAL; } + if ((ssize_t) count < 0) + return -EINVAL; + pos = *ppos; + if (file->f_flags & O_APPEND) { + pos = inode->i_size; + } - errno = 0; + if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { + if (pos >= MAX_NON_LFS) { + send_sig(SIGXFSZ, current, 0); + return -EFBIG; + } + if (count > MAX_NON_LFS - (u32)pos) { + count = MAX_NON_LFS - (u32)pos; + } + } + if (pos >= inode->i_sb->s_maxbytes) { + if (count || pos > inode->i_sb->s_maxbytes) { + send_sig(SIGXFSZ, current, 0); + return -EFBIG; + } + } + if (pos + count > inode->i_sb->s_maxbytes) { + count = inode->i_sb->s_maxbytes - pos; + } + if (!count) - goto out; + return 0; errno = ncp_make_open(inode, O_WRONLY); if (errno) { DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno); return errno; } - pos = *ppos; - - if (file->f_flags & O_APPEND) { - pos = inode->i_size; - } bufsize = NCP_SERVER(inode)->buffer_size; already_written = 0; @@ -268,7 +284,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name); outrel: ncp_inode_close(inode); -out: return already_written ? already_written : errno; } diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c --- a/fs/ncpfs/inode.c Fri Jul 26 19:58:51 2002 +++ b/fs/ncpfs/inode.c Fri Jul 26 19:58:51 2002 @@ -5,6 +5,7 @@ * Modified for big endian by J.F. Chadima and David S. Miller * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache * Modified 1998 Wolfram Pienkoss for NLS + * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info * */ @@ -90,8 +91,8 @@ statfs: ncp_statfs, }; -extern struct dentry_operations ncp_dentry_operations; -#ifdef CONFIG_NCPFS_EXTRAS +extern struct dentry_operations ncp_root_dentry_operations; +#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) extern struct address_space_operations ncp_symlink_aops; extern int ncp_symlink(struct inode*, struct dentry*, const char*); #endif @@ -99,19 +100,18 @@ /* * Fill in the ncpfs-specific information in the inode. */ -void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo) +static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo) { NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum; NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum; - NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber; + NCP_FINFO(inode)->volNumber = nwinfo->volume; +} -#ifdef CONFIG_NCPFS_STRONG - NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; -#else +void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo) +{ + ncp_update_dirent(inode, nwinfo); NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; -#endif NCP_FINFO(inode)->access = nwinfo->access; - NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle; memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle, sizeof(nwinfo->file_handle)); DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n", @@ -119,68 +119,27 @@ NCP_FINFO(inode)->dirEntNum); } -void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) +static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi) { - struct nw_info_struct *nwi = &nwinfo->i; - struct ncp_server *server = NCP_SERVER(inode); - - if (!atomic_read(&NCP_FINFO(inode)->opened)) { -#ifdef CONFIG_NCPFS_STRONG - NCP_FINFO(inode)->nwattr = nwi->attributes; -#endif - if (nwi->attributes & aDIR) { - inode->i_mode = server->m.dir_mode; - inode->i_size = NCP_BLOCK_SIZE; - } else { - inode->i_mode = server->m.file_mode; - inode->i_size = le32_to_cpu(nwi->dataStreamSize); -#ifdef CONFIG_NCPFS_EXTRAS - if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) && (nwi->attributes & aSHARED)) { - switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { - case aHIDDEN: - if (server->m.flags & NCP_MOUNT_SYMLINKS) { - if ( /* (inode->i_size >= NCP_MIN_SYMLINK_SIZE) - && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { - inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; - break; - } - } - /* FALLTHROUGH */ - case 0: - if (server->m.flags & NCP_MOUNT_EXTRAS) - inode->i_mode |= 0444; - break; - case aSYSTEM: - if (server->m.flags & NCP_MOUNT_EXTRAS) - inode->i_mode |= (inode->i_mode >> 2) & 0111; - break; - /* case aSYSTEM|aHIDDEN: */ - default: - /* reserved combination */ - break; - } - } -#endif - } - if (nwi->attributes & aRONLY) inode->i_mode &= ~0222; + /* NFS namespace mode overrides others if it's set. */ + DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n", + nwi->entryName, nwi->nfs.mode); + if (nwi->nfs.mode) { + /* XXX Security? */ + inode->i_mode = nwi->nfs.mode; } + inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime), le16_to_cpu(nwi->modifyDate)); inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime), le16_to_cpu(nwi->creationDate)); - inode->i_atime = ncp_date_dos2unix(0, le16_to_cpu(nwi->lastAccessDate)); - - NCP_FINFO(inode)->DosDirNum = nwi->DosDirNum; - NCP_FINFO(inode)->dirEntNum = nwi->dirEntNum; - NCP_FINFO(inode)->volNumber = nwi->volNumber; + inode->i_atime = ncp_date_dos2unix(0, + le16_to_cpu(nwi->lastAccessDate)); } -/* - * Fill in the inode based on the ncp_entry_info structure. - */ -static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) +static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo) { struct nw_info_struct *nwi = &nwinfo->i; struct ncp_server *server = NCP_SERVER(inode); @@ -202,17 +161,18 @@ if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE) && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; + NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK; break; } } /* FALLTHROUGH */ case 0: if (server->m.flags & NCP_MOUNT_EXTRAS) - inode->i_mode |= 0444; + inode->i_mode |= S_IRUGO; break; case aSYSTEM: if (server->m.flags & NCP_MOUNT_EXTRAS) - inode->i_mode |= (inode->i_mode >> 2) & 0111; + inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO; break; /* case aSYSTEM|aHIDDEN: */ default: @@ -222,7 +182,31 @@ } #endif } - if (nwi->attributes & aRONLY) inode->i_mode &= ~0222; + if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO; +} + +void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) +{ + NCP_FINFO(inode)->flags = 0; + if (!atomic_read(&NCP_FINFO(inode)->opened)) { + NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; + ncp_update_attrs(inode, nwinfo); + } + + ncp_update_dates(inode, &nwinfo->i); + ncp_update_dirent(inode, nwinfo); +} + +/* + * Fill in the inode based on the ncp_entry_info structure. + */ +static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) +{ + struct ncp_server *server = NCP_SERVER(inode); + + NCP_FINFO(inode)->flags = 0; + + ncp_update_attrs(inode, nwinfo); DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); @@ -232,14 +216,7 @@ inode->i_rdev = NODEV; inode->i_blksize = NCP_BLOCK_SIZE; - inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; - - inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime), - le16_to_cpu(nwi->modifyDate)); - inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime), - le16_to_cpu(nwi->creationDate)); - inode->i_atime = ncp_date_dos2unix(0, - le16_to_cpu(nwi->lastAccessDate)); + ncp_update_dates(inode, &nwinfo->i); ncp_update_inode(inode, nwinfo); } @@ -274,11 +251,17 @@ } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ncp_dir_inode_operations; inode->i_fop = &ncp_dir_operations; -#ifdef CONFIG_NCPFS_EXTRAS +#ifdef CONFIG_NCPFS_NFS_NS + } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { + init_special_inode(inode, inode->i_mode, info->i.nfs.rdev); +#endif +#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &ncp_symlink_inode_operations; inode->i_data.a_ops = &ncp_symlink_aops; #endif + } else { + make_bad_inode(inode); } insert_inode_hash(inode); } else @@ -479,7 +462,7 @@ #ifdef CONFIG_NCPFS_SMALLDOS finfo.i.NSCreator = NW_NS_DOS; #endif - finfo.i.volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */ + finfo.volume = NCP_NUMBER_OF_VOLUMES; /* set dates of mountpoint to Jan 1, 1986; 00:00 */ finfo.i.creationTime = finfo.i.modifyTime = cpu_to_le16(0x0000); @@ -492,7 +475,7 @@ finfo.opened = 0; finfo.ino = 2; /* tradition */ - server->name_space[finfo.i.volNumber] = NW_NS_DOS; + server->name_space[finfo.volume] = NW_NS_DOS; error = -ENOMEM; root_inode = ncp_iget(sb, &finfo); @@ -502,7 +485,7 @@ sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) goto out_no_root; - sb->s_root->d_op = &ncp_dentry_operations; + sb->s_root->d_op = &ncp_root_dentry_operations; return 0; out_no_root: @@ -567,12 +550,60 @@ static int ncp_statfs(struct super_block *sb, struct statfs *buf) { + struct dentry* d; + struct inode* i; + struct ncp_inode_info* ni; + struct ncp_server* s; + struct ncp_volume_info vi; + int err; + __u8 dh; + + d = sb->s_root; + if (!d) { + goto dflt; + } + i = d->d_inode; + if (!i) { + goto dflt; + } + ni = NCP_FINFO(i); + if (!ni) { + goto dflt; + } + s = NCP_SBP(sb); + if (!s) { + goto dflt; + } + if (!s->m.mounted_vol[0]) { + goto dflt; + } + + err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh); + if (err) { + goto dflt; + } + err = ncp_get_directory_info(s, dh, &vi); + ncp_dirhandle_free(s, dh); + if (err) { + goto dflt; + } + buf->f_type = NCP_SUPER_MAGIC; + buf->f_bsize = vi.sectors_per_block * 512; + buf->f_blocks = vi.total_blocks; + buf->f_bfree = vi.free_blocks; + buf->f_bavail = vi.free_blocks; + buf->f_files = vi.total_dir_entries; + buf->f_ffree = vi.available_dir_entries; + buf->f_namelen = 12; + return 0; + /* We cannot say how much disk space is left on a mounted NetWare Server, because free space is distributed over volumes, and the current user might have disk quotas. So free space is not that simple to determine. Our decision here is to err conservatively. */ +dflt:; buf->f_type = NCP_SUPER_MAGIC; buf->f_bsize = NCP_BLOCK_SIZE; buf->f_blocks = 0; @@ -616,7 +647,7 @@ if (((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & - ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) + ~(S_IFREG | S_IFDIR | S_IRWXUGO)))) goto out; info_mask = 0; @@ -625,58 +656,81 @@ #if 1 if ((attr->ia_valid & ATTR_MODE) != 0) { - if (S_ISDIR(inode->i_mode)) { - umode_t newmode; + umode_t newmode = attr->ia_mode; - info_mask |= DM_ATTRIBUTES; - newmode = attr->ia_mode; - newmode &= NCP_SERVER(inode)->m.dir_mode; - - if (newmode & 0222) - info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - else - info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - } else if (!S_ISREG(inode->i_mode)) - { - result = -EPERM; - goto out; - } - else - { - umode_t newmode; -#ifdef CONFIG_NCPFS_EXTRAS - int extras; - - extras = server->m.flags & NCP_MOUNT_EXTRAS; -#endif - info_mask |= DM_ATTRIBUTES; - newmode=attr->ia_mode; -#ifdef CONFIG_NCPFS_EXTRAS - if (!extras) -#endif - newmode &= server->m.file_mode; + info_mask |= DM_ATTRIBUTES; - if (newmode & 0222) /* any write bit set */ - { - info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - } - else - { - info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - } -#ifdef CONFIG_NCPFS_EXTRAS - if (extras) { - if (newmode & 0111) /* any execute bit set */ + if (S_ISDIR(inode->i_mode)) { + newmode &= server->m.dir_mode; + } else { +#ifdef CONFIG_NCPFS_EXTRAS + if (server->m.flags & NCP_MOUNT_EXTRAS) { + /* any non-default execute bit set */ + if (newmode & ~server->m.file_mode & S_IXUGO) info.attributes |= aSHARED | aSYSTEM; /* read for group/world and not in default file_mode */ - else if (newmode & ~server->m.file_mode & 0444) + else if (newmode & ~server->m.file_mode & S_IRUGO) info.attributes |= aSHARED; - } + } else #endif + newmode &= server->m.file_mode; } + if (newmode & S_IWUGO) + info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); + else + info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); + +#ifdef CONFIG_NCPFS_NFS_NS + if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) { + result = ncp_modify_nfs_info(server, + NCP_FINFO(inode)->volNumber, + NCP_FINFO(inode)->dirEntNum, + attr->ia_mode, 0); + if (result != 0) + goto out; + info.attributes &= ~(aSHARED | aSYSTEM); + { + /* mark partial success */ + struct iattr tmpattr; + + tmpattr.ia_valid = ATTR_MODE; + tmpattr.ia_mode = attr->ia_mode; + + inode_setattr(inode, &tmpattr); + } + } +#endif } #endif + /* Do SIZE before attributes, otherwise mtime together with size does not work... + */ + if ((attr->ia_valid & ATTR_SIZE) != 0) { + int written; + + DPRINTK("ncpfs: trying to change size to %ld\n", + attr->ia_size); + + if ((result = ncp_make_open(inode, O_WRONLY)) < 0) { + result = -EACCES; + goto out; + } + ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, + attr->ia_size, 0, "", &written); + + /* According to ndir, the changes only take effect after + closing the file */ + ncp_inode_close(inode); + result = ncp_make_closed(inode); + { + struct iattr tmpattr; + + tmpattr.ia_valid = ATTR_SIZE; + tmpattr.ia_size = attr->ia_size; + + inode_setattr(inode, &tmpattr); + } + } if ((attr->ia_valid & ATTR_CTIME) != 0) { info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE); ncp_date_unix2dos(attr->ia_ctime, @@ -711,33 +765,16 @@ a terrible hack, but I do not know how to do this correctly. */ result = 0; - } + } else + goto out; } #ifdef CONFIG_NCPFS_STRONG if ((!result) && (info_mask & DM_ATTRIBUTES)) NCP_FINFO(inode)->nwattr = info.attributes; #endif } - if ((attr->ia_valid & ATTR_SIZE) != 0) { - int written; - - DPRINTK("ncpfs: trying to change size to %ld\n", - attr->ia_size); - - if ((result = ncp_make_open(inode, O_WRONLY)) < 0) { - result = -EACCES; - goto out; - } - ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, - attr->ia_size, 0, "", &written); - - /* According to ndir, the changes only take effect after - closing the file */ - ncp_inode_close(inode); - result = ncp_make_closed(inode); - if (!result) - result = vmtruncate(inode, attr->ia_size); - } + if (!result) + inode_setattr(inode, attr); out: unlock_kernel(); return result; diff -Nru a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c --- a/fs/ncpfs/ioctl.c Fri Jul 26 19:58:50 2002 +++ b/fs/ncpfs/ioctl.c Fri Jul 26 19:58:50 2002 @@ -201,7 +201,7 @@ case NCP_IOC_SETROOT: { struct ncp_setroot_ioctl sr; - struct nw_info_struct i; + unsigned int vnum, de, dosde; struct dentry* dentry; if (!capable(CAP_SYS_ADMIN)) @@ -214,25 +214,31 @@ sizeof(sr))) return -EFAULT; if (sr.volNumber < 0) { server->m.mounted_vol[0] = 0; - i.volNumber = NCP_NUMBER_OF_VOLUMES + 1; - i.dirEntNum = 0; - i.DosDirNum = 0; + vnum = NCP_NUMBER_OF_VOLUMES; + de = 0; + dosde = 0; } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { return -EINVAL; - } else - if (ncp_mount_subdir(server, &i, sr.volNumber, + } else { + struct nw_info_struct ni; + + if (ncp_mount_subdir(server, &ni, sr.volNumber, sr.namespace, sr.dirEntNum)) return -ENOENT; - + vnum = ni.volNumber; + de = ni.dirEntNum; + dosde = ni.DosDirNum; + } + dentry = inode->i_sb->s_root; server->root_setuped = 1; if (dentry) { struct inode* inode = dentry->d_inode; if (inode) { - NCP_FINFO(inode)->volNumber = i.volNumber; - NCP_FINFO(inode)->dirEntNum = i.dirEntNum; - NCP_FINFO(inode)->DosDirNum = i.DosDirNum; + NCP_FINFO(inode)->volNumber = vnum; + NCP_FINFO(inode)->dirEntNum = de; + NCP_FINFO(inode)->DosDirNum = dosde; } else DPRINTK("ncpfs: s_root->d_inode==NULL\n"); } else diff -Nru a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c --- a/fs/ncpfs/ncplib_kernel.c Fri Jul 26 19:58:51 2002 +++ b/fs/ncpfs/ncplib_kernel.c Fri Jul 26 19:58:51 2002 @@ -5,6 +5,7 @@ * Modified for big endian by J.F. Chadima and David S. Miller * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache * Modified 1999 Wolfram Pienkoss for NLS + * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info * */ @@ -44,6 +45,10 @@ return; } +static inline void ncp_add_dword_lh(struct ncp_server *server, __u32 x) { + ncp_add_dword(server, cpu_to_le32(x)); +} + static void ncp_add_mem(struct ncp_server *server, const void *source, int size) { assert_server_locked(server); @@ -89,24 +94,43 @@ return &(server->packet[sizeof(struct ncp_reply_header) + offset]); } +static inline __u8 BVAL(void* data) +{ + return get_unaligned((__u8*)data); +} + static __u8 ncp_reply_byte(struct ncp_server *server, int offset) { return get_unaligned((__u8 *) ncp_reply_data(server, offset)); } +static inline __u16 WVAL_LH(void* data) +{ + return le16_to_cpu(get_unaligned((__u16*)data)); +} + static __u16 ncp_reply_word(struct ncp_server *server, int offset) { return get_unaligned((__u16 *) ncp_reply_data(server, offset)); } +static inline __u32 DVAL_LH(void* data) +{ + return le32_to_cpu(get_unaligned((__u32*)data)); +} + static __u32 ncp_reply_dword(struct ncp_server *server, int offset) { return get_unaligned((__u32 *) ncp_reply_data(server, offset)); } +static inline __u32 ncp_reply_dword_lh(struct ncp_server* server, int offset) { + return le32_to_cpu(ncp_reply_dword(server, offset)); +} + int ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target) { @@ -159,10 +183,8 @@ return 0; } -int -ncp_get_volume_info_with_number(struct ncp_server *server, int n, - struct ncp_volume_info *target) -{ +int ncp_get_volume_info_with_number(struct ncp_server* server, + int n, struct ncp_volume_info* target) { int result; int len; @@ -172,12 +194,12 @@ if ((result = ncp_request(server, 22)) != 0) { goto out; } - target->total_blocks = ncp_reply_dword(server, 0); - target->free_blocks = ncp_reply_dword(server, 4); - target->purgeable_blocks = ncp_reply_dword(server, 8); - target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12); - target->total_dir_entries = ncp_reply_dword(server, 16); - target->available_dir_entries = ncp_reply_dword(server, 20); + target->total_blocks = ncp_reply_dword_lh(server, 0); + target->free_blocks = ncp_reply_dword_lh(server, 4); + target->purgeable_blocks = ncp_reply_dword_lh(server, 8); + target->not_yet_purgeable_blocks = ncp_reply_dword_lh(server, 12); + target->total_dir_entries = ncp_reply_dword_lh(server, 16); + target->available_dir_entries = ncp_reply_dword_lh(server, 20); target->sectors_per_block = ncp_reply_byte(server, 28); memset(&(target->volume_name), 0, sizeof(target->volume_name)); @@ -195,6 +217,40 @@ return result; } +int ncp_get_directory_info(struct ncp_server* server, __u8 n, + struct ncp_volume_info* target) { + int result; + int len; + + ncp_init_request_s(server, 45); + ncp_add_byte(server, n); + + if ((result = ncp_request(server, 22)) != 0) { + goto out; + } + target->total_blocks = ncp_reply_dword_lh(server, 0); + target->free_blocks = ncp_reply_dword_lh(server, 4); + target->purgeable_blocks = 0; + target->not_yet_purgeable_blocks = 0; + target->total_dir_entries = ncp_reply_dword_lh(server, 8); + target->available_dir_entries = ncp_reply_dword_lh(server, 12); + target->sectors_per_block = ncp_reply_byte(server, 20); + + memset(&(target->volume_name), 0, sizeof(target->volume_name)); + + result = -EIO; + len = ncp_reply_byte(server, 21); + if (len > NCP_VOLNAME_LEN) { + DPRINTK("ncpfs: volume name too long: %d\n", len); + goto out; + } + memcpy(&(target->volume_name), ncp_reply_data(server, 22), len); + result = 0; +out: + ncp_unlock_server(server); + return result; +} + int ncp_close_file(struct ncp_server *server, const char *file_id) { @@ -248,10 +304,37 @@ } } -static void ncp_extract_file_info(void *structure, struct nw_info_struct *target) +int ncp_dirhandle_alloc(struct ncp_server* server, __u8 volnum, __u32 dirent, + __u8* dirhandle) { + int result; + + ncp_init_request(server); + ncp_add_byte(server, 12); /* subfunction */ + ncp_add_byte(server, NW_NS_DOS); + ncp_add_byte(server, 0); + ncp_add_word(server, 0); + ncp_add_handle_path(server, volnum, dirent, 1, NULL); + if ((result = ncp_request(server, 87)) == 0) { + *dirhandle = ncp_reply_byte(server, 0); + } + ncp_unlock_server(server); + return result; +} + +int ncp_dirhandle_free(struct ncp_server* server, __u8 dirhandle) { + int result; + + ncp_init_request_s(server, 20); + ncp_add_byte(server, dirhandle); + result = ncp_request(server, 22); + ncp_unlock_server(server); + return result; +} + +void ncp_extract_file_info(void *structure, struct nw_info_struct *target) { __u8 *name_len; - const int info_struct_size = sizeof(struct nw_info_struct) - 257; + const int info_struct_size = offsetof(struct nw_info_struct, nameLen); memcpy(target, structure, info_struct_size); name_len = structure + info_struct_size; @@ -261,6 +344,56 @@ return; } +#ifdef CONFIG_NCPFS_NFS_NS +static inline void ncp_extract_nfs_info(unsigned char *structure, + struct nw_nfs_info *target) +{ + target->mode = DVAL_LH(structure); + target->rdev = DVAL_LH(structure + 8); +} +#endif + +int ncp_obtain_nfs_info(struct ncp_server *server, + struct nw_info_struct *target) + +{ + int result = 0; +#ifdef CONFIG_NCPFS_NFS_NS + __u32 volnum = target->volNumber; + + if (ncp_is_nfs_extras(server, volnum)) { + ncp_init_request(server); + ncp_add_byte(server, 19); /* subfunction */ + ncp_add_byte(server, server->name_space[volnum]); + ncp_add_byte(server, NW_NS_NFS); + ncp_add_byte(server, 0); + ncp_add_byte(server, volnum); + ncp_add_dword(server, target->dirEntNum); + /* We must retrieve both nlinks and rdev, otherwise some server versions + report zeroes instead of valid data */ + ncp_add_dword_lh(server, NSIBM_NFS_MODE | NSIBM_NFS_NLINKS | NSIBM_NFS_RDEV); + + if ((result = ncp_request(server, 87)) == 0) { + ncp_extract_nfs_info(ncp_reply_data(server, 0), &target->nfs); + DPRINTK(KERN_DEBUG + "ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n", + target->entryName, target->nfs.mode, + target->nfs.rdev); + } else { + target->nfs.mode = 0; + target->nfs.rdev = 0; + } + ncp_unlock_server(server); + + } else +#endif + { + target->nfs.mode = 0; + target->nfs.rdev = 0; + } + return result; +} + /* * Returns information for a (one-component) name relative to * the specified directory. @@ -287,6 +420,10 @@ if ((result = ncp_request(server, 87)) != 0) goto out; ncp_extract_file_info(ncp_reply_data(server, 0), target); + ncp_unlock_server(server); + + result = ncp_obtain_nfs_info(server, target); + return result; out: ncp_unlock_server(server); @@ -463,6 +600,7 @@ /* set dates to Jan 1, 1986 00:00 */ target->creationTime = target->modifyTime = cpu_to_le16(0x0000); target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21); + target->nfs.mode = 0; return 0; } @@ -500,6 +638,34 @@ info_mask, info); } +#ifdef CONFIG_NCPFS_NFS_NS +int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __u32 dirent, + __u32 mode, __u32 rdev) + +{ + int result = 0; + + if (server->name_space[volnum] == NW_NS_NFS) { + ncp_init_request(server); + ncp_add_byte(server, 25); /* subfunction */ + ncp_add_byte(server, server->name_space[volnum]); + ncp_add_byte(server, NW_NS_NFS); + ncp_add_byte(server, volnum); + ncp_add_dword(server, dirent); + /* we must always operate on both nlinks and rdev, otherwise + rdev is not set */ + ncp_add_dword_lh(server, NSIBM_NFS_MODE | NSIBM_NFS_NLINKS | NSIBM_NFS_RDEV); + ncp_add_dword_lh(server, mode); + ncp_add_dword_lh(server, 1); /* nlinks */ + ncp_add_dword_lh(server, rdev); + result = ncp_request(server, 87); + ncp_unlock_server(server); + } + return result; +} +#endif + + static int ncp_DeleteNSEntry(struct ncp_server *server, __u8 have_dir_base, __u8 volnum, __u32 dirent, @@ -577,15 +743,12 @@ struct ncp_entry_info *target) { __u16 search_attribs = ntohs(0x0600); - __u8 volnum = target->i.volNumber; - __u32 dirent = target->i.dirEntNum; + __u8 volnum; + __u32 dirent; int result; - if (dir) - { - volnum = NCP_FINFO(dir)->volNumber; - dirent = NCP_FINFO(dir)->dirEntNum; - } + volnum = NCP_FINFO(dir)->volNumber; + dirent = NCP_FINFO(dir)->dirEntNum; if ((create_attributes & aDIR) != 0) { search_attribs |= ntohs(0x0080); @@ -606,12 +769,16 @@ goto out; if (!(create_attributes & aDIR)) target->opened = 1; - target->server_file_handle = ncp_reply_dword(server, 0); - target->open_create_action = ncp_reply_byte(server, 4); /* in target there's a new finfo to fill */ ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i)); - ConvertToNWfromDWORD(target->server_file_handle, target->file_handle); + target->volume = target->i.volNumber; + ConvertToNWfromDWORD(ncp_reply_dword(server, 0), target->file_handle); + + ncp_unlock_server(server); + + (void)ncp_obtain_nfs_info(server, &(target->i)); + return 0; out: ncp_unlock_server(server); @@ -672,9 +839,62 @@ memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq)); ncp_extract_file_info(ncp_reply_data(server, 10), target); + ncp_unlock_server(server); + + result = ncp_obtain_nfs_info(server, target); + return result; + out: ncp_unlock_server(server); return result; +} + +int ncp_search_for_fileset(struct ncp_server *server, + struct nw_search_sequence *seq, + int* more, + int* cnt, + char* buffer, + size_t bufsize, + char** rbuf, + size_t* rsize) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 20); + ncp_add_byte(server, server->name_space[seq->volNumber]); + ncp_add_byte(server, 0); /* datastream */ + ncp_add_word(server, htons(0x0680)); + ncp_add_dword(server, RIM_ALL); + ncp_add_word(server, 32767); /* max returned items */ + ncp_add_mem(server, seq, 9); +#ifdef CONFIG_NCPFS_NFS_NS + if (server->name_space[seq->volNumber] == NW_NS_NFS) { + ncp_add_byte(server, 0); /* 0 byte pattern */ + } else +#endif + { + ncp_add_byte(server, 2); /* 2 byte pattern */ + ncp_add_byte(server, 0xff); /* following is a wildcard */ + ncp_add_byte(server, '*'); + } + result = ncp_request2(server, 87, buffer, bufsize); + if (result) { + ncp_unlock_server(server); + return result; + } + if (server->ncp_reply_size < 12) { + ncp_unlock_server(server); + return 0xFF; + } + *rsize = server->ncp_reply_size - 12; + ncp_unlock_server(server); + buffer = buffer + sizeof(struct ncp_reply_header); + *rbuf = buffer + 12; + *cnt = WVAL_LH(buffer + 10); + *more = BVAL(buffer + 9); + memcpy(seq, buffer, 9); + return 0; } int diff -Nru a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h --- a/fs/ncpfs/ncplib_kernel.h Fri Jul 26 19:58:51 2002 +++ b/fs/ncpfs/ncplib_kernel.h Fri Jul 26 19:58:51 2002 @@ -44,8 +44,13 @@ int ncp_negotiate_buffersize(struct ncp_server *, int, int *); int ncp_negotiate_size_and_options(struct ncp_server *server, int size, int options, int *ret_size, int *ret_options); -int ncp_get_volume_info_with_number(struct ncp_server *, int, - struct ncp_volume_info *); + +int ncp_get_volume_info_with_number(struct ncp_server* server, int n, + struct ncp_volume_info *target); + +int ncp_get_directory_info(struct ncp_server* server, __u8 dirhandle, + struct ncp_volume_info* target); + int ncp_close_file(struct ncp_server *, const char *); static inline int ncp_read_bounce_size(__u32 size) { return sizeof(struct ncp_reply_header) + 2 + 2 + size + 8; @@ -61,13 +66,17 @@ atomic_dec(&NCP_FINFO(inode)->opened); } +void ncp_extract_file_info(void* src, struct nw_info_struct* target); int ncp_obtain_info(struct ncp_server *server, struct inode *, char *, struct nw_info_struct *target); +int ncp_obtain_nfs_info(struct ncp_server *server, struct nw_info_struct *target); int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *); int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *, __u32, const struct nw_modify_dos_info *info); int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *, const char* path, __u32, const struct nw_modify_dos_info *info); +int ncp_modify_nfs_info(struct ncp_server *, __u8 volnum, __u32 dirent, + __u32 mode, __u32 rdev); int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*); int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *); @@ -79,6 +88,11 @@ int ncp_search_for_file_or_subdir(struct ncp_server *server, struct nw_search_sequence *seq, struct nw_info_struct *target); +int ncp_search_for_fileset(struct ncp_server *server, + struct nw_search_sequence *seq, + int* more, int* cnt, + char* buffer, size_t bufsize, + char** rbuf, size_t* rsize); int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, struct inode *, char *, struct inode *, char *); @@ -99,6 +113,20 @@ int ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *, __u8, __u8, __u32); +int ncp_dirhandle_alloc(struct ncp_server *, __u8 vol, __u32 dirent, __u8 *dirhandle); +int ncp_dirhandle_free(struct ncp_server *, __u8 dirhandle); + +int ncp_create_new(struct inode *dir, struct dentry *dentry, + int mode, int rdev, int attributes); + +static inline int ncp_is_nfs_extras(struct ncp_server* server, unsigned int volnum) { +#ifdef CONFIG_NCPFS_NFS_NS + return (server->m.flags & NCP_MOUNT_NFS_EXTRAS) && + (server->name_space[volnum] == NW_NS_NFS); +#else + return 0; +#endif +} #ifdef CONFIG_NCPFS_NLS diff -Nru a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c --- a/fs/ncpfs/symlink.c Fri Jul 26 19:58:52 2002 +++ b/fs/ncpfs/symlink.c Fri Jul 26 19:58:52 2002 @@ -7,19 +7,21 @@ * the file to make sure we don't accidentally use a non-link file * as a link. * + * When using the NFS namespace, we set the mode to indicate a symlink and + * don't bother with the magic numbers. + * * from linux/fs/ext2/symlink.c * * Copyright (C) 1998-99, Frank A. Vorstenbosch * * ncpfs symlink handling code * NLS support (c) 1999 Petr Vandrovec + * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info * */ #include -#ifdef CONFIG_NCPFS_EXTRAS - #include #include @@ -28,7 +30,6 @@ #include #include #include -#include #include "ncplib_kernel.h" @@ -38,30 +39,25 @@ #define NCP_SYMLINK_MAGIC0 le32_to_cpu(0x6c6d7973) /* "symlnk->" */ #define NCP_SYMLINK_MAGIC1 le32_to_cpu(0x3e2d6b6e) -int ncp_create_new(struct inode *dir, struct dentry *dentry, - int mode,int attributes); - /* ----- read a symbolic link ------------------------------------------ */ static int ncp_symlink_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; - int error, length, len, cnt; - char *link; + int error, length, len; + char *link, *rawlink; char *buf = kmap(page); error = -ENOMEM; - for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) { - if (cnt > 10) - goto fail; - schedule(); - } + rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS); + if (!rawlink) + goto fail; if (ncp_make_open(inode,O_RDONLY)) goto failEIO; error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle, - 0,NCP_MAX_SYMLINK_SIZE,link,&length); + 0,NCP_MAX_SYMLINK_SIZE,rawlink,&length); ncp_inode_close(inode); /* Close file handle if no other users... */ @@ -69,14 +65,20 @@ if (error) goto failEIO; - if (lengthflags & NCPI_KLUDGE_SYMLINK) { + if (lengthvolNumber)) + kludge = 0; + else +#ifdef CONFIG_NCPFS_EXTRAS + if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS) + kludge = 1; + else #endif + /* EPERM is returned by VFS if symlink procedure does not exist */ + return -EPERM; + + rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS); + if (!rawlink) + return -ENOMEM; - if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)) - return -EPERM; /* EPERM is returned by VFS if symlink procedure does not exist */ + if (kludge) { + mode = 0; + attr = aSHARED | aHIDDEN; + ((__u32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0; + ((__u32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1; + hdr = 8; + } else { + mode = S_IFLNK | S_IRWXUGO; + attr = 0; + hdr = 0; + } - if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE-8) - return -EINVAL; + length = strlen(symname); + /* map to/from server charset, do not touch upper/lower case as + symlink can point out of ncp filesystem */ + outlen = NCP_MAX_SYMLINK_SIZE - hdr; + err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0); + if (err) + goto failfree; - if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL) - return -ENOMEM; + outlen += hdr; err = -EIO; - lock_kernel(); - if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN)) + if (ncp_create_new(dir,dentry,mode,0,attr)) { goto failfree; + } inode=dentry->d_inode; if (ncp_make_open(inode, O_WRONLY)) goto failfree; - ((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0; - ((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1; - - /* map to/from server charset, do not touch upper/lower case as - symlink can point out of ncp filesystem */ - length += 1; - err = ncp_io2vol(NCP_SERVER(inode),link+8,&length,symname,length-1,0); - if (err) - goto fail; - - if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, - 0, length+8, link, &i) || i!=length+8) { - err = -EIO; + if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, + 0, outlen, rawlink, &i) || i!=outlen) { goto fail; } ncp_inode_close(inode); ncp_make_closed(inode); - unlock_kernel(); - kfree(link); + kfree(rawlink); return 0; - -fail: +fail:; ncp_inode_close(inode); ncp_make_closed(inode); -failfree: - unlock_kernel(); - kfree(link); - return err; +failfree:; + kfree(rawlink); + return err; } -#endif /* ----- EOF ----- */ diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c Fri Jul 26 19:58:51 2002 +++ b/fs/nfs/dir.c Fri Jul 26 19:58:51 2002 @@ -430,16 +430,9 @@ } static inline -int nfs_lookup_verify_inode(struct inode *inode, int flags) +int nfs_lookup_verify_inode(struct inode *inode) { - struct nfs_server *server = NFS_SERVER(inode); - /* - * If we're interested in close-to-open cache consistency, - * then we revalidate the inode upon lookup. - */ - if (!(server->flags & NFS_MOUNT_NOCTO) && !(flags & LOOKUP_CONTINUE)) - NFS_CACHEINV(inode); - return nfs_revalidate_inode(server, inode); + return nfs_revalidate_inode(NFS_SERVER(inode), inode); } /* @@ -497,7 +490,7 @@ /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { - if (nfs_lookup_verify_inode(inode, flags)) + if (nfs_lookup_verify_inode(inode)) goto out_bad; goto out_valid; } @@ -1087,38 +1080,70 @@ int nfs_permission(struct inode *inode, int mask) { - int error = vfs_permission(inode, mask); - - if (!NFS_PROTO(inode)->access) - goto out; + struct nfs_access_cache *cache = &NFS_I(inode)->cache_access; + struct rpc_cred *cred; + int mode = inode->i_mode; + int res; - if (error == -EROFS) - goto out; + if (mask & MAY_WRITE) { + /* + * + * Nobody gets write access to a read-only fs. + * + */ + if (IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; - /* - * Trust UNIX mode bits except: - * - * 1) When override capabilities may have been invoked - * 2) When root squashing may be involved - * 3) When ACLs may overturn a negative answer */ - if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH) - && (current->fsuid != 0) && (current->fsgid != 0) - && error != -EACCES) - goto out; + /* + * + * Nobody gets write access to an immutable file. + * + */ + if (IS_IMMUTABLE(inode)) + return -EACCES; + } lock_kernel(); - error = NFS_PROTO(inode)->access(inode, mask, 0); + if (!NFS_PROTO(inode)->access) + goto out_notsup; - if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv && - current->uid != 0 && current->gid != 0 && - (current->fsuid != current->uid || current->fsgid != current->gid)) - error = NFS_PROTO(inode)->access(inode, mask, 1); + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + if (cache->cred == cred + && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) { + if (!(res = cache->err)) { + /* Is the mask a subset of an accepted mask? */ + if ((cache->mask & mask) == mask) + goto out; + } else { + /* ...or is it a superset of a rejected mask? */ + if ((cache->mask & mask) == cache->mask) + goto out; + } + } + res = NFS_PROTO(inode)->access(inode, cred, mask); + if (!res || res == -EACCES) + goto add_cache; +out: + put_rpccred(cred); unlock_kernel(); - - out: - return error; + return res; +out_notsup: + nfs_revalidate_inode(NFS_SERVER(inode), inode); + res = vfs_permission(inode, mask); + unlock_kernel(); + return res; +add_cache: + cache->jiffies = jiffies; + if (cache->cred) + put_rpccred(cache->cred); + cache->cred = cred; + cache->mask = mask; + cache->err = res; + unlock_kernel(); + return res; } /* diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c Fri Jul 26 19:58:52 2002 +++ b/fs/nfs/inode.c Fri Jul 26 19:58:52 2002 @@ -125,10 +125,14 @@ static void nfs_clear_inode(struct inode *inode) { - struct rpc_cred *cred = NFS_I(inode)->mm_cred; + struct nfs_inode *nfsi = NFS_I(inode); + struct rpc_cred *cred = nfsi->mm_cred; if (cred) put_rpccred(cred); + cred = nfsi->cache_access.cred; + if (cred) + put_rpccred(cred); } void @@ -425,7 +429,8 @@ goto failure_kill_reqlist; } - /* We're airborne */ + /* We're airborne Set socket buffersize */ + rpc_setbufsize(clnt, server->wsize + 100, server->rsize + 100); /* Check whether to start the lockd process */ if (!(server->flags & NFS_MOUNT_NONLM)) @@ -721,6 +726,7 @@ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); + NFS_I(inode)->cache_access.cred = NULL; unlock_new_inode(inode); } else @@ -854,15 +860,23 @@ { struct rpc_auth *auth; struct rpc_cred *cred; + int err = 0; lock_kernel(); + /* Ensure that we revalidate the data cache */ + if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOCTO) { + err = __nfs_revalidate_inode(NFS_SERVER(inode),inode); + if (err) + goto out; + } auth = NFS_CLIENT(inode)->cl_auth; cred = rpcauth_lookupcred(auth, 0); filp->private_data = cred; if (filp->f_mode & FMODE_WRITE) nfs_set_mmcred(inode, cred); +out: unlock_kernel(); - return 0; + return err; } int nfs_release(struct inode *inode, struct file *filp) @@ -1075,6 +1089,16 @@ NFS_CACHE_ISIZE(inode) = new_size; inode->i_size = new_isize; + + if (inode->i_mode != fattr->mode || + inode->i_uid != fattr->uid || + inode->i_gid != fattr->gid) { + struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred; + if (*cred) { + put_rpccred(*cred); + *cred = NULL; + } + } inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c --- a/fs/nfs/nfs3proc.c Fri Jul 26 19:58:51 2002 +++ b/fs/nfs/nfs3proc.c Fri Jul 26 19:58:51 2002 @@ -133,16 +133,22 @@ } static int -nfs3_proc_access(struct inode *inode, int mode, int ruid) +nfs3_proc_access(struct inode *inode, struct rpc_cred *cred, int mode) { struct nfs_fattr fattr; struct nfs3_accessargs arg = { - fh: NFS_FH(inode), + .fh = NFS_FH(inode), }; struct nfs3_accessres res = { - fattr: &fattr, + .fattr = &fattr, }; - int status, flags; + struct rpc_message msg = { + .rpc_proc = NFS3PROC_ACCESS, + .rpc_argp = &arg, + .rpc_resp = &res, + .rpc_cred = cred + }; + int status; dprintk("NFS call access\n"); fattr.valid = 0; @@ -160,8 +166,7 @@ if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_EXECUTE; } - flags = (ruid) ? RPC_CALL_REALUID : 0; - status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply access\n"); diff -Nru a/fs/open.c b/fs/open.c --- a/fs/open.c Fri Jul 26 19:58:50 2002 +++ b/fs/open.c Fri Jul 26 19:58:50 2002 @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -30,6 +31,9 @@ retval = -ENOSYS; if (sb->s_op && sb->s_op->statfs) { memset(buf, 0, sizeof(struct statfs)); + retval = security_ops->sb_statfs(sb); + if (retval) + return retval; retval = sb->s_op->statfs(sb, buf); } } diff -Nru a/fs/partitions/Config.help b/fs/partitions/Config.help --- a/fs/partitions/Config.help Fri Jul 26 19:58:51 2002 +++ b/fs/partitions/Config.help Fri Jul 26 19:58:51 2002 @@ -46,15 +46,14 @@ Windows 2000 introduced the concept of Dynamic Disks to get around the limitations of the PC's partitioning scheme. The Logical Disk - Manager allows the user to repartion a disk and create spanned, + Manager allows the user to repartition a disk and create spanned, mirrored, striped or RAID volumes, all without the need for rebooting. Normal partitions are now called Basic Disks under Windows 2000 and XP. - Technical documentation to accompany this driver is available from: - . + For a fuller description read . If unsure, say N. diff -Nru a/fs/partitions/Config.in b/fs/partitions/Config.in --- a/fs/partitions/Config.in Fri Jul 26 19:58:51 2002 +++ b/fs/partitions/Config.in Fri Jul 26 19:58:51 2002 @@ -25,7 +25,7 @@ bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL fi - dep_bool ' Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL + dep_bool ' Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION if [ "$CONFIG_LDM_PARTITION" = "y" ]; then bool ' Windows LDM extra logging' CONFIG_LDM_DEBUG fi diff -Nru a/fs/partitions/ldm.c b/fs/partitions/ldm.c --- a/fs/partitions/ldm.c Fri Jul 26 19:58:51 2002 +++ b/fs/partitions/ldm.c Fri Jul 26 19:58:51 2002 @@ -1,1020 +1,1476 @@ -/* - * ldm - Part of the Linux-NTFS project. +/** + * ldm - Support for Windows Logical Disk Manager (Dynamic Disks) * - * Copyright (C) 2001 Richard Russon - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 2001,2002 Richard Russon + * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001,2002 Jakob Kemi * * Documentation is available at http://linux-ntfs.sf.net/ldm * - * 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 (in the main directory of the Linux-NTFS source - * in the file COPYING); if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * 28/10/2001 - Added sorting of ldm partitions. (AIA) + * 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 (in the main directory of the source in the file COPYING); if + * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA */ + #include -#include "check.h" +#include #include "ldm.h" +#include "check.h" #include "msdos.h" -#if 0 /* Fool kernel-doc since it doesn't do macros yet. */ +typedef enum { + FALSE = 0, + TRUE = 1 +} BOOL; + /** - * ldm_debug - output an error message if debugging was enabled at compile time - * @f: a printf format string containing the message - * @...: the variables to substitute into @f + * ldm_debug/info/error/crit - Output an error message + * @f: A printf format string containing the message + * @...: Variables to substitute into @f * * ldm_debug() writes a DEBUG level message to the syslog but only if the * driver was compiled with debug enabled. Otherwise, the call turns into a NOP. */ -static void ldm_debug(const char *f, ...); +#ifndef CONFIG_LDM_DEBUG +#define ldm_debug(...) do {} while (0) +#else +#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __FUNCTION__, f, ##a) #endif -#ifdef CONFIG_LDM_DEBUG -#define ldm_debug(f, a...) \ - { \ - printk(LDM_DEBUG " DEBUG (%s, %d): %s: ", \ - __FILE__, __LINE__, __FUNCTION__); \ - printk(f, ##a); \ - } -#else /* !CONFIG_LDM_DEBUG */ -#define ldm_debug(f, a...) do {} while (0) -#endif /* !CONFIG_LDM_DEBUG */ -/* Necessary forward declarations. */ -static int parse_privhead(const u8 *, struct privhead *); -static u64 get_vnum(const u8 *, int *); -static int get_vstr(const u8 *, u8 *, const int); +#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __FUNCTION__, f, ##a) +#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __FUNCTION__, f, ##a) +#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __FUNCTION__, f, ##a) + +__attribute__ ((format (printf, 3, 4))) +static void _ldm_printk (const char *level, const char *function, + const char *fmt, ...) +{ + static char buf[128]; + va_list args; + + va_start (args, fmt); + vsnprintf (buf, sizeof (buf), fmt, args); + va_end (args); + + printk ("%s%s(): %s\n", level, function, buf); +} + /** - * parse_vblk_part - parse a LDM database vblk partition record - * @buffer: vblk partition record loaded from the LDM database - * @buf_size: size of @buffer in bytes - * @vb: in memory vblk structure to return parsed information in + * ldm_parse_hexbyte - Convert a ASCII hex number to a byte + * @src: Pointer to at least 2 characters to convert. * - * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition - * record, supplied in @buffer and sets up the in memory vblk structure @vb - * with the obtained information. + * Convert a two character ASCII hex string to a number. * - * Return 1 on success and -1 on error, in which case @vb is undefined. + * Return: 0-255 Success, the byte was parsed correctly + * -1 Error, an invalid character was supplied */ -static int parse_vblk_part(const u8 *buffer, const int buf_size, - struct vblk *vb) +static int ldm_parse_hexbyte (const u8 *src) { - int err, rel_objid, rel_name, rel_size, rel_parent; + unsigned int x; /* For correct wrapping */ + int h; - if (0x34 >= buf_size) - return -1; - /* Calculate relative offsets. */ - rel_objid = 1 + buffer[0x18]; - if (0x18 + rel_objid >= buf_size) - return -1; - rel_name = 1 + buffer[0x18 + rel_objid] + rel_objid; - if (0x34 + rel_name >= buf_size) - return -1; - rel_size = 1 + buffer[0x34 + rel_name] + rel_name; - if (0x34 + rel_size >= buf_size) - return -1; - rel_parent = 1 + buffer[0x34 + rel_size] + rel_size; - if (0x34 + rel_parent >= buf_size) - return -1; - /* Setup @vb. */ - vb->vblk_type = VBLK_PART; - vb->obj_id = get_vnum(buffer + 0x18, &err); - if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size) - return -1; - vb->disk_id = get_vnum(buffer + 0x34 + rel_parent, &err); - if (err || 0x24 + rel_name + 8 > buf_size) - return -1; - vb->start_sector = BE64(buffer + 0x24 + rel_name); - if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size) - return -1; - vb->num_sectors = get_vnum(buffer + 0x34 + rel_name, &err); - if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size) - return -1; - err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name)); - if (err == -1) - return err; - ldm_debug("Parsed Partition VBLK successfully.\n"); - return 1; + /* high part */ + if ((x = src[0] - '0') <= '9'-'0') h = x; + else if ((x = src[0] - 'a') <= 'f'-'a') h = x+10; + else if ((x = src[0] - 'A') <= 'F'-'A') h = x+10; + else return -1; + h <<= 4; + + /* low part */ + if ((x = src[1] - '0') <= '9'-'0') return h | x; + if ((x = src[1] - 'a') <= 'f'-'a') return h | (x+10); + if ((x = src[1] - 'A') <= 'F'-'A') return h | (x+10); + return -1; } /** - * parse_vblk - parse a LDM database vblk record - * @buffer: vblk record loaded from the LDM database - * @buf_size: size of @buffer in bytes - * @vb: in memory vblk structure to return parsed information in + * ldm_parse_guid - Convert GUID from ASCII to binary + * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba + * @dest: Memory block to hold binary GUID (16 bytes) * - * This parses the LDM database vblk record supplied in @buffer and sets up - * the in memory vblk structure @vb with the obtained information. + * N.B. The GUID need not be NULL terminated. + * + * Return: TRUE @dest contains binary GUID + * FALSE @dest contents are undefined + */ +static BOOL ldm_parse_guid (const u8 *src, u8 *dest) +{ + static const int size[] = { 4, 2, 2, 2, 6 }; + int i, j, v; + + if (src[8] != '-' || src[13] != '-' || + src[18] != '-' || src[23] != '-') + return FALSE; + + for (j = 0; j < 5; j++, src++) + for (i = 0; i < size[j]; i++, src+=2, *dest++ = v) + if ((v = ldm_parse_hexbyte (src)) < 0) + return FALSE; + + return TRUE; +} + + +/** + * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure + * @data: Raw database PRIVHEAD structure loaded from the device + * @ph: In-memory privhead structure in which to return parsed information * - * Return 1 on success, 0 if successful but record not in use, and -1 on error. - * If the return value is 0 or -1, @vb is undefined. + * This parses the LDM database PRIVHEAD structure supplied in @data and + * sets up the in-memory privhead structure @ph with the obtained information. * - * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records - * describing a partition. For all others, we just set @vb->vblk_type to 0 and - * return success. This of course means that if @vb->vblk_type is zero, all - * other fields in @vb are undefined. + * Return: TRUE @ph contains the PRIVHEAD data + * FALSE @ph contents are undefined */ -static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) +static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph) { - int err = 1; + BUG_ON (!data || !ph); - if (buf_size < 0x14) - return -1; - if (MAGIC_VBLK != BE32(buffer)) { - printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n"); - return -1; + if (MAGIC_PRIVHEAD != BE64 (data)) { + ldm_error ("Cannot find PRIVHEAD structure. LDM database is" + " corrupt. Aborting."); + return FALSE; } - if ((BE16(buffer + 0x0E) == 0) || /* Record is not in use. */ - (BE16(buffer + 0x0C) != 0)) /* Part 2 of an ext. record */ - return 0; - /* FIXME: What about extended VBLKs? */ - switch (buffer[0x13]) { - case VBLK_PART: - err = parse_vblk_part(buffer, buf_size, vb); - break; - default: - vb->vblk_type = 0; + + ph->ver_major = BE16 (data + 0x000C); + ph->ver_minor = BE16 (data + 0x000E); + ph->logical_disk_start = BE64 (data + 0x011B); + ph->logical_disk_size = BE64 (data + 0x0123); + ph->config_start = BE64 (data + 0x012B); + ph->config_size = BE64 (data + 0x0133); + + if ((ph->ver_major != 2) || (ph->ver_minor != 11)) { + ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d." + " Aborting.", 2, 11, ph->ver_major, ph->ver_minor); + return FALSE; } - if (err != -1) - ldm_debug("Parsed VBLK successfully.\n"); - return err; + if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ + /* Warn the user and continue, carefully */ + ldm_info ("Database is normally %u bytes, it claims to " + "be %llu bytes.", LDM_DB_SIZE, + (unsigned long long)ph->config_size ); + } + if ((ph->logical_disk_size == 0) || + (ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) { + ldm_error ("PRIVHEAD disk size doesn't match real disk size"); + return FALSE; + } + + if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) { + ldm_error ("PRIVHEAD contains an invalid GUID."); + return FALSE; + } + + ldm_debug ("Parsed PRIVHEAD successfully."); + return TRUE; } /** - * add_partition_to_list - insert partition into a partition list - * @pl: sorted list of partitions - * @disk_size: number of sectors on the disk device - * @start: first sector within the disk device - * @size: number of sectors on the partition device + * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure + * @data: Raw database TOCBLOCK structure loaded from the device + * @toc: In-memory toc structure in which to return parsed information * - * This sanity checks the partition specified by @start and @size against the - * device specified by @hd and inserts the partition into the sorted partition - * list @pl if the checks pass. + * This parses the LDM Database TOCBLOCK (table of contents) structure supplied + * in @data and sets up the in-memory tocblock structure @toc with the obtained + * information. * - * On success return 1, otherwise return -1. + * N.B. The *_start and *_size values returned in @toc are not range-checked. * - * TODO: Add sanity check for overlapping partitions. (AIA) - */ -static int add_partition_to_list(struct list_head *pl, - const unsigned long disk_size, - const unsigned long start, - const unsigned long size) + * Return: TRUE @toc contains the TOCBLOCK data + * FALSE @toc contents are undefined + */ +static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc) { - struct ldm_part *lp, *lptmp; - struct list_head *tmp; + BUG_ON (!data || !toc); - if (start < 1 || start + size > disk_size) { - printk(LDM_CRIT "LDM partition exceeds physical disk. " - "Skipping.\n"); - return -1; + if (MAGIC_TOCBLOCK != BE64 (data)) { + ldm_crit ("Cannot find TOCBLOCK, database may be corrupt."); + return FALSE; + } + strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name)); + toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0; + toc->bitmap1_start = BE64 (data + 0x2E); + toc->bitmap1_size = BE64 (data + 0x36); + + if (strncmp (toc->bitmap1_name, TOC_BITMAP1, + sizeof (toc->bitmap1_name)) != 0) { + ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.", + TOC_BITMAP1, toc->bitmap1_name); + return FALSE; + } + strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name)); + toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0; + toc->bitmap2_start = BE64 (data + 0x50); + toc->bitmap2_size = BE64 (data + 0x58); + if (strncmp (toc->bitmap2_name, TOC_BITMAP2, + sizeof (toc->bitmap2_name)) != 0) { + ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.", + TOC_BITMAP2, toc->bitmap2_name); + return FALSE; } - lp = (struct ldm_part*)kmalloc(sizeof(struct ldm_part), GFP_KERNEL); - if (!lp) { - printk(LDM_CRIT "Not enough memory! Aborting LDM partition " - "parsing.\n"); - return -2; - } - INIT_LIST_HEAD(&lp->part_list); - lp->start = start; - lp->size = size; - list_for_each(tmp, pl) { - lptmp = list_entry(tmp, struct ldm_part, part_list); - if (start > lptmp->start) - continue; - if (start < lptmp->start) - break; - printk(LDM_CRIT "Duplicate LDM partition entry! Skipping.\n"); - kfree(lp); - return -1; - } - list_add_tail(&lp->part_list, tmp); - ldm_debug("Added LDM partition successfully.\n"); - return 1; + ldm_debug ("Parsed TOCBLOCK successfully."); + return TRUE; } /** - * create_data_partitions - create the data partition devices - * @hd: gendisk structure in which to create the data partitions - * @first_part_minor: first minor number of data partition devices - * @dev: partition device holding the LDM database - * @vm: in memory vmdb structure of @dev - * @ph: in memory privhead structure of the disk device - * @dk: in memory ldmdisk structure of the disk device + * ldm_parse_vmdb - Read the LDM Database VMDB structure + * @data: Raw database VMDB structure loaded from the device + * @vm: In-memory vmdb structure in which to return parsed information * - * The database contains ALL the partitions for ALL the disks, so we need to - * filter out this specific disk. Using the disk's object id, we can find all - * the partitions in the database that belong to this disk. + * This parses the LDM Database VMDB structure supplied in @data and sets up + * the in-memory vmdb structure @vm with the obtained information. + * + * N.B. The *_start, *_size and *_seq values will be range-checked later. * - * For each found partition, we create a corresponding partition device starting - * with minor number @first_part_minor. But we do this in such a way that we - * actually sort the partitions in order of on-disk position. Any invalid - * partitions are completely ignored/skipped (an error is output but that's - * all). - * - * Return 1 on success and -1 on error. - */ -static int create_data_partitions(struct parsed_partitions *state, - int slot, struct block_device *bdev, const struct vmdb *vm, - const struct privhead *ph, const struct ldmdisk *dk, - unsigned long base) + * Return: TRUE @vm contains VMDB info + * FALSE @vm contents are undefined + */ +static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm) { - Sector sect; - unsigned char *data; - struct vblk *vb; - LIST_HEAD(pl); /* Sorted list of partitions. */ - struct ldm_part *lp; - struct list_head *tmp; - int vblk; - int vsize; /* VBLK size. */ - int perbuf; /* VBLKs per buffer. */ - int buffer, lastbuf, lastofs, err; - - vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL); - if (!vb) - goto no_mem; - vsize = vm->vblk_size; - if (vsize < 1 || vsize > 512) - goto err_out; - perbuf = 512 / vsize; - if (perbuf < 1 || 512 % vsize) - goto err_out; - /* 512 == VMDB size */ - lastbuf = vm->last_vblk_seq / perbuf - 1; - lastofs = vm->last_vblk_seq % perbuf; - if (lastofs) - lastbuf++; - if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > - ph->config_size * 512) - goto err_out; - for (buffer = 0; buffer < lastbuf; buffer++) { - data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); - if (!data) - goto read_err; - for (vblk = 0; vblk < perbuf; vblk++) { - u8 *block; - - if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) - break; - block = data + vsize * vblk; - if (block + vsize > data + 512) - goto brelse_out; - if (parse_vblk(block, vsize, vb) != 1) - continue; - if (vb->vblk_type != VBLK_PART) - continue; - if (dk->obj_id != vb->disk_id) - continue; - /* Ignore invalid partition errors. */ - if (add_partition_to_list(&pl, - bdev->bd_inode->i_size>>9, - vb->start_sector + - ph->logical_disk_start, - vb->num_sectors) < -1) - goto brelse_out; - } - put_dev_sector(sect); + BUG_ON (!data || !vm); + + if (MAGIC_VMDB != BE32 (data)) { + ldm_crit ("Cannot find the VMDB, database may be corrupt."); + return FALSE; } - err = 1; -out: - /* Finally create the nicely sorted data partitions. */ - printk(" <"); - list_for_each(tmp, &pl) { - lp = list_entry(tmp, struct ldm_part, part_list); - put_partition(state, slot++, lp->start, lp->size); - } - printk(" >\n"); - if (!list_empty(&pl)) { - struct list_head *tmp2; - - /* Cleanup the partition list which is now superfluous. */ - list_for_each_safe(tmp, tmp2, &pl) { - lp = list_entry(tmp, struct ldm_part, part_list); - list_del(tmp); - kfree(lp); - } + + vm->ver_major = BE16 (data + 0x12); + vm->ver_minor = BE16 (data + 0x14); + if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { + ldm_error ("Expected VMDB version %d.%d, got %d.%d. " + "Aborting.", 4, 10, vm->ver_major, vm->ver_minor); + return FALSE; } - kfree(vb); - return err; -brelse_out: - put_dev_sector(sect); - goto err_out; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); - goto err_out; -read_err: - printk(LDM_CRIT "Disk read failed in create_partitions.\n"); -err_out: - err = -1; - goto out; + + vm->vblk_size = BE32 (data + 0x08); + vm->vblk_offset = BE32 (data + 0x0C); + vm->last_vblk_seq = BE32 (data + 0x04); + + ldm_debug ("Parsed VMDB successfully."); + return TRUE; } /** - * get_vnum - convert a variable-width, big endian number, to cpu u64 one - * @block: pointer to the variable-width number to convert - * @err: address of an integer into which to return the error code. - * - * This converts a variable-width, big endian number into a 64-bit, CPU format - * number and returns the result with err set to 0. If an error occurs return 0 - * with err set to -1. + * ldm_compare_privheads - Compare two privhead objects + * @ph1: First privhead + * @ph2: Second privhead + * + * This compares the two privhead structures @ph1 and @ph2. * - * The first byte of a variable-width number is the size of the number in bytes. + * Return: TRUE Identical + * FALSE Different */ -static u64 get_vnum(const u8 *block, int *err) +static BOOL ldm_compare_privheads (const struct privhead *ph1, + const struct privhead *ph2) { - u64 tmp = 0ULL; - u8 length = *block++; + BUG_ON (!ph1 || !ph2); - if (length && length <= 8) { - while (length--) - tmp = (tmp << 8) | *block++; - *err = 0; - } else { - printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length); - *err = 1; - } - return tmp; + return ((ph1->ver_major == ph2->ver_major) && + (ph1->ver_minor == ph2->ver_minor) && + (ph1->logical_disk_start == ph2->logical_disk_start) && + (ph1->logical_disk_size == ph2->logical_disk_size) && + (ph1->config_start == ph2->config_start) && + (ph1->config_size == ph2->config_size) && + !memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE)); } /** - * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one - * @block: string to convert - * @buffer: output buffer - * @buflen: size of output buffer + * ldm_compare_tocblocks - Compare two tocblock objects + * @toc1: First toc + * @toc2: Second toc * - * This converts @block, a counted, non-null-terminated ASCII string, into a - * C-style, null-terminated, ASCII string and returns this in @buffer. The - * maximum number of characters converted is given by @buflen. + * This compares the two tocblock structures @toc1 and @toc2. * - * The first bytes of a counted string stores the length of the string in bytes. + * Return: TRUE Identical + * FALSE Different + */ +static BOOL ldm_compare_tocblocks (const struct tocblock *toc1, + const struct tocblock *toc2) +{ + BUG_ON (!toc1 || !toc2); + + return ((toc1->bitmap1_start == toc2->bitmap1_start) && + (toc1->bitmap1_size == toc2->bitmap1_size) && + (toc1->bitmap2_start == toc2->bitmap2_start) && + (toc1->bitmap2_size == toc2->bitmap2_size) && + !strncmp (toc1->bitmap1_name, toc2->bitmap1_name, + sizeof (toc1->bitmap1_name)) && + !strncmp (toc1->bitmap2_name, toc2->bitmap2_name, + sizeof (toc1->bitmap2_name))); +} + +/** + * ldm_validate_privheads - Compare the primary privhead with its backups + * @bdev: Device holding the LDM Database + * @ph1: Memory struct to fill with ph contents + * + * Read and compare all three privheads from disk. + * + * The privheads on disk show the size and location of the main disk area and + * the configuration area (the database). The values are range-checked against + * @hd, which contains the real size of the disk. * - * Return the number of characters written to @buffer, not including the - * terminating null character, on success, and -1 on error, in which case - * @buffer is not defined. + * Return: TRUE Success + * FALSE Error */ -static int get_vstr(const u8 *block, u8 *buffer, const int buflen) +static BOOL ldm_validate_privheads (struct block_device *bdev, + struct privhead *ph1) { - int length = block[0]; + static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 }; + struct privhead *ph[3] = { ph1 }; + Sector sect; + u8 *data; + BOOL result = FALSE; + long num_sects; + int i; + + BUG_ON (!bdev || !ph1); + + ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL); + ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL); + if (!ph[1] || !ph[2]) { + ldm_crit ("Out of memory."); + goto out; + } - if (length < 1) - return -1; - if (length >= buflen) { - printk(LDM_ERR "String too long for buffer in get_vstr(): " - "(%d/%d). Truncating.\n", length, buflen); - length = buflen - 1; + /* off[1 & 2] are relative to ph[0]->config_start */ + ph[0]->config_start = 0; + + /* Read and parse privheads */ + for (i = 0; i < 3; i++) { + data = read_dev_sector (bdev, + ph[0]->config_start + off[i], §); + if (!data) { + ldm_crit ("Disk read failed."); + goto out; + } + result = ldm_parse_privhead (data, ph[i]); + put_dev_sector (sect); + if (!result) { + ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */ + if (i < 2) + goto out; /* Already logged */ + else + break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */ + } } - memcpy(buffer, block + 1, length); - buffer[length] = (u8)'\0'; - return length; + + num_sects = bdev->bd_inode->i_size >> 9; + + if ((ph[0]->config_start > num_sects) || + ((ph[0]->config_start + ph[0]->config_size) > num_sects)) { + ldm_crit ("Database extends beyond the end of the disk."); + goto out; + } + + if ((ph[0]->logical_disk_start > ph[0]->config_start) || + ((ph[0]->logical_disk_start + ph[0]->logical_disk_size) + > ph[0]->config_start)) { + ldm_crit ("Disk and database overlap."); + goto out; + } + + if (!ldm_compare_privheads (ph[0], ph[1])) { + ldm_crit ("Primary and backup PRIVHEADs don't match."); + goto out; + } + /* FIXME ignore this for now + if (!ldm_compare_privheads (ph[0], ph[2])) { + ldm_crit ("Primary and backup PRIVHEADs don't match."); + goto out; + }*/ + ldm_debug ("Validated PRIVHEADs successfully."); + result = TRUE; +out: + kfree (ph[1]); + kfree (ph[2]); + return result; } /** - * get_disk_objid - obtain the object id for the device we are working on - * @dev: partition device holding the LDM database - * @vm: in memory vmdb structure of the LDM database - * @ph: in memory privhead structure of the device we are working on - * @dk: in memory ldmdisk structure to return information into - * - * This obtains the object id for the device we are working on as defined by - * the private header @ph. The obtained object id, together with the disk's - * GUID from @ph are returned in the ldmdisk structure pointed to by @dk. - * - * A Disk has two Ids. The main one is a GUID in string format. The second, - * used internally for cross-referencing, is a small, sequentially allocated, - * number. The PRIVHEAD, just after the partition table, tells us the disk's - * GUID. To find the disk's object id, we have to look through the database. - * - * Return 1 on success and -1 on error, in which case @dk is undefined. - */ -static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm, - const struct privhead *ph, struct ldmdisk *dk, - unsigned long base) + * ldm_validate_tocblocks - Validate the table of contents and its backups + * @bdev: Device holding the LDM Database + * @base: Offset, into @bdev, of the database + * @ldb: Cache of the database structures + * + * Find and compare the four tables of contents of the LDM Database stored on + * @bdev and return the parsed information into @toc1. + * + * The offsets and sizes of the configs are range-checked against a privhead. + * + * Return: TRUE @toc1 contains validated TOCBLOCK info + * FALSE @toc1 contents are undefined + */ +static BOOL ldm_validate_tocblocks (struct block_device *bdev, + unsigned long base, struct ldmdb *ldb) { + static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4}; + struct tocblock *tb[4]; + struct privhead *ph; Sector sect; - unsigned char *data; - u8 *disk_id; - int vblk; - int vsize; /* VBLK size. */ - int perbuf; /* VBLKs per buffer. */ - int buffer, lastbuf, lastofs, err; - - disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL); - if (!disk_id) - goto no_mem; - vsize = vm->vblk_size; - if (vsize < 1 || vsize > 512) - goto err_out; - perbuf = 512 / vsize; - if (perbuf < 1 || 512 % vsize) - goto err_out; - /* 512 == VMDB size */ - lastbuf = vm->last_vblk_seq / perbuf - 1; - lastofs = vm->last_vblk_seq % perbuf; - if (lastofs) - lastbuf++; - if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > - ph->config_size * 512) - goto err_out; - for (buffer = 0; buffer < lastbuf; buffer++) { - data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); - if (!data) - goto read_err; - for (vblk = 0; vblk < perbuf; vblk++) { - int rel_objid, rel_name, delta; - u8 *block; - - if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) - break; - block = data + vblk * vsize; - delta = vblk * vsize + 0x18; - if (delta >= 512) - goto brelse_out; - if (block[0x0D] != 0) /* Extended VBLK, ignore */ - continue; - if ((block[0x13] != VBLK_DSK1) && - (block[0x13] != VBLK_DSK2)) - continue; - /* Calculate relative offsets. */ - rel_objid = 1 + block[0x18]; - if (delta + rel_objid >= 512) - goto brelse_out; - rel_name = 1 + block[0x18 + rel_objid] + rel_objid; - if (delta + rel_name >= 512 || - delta + rel_name + block[0x18 + rel_name] >= 512) - goto brelse_out; - err = get_vstr(block + 0x18 + rel_name, disk_id, - DISK_ID_SIZE); - if (err == -1) - goto brelse_out; - if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) { - dk->obj_id = get_vnum(block + 0x18, &err); - put_dev_sector(sect); - if (err) - goto out; - strncpy(dk->disk_id, ph->disk_id, - sizeof(dk->disk_id)); - dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0'; - err = 1; - goto out; - } + u8 *data; + BOOL result = FALSE; + int i; + + BUG_ON (!bdev || !ldb); + + ph = &ldb->ph; + tb[0] = &ldb->toc; + tb[1] = kmalloc (sizeof (*tb[1]), GFP_KERNEL); + tb[2] = kmalloc (sizeof (*tb[2]), GFP_KERNEL); + tb[3] = kmalloc (sizeof (*tb[3]), GFP_KERNEL); + if (!tb[1] || !tb[2] || !tb[3]) { + ldm_crit ("Out of memory."); + goto out; + } + + for (i = 0; i < 4; i++) /* Read and parse all four toc's. */ + { + data = read_dev_sector (bdev, base + off[i], §); + if (!data) { + ldm_crit ("Disk read failed."); + goto out; } - put_dev_sector(sect); + result = ldm_parse_tocblock (data, tb[i]); + put_dev_sector (sect); + if (!result) + goto out; /* Already logged */ + } + + /* Range check the toc against a privhead. */ + if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) || + ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > ph->config_size)) { + ldm_crit ("The bitmaps are out of range. Giving up."); + goto out; } - err = -1; + + if (!ldm_compare_tocblocks (tb[0], tb[1]) || /* Compare all tocs. */ + !ldm_compare_tocblocks (tb[0], tb[2]) || + !ldm_compare_tocblocks (tb[0], tb[3])) { + ldm_crit ("The TOCBLOCKs don't match."); + goto out; + } + + ldm_debug ("Validated TOCBLOCKs successfully."); + result = TRUE; out: - kfree(disk_id); - return err; -brelse_out: - put_dev_sector(sect); - goto err_out; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); - goto err_out; -read_err: - printk(LDM_CRIT "Disk read failed in get_disk_objid.\n"); -err_out: - err = -1; - goto out; + kfree (tb[1]); + kfree (tb[2]); + kfree (tb[3]); + return result; } /** - * parse_vmdb - parse the LDM database vmdb structure - * @buffer: LDM database vmdb structure loaded from the device - * @vm: in memory vmdb structure to return parsed information in - * - * This parses the LDM database vmdb structure supplied in @buffer and sets up - * the in memory vmdb structure @vm with the obtained information. - * - * Return 1 on success and -1 on error, in which case @vm is undefined. + * ldm_validate_vmdb - Read the VMDB and validate it + * @bdev: Device holding the LDM Database + * @base: Offset, into @bdev, of the database + * @ldb: Cache of the database structures * - * NOTE: The *_start, *_size and *_seq values returned in @vm have not been - * checked for validity, so make sure to check them when using them. + * Find the vmdb of the LDM Database stored on @bdev and return the parsed + * information in @ldb. + * + * Return: TRUE @ldb contains validated VBDB info + * FALSE @ldb contents are undefined */ -static int parse_vmdb(const u8 *buffer, struct vmdb *vm) +static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base, + struct ldmdb *ldb) { - if (MAGIC_VMDB != BE32(buffer)) { - printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n"); - return -1; + Sector sect; + u8 *data; + BOOL result = FALSE; + struct vmdb *vm; + struct tocblock *toc; + + BUG_ON (!bdev || !ldb); + + vm = &ldb->vm; + toc = &ldb->toc; + + data = read_dev_sector (bdev, base + OFF_VMDB, §); + if (!data) { + ldm_crit ("Disk read failed."); + return FALSE; } - vm->ver_major = BE16(buffer + 0x12); - vm->ver_minor = BE16(buffer + 0x14); - if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { - printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. " - "Aborting.\n", 4, 10, vm->ver_major, - vm->ver_minor); - return -1; + + if (!ldm_parse_vmdb (data, vm)) + goto out; /* Already logged */ + + /* Are there uncommitted transactions? */ + if (BE16(data + 0x10) != 0x01) { + ldm_crit ("Database is not in a consistant state. Aborting."); + goto out; } - vm->vblk_size = BE32(buffer + 0x08); - vm->vblk_offset = BE32(buffer + 0x0C); - vm->last_vblk_seq = BE32(buffer + 0x04); - ldm_debug("Parsed VMDB successfully.\n"); - return 1; + if (vm->vblk_offset != 512) + ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset); + + /* FIXME: How should we handle this situation? */ + if ((vm->vblk_size * vm->last_vblk_seq) != (toc->bitmap1_size << 9)) + ldm_info ("VMDB and TOCBLOCK don't agree on the database size."); + + result = TRUE; +out: + put_dev_sector (sect); + return result; } + /** - * validate_vmdb - validate the vmdb - * @dev: partition device holding the LDM database - * @vm: in memory vmdb in which to return information + * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk + * @bdev: Device holding the LDM Database * - * Find the vmdb of the LDM database stored on @dev and return the parsed - * information into @vm. + * This function provides a weak test to decide whether the device is a dynamic + * disk or not. It looks for an MS-DOS-style partition table containing at + * least one partition of type 0x42 (formerly SFS, now used by Windows for + * dynamic disks). + * + * N.B. The only possible error can come from the read_dev_sector and that is + * only likely to happen if the underlying device is strange. If that IS + * the case we should return zero to let someone else try. * - * Return 1 on success and -1 on error, in which case @vm is undefined. + * Return: TRUE @bdev is a dynamic disk + * FALSE @bdev is not a dynamic disk, or an error occurred */ -static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base) +static BOOL ldm_validate_partition_table (struct block_device *bdev) { Sector sect; - unsigned char *data; - int ret; + u8 *data; + struct partition *p; + int i; + BOOL result = FALSE; + + BUG_ON (!bdev); - data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, §); + data = read_dev_sector (bdev, 0, §); if (!data) { - printk(LDM_CRIT "Disk read failed in validate_vmdb.\n"); - return -1; + ldm_crit ("Disk read failed."); + return FALSE; + } + + if (*(u16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC)) { + ldm_debug ("No MS-DOS partition table found."); + goto out; } - ret = parse_vmdb(data, vm); - put_dev_sector(sect); - return ret; + + p = (struct partition*)(data + 0x01BE); + for (i = 0; i < 4; i++, p++) + if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) { + result = TRUE; + break; + } + + if (result) + ldm_debug ("Parsed partition table successfully."); + else + ldm_debug ("Found an MS-DOS partition table, not a dynamic disk."); +out: + put_dev_sector (sect); + return result; } /** - * compare_tocblocks - compare two tables of contents - * @toc1: first toc - * @toc2: second toc + * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id + * @ldb: Cache of the database structures * - * This compares the two tables of contents @toc1 and @toc2. + * The LDM Database contains a list of all partitions on all dynamic disks. The + * primary PRIVHEAD, at the beginning of the physical disk, tells us the GUID of + * this disk. This function searches for the GUID in a linked list of vblk's. * - * Return 1 if @toc1 and @toc2 are equal and -1 otherwise. + * Return: Pointer, A matching vblk was found + * NULL, No match, or an error */ -static int compare_tocblocks(const struct tocblock *toc1, - const struct tocblock *toc2) +static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb) { - if ((toc1->bitmap1_start == toc2->bitmap1_start) && - (toc1->bitmap1_size == toc2->bitmap1_size) && - (toc1->bitmap2_start == toc2->bitmap2_start) && - (toc1->bitmap2_size == toc2->bitmap2_size) && - !strncmp(toc1->bitmap1_name, toc2->bitmap1_name, - sizeof(toc1->bitmap1_name)) && - !strncmp(toc1->bitmap2_name, toc2->bitmap2_name, - sizeof(toc1->bitmap2_name))) - return 1; - return -1; + struct list_head *item; + + BUG_ON (!ldb); + + list_for_each (item, &ldb->v_disk) { + struct vblk *v = list_entry (item, struct vblk, list); + if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE)) + return v; + } + + return NULL; } /** - * parse_tocblock - parse the LDM database table of contents structure - * @buffer: LDM database toc structure loaded from the device - * @toc: in memory toc structure to return parsed information in + * ldm_create_data_partitions - Create data partitions for this device + * @pp: List of the partitions parsed so far + * @ldb: Cache of the database structures * - * This parses the LDM database table of contents structure supplied in @buffer - * and sets up the in memory table of contents structure @toc with the obtained - * information. + * The database contains ALL the partitions for ALL disk groups, so we need to + * filter out this specific disk. Using the disk's object id, we can find all + * the partitions in the database that belong to this disk. * - * Return 1 on success and -1 on error, in which case @toc is undefined. + * Add each partition in our database, to the parsed_partitions structure. * - * FIXME: The *_start and *_size values returned in @toc are not been checked - * for validity but as we don't use the actual values for anything other than - * comparing between the toc and its backups, the values are not important. + * N.B. This function creates the partitions in the order it finds partition + * objects in the linked list. + * + * Return: TRUE Partition created + * FALSE Error, probably a range checking problem */ -static int parse_tocblock(const u8 *buffer, struct tocblock *toc) +static BOOL ldm_create_data_partitions (struct parsed_partitions *pp, + const struct ldmdb *ldb) { - if (MAGIC_TOCBLOCK != BE64(buffer)) { - printk(LDM_CRIT "Cannot find TOCBLOCK, database may be " - "corrupt.\n"); - return -1; + struct list_head *item; + struct vblk *vb; + struct vblk *disk; + struct vblk_part *part; + int part_num = 1; + + BUG_ON (!pp || !ldb); + + disk = ldm_get_disk_objid (ldb); + if (!disk) { + ldm_crit ("Can't find the ID of this disk in the database."); + return FALSE; } - strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name)); - toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0'; - toc->bitmap1_start = BE64(buffer + 0x2E); - toc->bitmap1_size = BE64(buffer + 0x36); - /*toc->bitmap1_flags = BE64(buffer + 0x3E);*/ - if (strncmp(toc->bitmap1_name, TOC_BITMAP1, - sizeof(toc->bitmap1_name)) != 0) { - printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is " - "%s.\n", TOC_BITMAP1, toc->bitmap1_name); - return -1; + + printk (" [LDM]"); + + /* Create the data partitions */ + list_for_each (item, &ldb->v_part) { + vb = list_entry (item, struct vblk, list); + part = &vb->vblk.part; + + if (part->disk_id != disk->obj_id) + continue; + + put_partition (pp, part_num, ldb->ph.logical_disk_start + + part->start, part->size); + part_num++; } - strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name)); - toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0'; - toc->bitmap2_start = BE64(buffer + 0x50); - toc->bitmap2_size = BE64(buffer + 0x58); - /*toc->bitmap2_flags = BE64(buffer + 0x60);*/ - if (strncmp(toc->bitmap2_name, TOC_BITMAP2, - sizeof(toc->bitmap2_name)) != 0) { - printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is " - "%s.\n", TOC_BITMAP2, toc->bitmap2_name); + + printk ("\n"); + return TRUE; +} + + +/** + * ldm_relative - Calculate the next relative offset + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @base: Size of the previous fixed width fields + * @offset: Cumulative size of the previous variable-width fields + * + * Because many of the VBLK fields are variable-width, it's necessary + * to calculate each offset based on the previous one and the length + * of the field it pointed to. + * + * Return: -1 Error, the calculated offset exceeded the size of the buffer + * n OK, a range-checked offset into buffer + */ +static int ldm_relative (const u8 *buffer, int buflen, int base, int offset) +{ + + base += offset; + if ((!buffer) || (offset < 0) || (base > buflen)) return -1; - } - ldm_debug("Parsed TOCBLOCK successfully.\n"); - return 1; + if ((base + buffer[base]) >= buflen) + return -1; + + return buffer[base] + offset + 1; } /** - * validate_tocblocks - validate the table of contents and its backups - * @dev: partition device holding the LDM database - * @toc1: in memory table of contents in which to return information + * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order + * @block: Pointer to the variable-width number to convert + * + * Large numbers in the LDM Database are often stored in a packed format. Each + * number is prefixed by a one byte width marker. All numbers in the database + * are stored in big-endian byte order. This function reads one of these + * numbers and returns the result * - * Find and compare the four tables of contents of the LDM database stored on - * @dev and return the parsed information into @toc1. + * N.B. This function DOES NOT perform any range checking, though the most + * it will read is eight bytes. * - * Return 1 on success and -1 on error, in which case @toc1 is undefined. + * Return: n A number + * 0 Zero, or an error occurred */ -static int validate_tocblocks(struct block_device *bdev, - struct tocblock *toc1, - unsigned long base) +static u64 ldm_get_vnum (const u8 *block) { - Sector sect; - unsigned char *data; - struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL; - int err; - - toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL); - if (!toc2) - goto no_mem; - toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL); - if (!toc3) - goto no_mem; - toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL); - if (!toc4) - goto no_mem; - /* Read and parse first toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, §); - if (!data) { - printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc1); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Read and parse second toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, §); - if (!data) { - printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc2); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Read and parse third toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, §); - if (!data) { - printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc3); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Read and parse fourth toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, §); - if (!data) { - printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n"); - goto err_out; + u64 tmp = 0; + u8 length; + + BUG_ON (!block); + + length = *block++; + + if (length && length <= 8) + while (length--) + tmp = (tmp << 8) | *block++; + else + ldm_error ("Illegal length %d.", length); + + return tmp; +} + +/** + * ldm_get_vstr - Read a length-prefixed string into a buffer + * @block: Pointer to the length marker + * @buffer: Location to copy string to + * @buflen: Size of the output buffer + * + * Many of the strings in the LDM Database are not NULL terminated. Instead + * they are prefixed by a one byte length marker. This function copies one of + * these strings into a buffer. + * + * N.B. This function DOES NOT perform any range checking on the input. + * If the buffer is too small, the output will be truncated. + * + * Return: 0, Error and @buffer contents are undefined + * n, String length in characters (excluding NULL) + * buflen-1, String was truncated. + */ +static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen) +{ + int length; + + BUG_ON (!block || !buffer); + + length = block[0]; + if (length >= buflen) { + ldm_error ("Truncating string %d -> %d.", length, buflen); + length = buflen - 1; } - err = parse_tocblock(data, toc4); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Compare all tocs. */ - err = compare_tocblocks(toc1, toc2); - if (err != 1) { - printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n"); - goto out; + memcpy (buffer, block + 1, length); + buffer[length] = 0; + return length; +} + + +/** + * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Component object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Component VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len; + struct vblk_comp *comp; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_vstate = ldm_relative (buffer, buflen, 0x18, r_name); + r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate); + r_parent = ldm_relative (buffer, buflen, 0x2D, r_child); + + if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) { + r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent); + r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe); + len = r_cols; + } else { + r_stripe = 0; + r_cols = 0; + len = r_parent; + } + if (len < 0) + return FALSE; + + len += VBLK_SIZE_CMP3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + comp = &vb->vblk.comp; + ldm_get_vstr (buffer + 0x18 + r_name, comp->state, + sizeof (comp->state)); + comp->type = buffer[0x18 + r_vstate]; + comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate); + comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child); + comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0; + + return TRUE; +} + +/** + * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk Group object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Disk Group VBLK + * FALSE @vb contents are not defined + */ +static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_diskid, r_id1, r_id2, len; + struct vblk_dgrp *dgrp; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_diskid = ldm_relative (buffer, buflen, 0x18, r_name); + + if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) { + r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid); + r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1); + len = r_id2; + } else { + r_id1 = 0; + r_id2 = 0; + len = r_diskid; + } + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DGR3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + dgrp = &vb->vblk.dgrp; + ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id, + sizeof (dgrp->disk_id)); + return TRUE; +} + +/** + * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk Group object (version 4) into a vblk structure. + * + * Return: TRUE @vb contains a Disk Group VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb) +{ + char buf[64]; + int r_objid, r_name, r_id1, r_id2, len; + struct vblk_dgrp *dgrp; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + + if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) { + r_id1 = ldm_relative (buffer, buflen, 0x44, r_name); + r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1); + len = r_id2; + } else { + r_id1 = 0; + r_id2 = 0; + len = r_name; } - err = compare_tocblocks(toc3, toc4); - if (err != 1) { - printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n"); - goto out; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DGR4; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + dgrp = &vb->vblk.dgrp; + + ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf)); + return TRUE; +} + +/** + * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Disk VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_diskid, r_altname, len; + struct vblk_disk *disk; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_diskid = ldm_relative (buffer, buflen, 0x18, r_name); + r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid); + len = r_altname; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DSK3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + disk = &vb->vblk.disk; + ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name, + sizeof (disk->alt_name)); + if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id)) + return FALSE; + + return TRUE; +} + +/** + * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk object (version 4) into a vblk structure. + * + * Return: TRUE @vb contains a Disk VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, len; + struct vblk_disk *disk; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + len = r_name; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DSK4; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + disk = &vb->vblk.disk; + memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE); + return TRUE; +} + +/** + * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Partition object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Partition VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len; + struct vblk_part *part; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_size = ldm_relative (buffer, buflen, 0x34, r_name); + r_parent = ldm_relative (buffer, buflen, 0x34, r_size); + r_diskid = ldm_relative (buffer, buflen, 0x34, r_parent); + + if (buffer[0x12] & VBLK_FLAG_PART_INDEX) { + r_index = ldm_relative (buffer, buflen, 0x34, r_diskid); + len = r_index; + } else { + r_index = 0; + len = r_diskid; } - err = compare_tocblocks(toc1, toc3); - if (err != 1) - printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n"); + if (len < 0) + return FALSE; + + len += VBLK_SIZE_PRT3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + part = &vb->vblk.part; + part->start = BE64 (buffer + 0x24 + r_name); + part->volume_offset = BE64 (buffer + 0x2C + r_name); + part->size = ldm_get_vnum (buffer + 0x34 + r_name); + part->parent_id = ldm_get_vnum (buffer + 0x34 + r_size); + part->disk_id = ldm_get_vnum (buffer + 0x34 + r_parent); + if (vb->flags & VBLK_FLAG_PART_INDEX) + part->partnum = buffer[0x35 + r_diskid]; else - ldm_debug("Validated TOCBLOCKs successfully.\n"); -out: - kfree(toc2); - kfree(toc3); - kfree(toc4); - return err; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); -err_out: - err = -1; - goto out; + part->partnum = 0; + + return TRUE; } /** - * compare_privheads - compare two privheads - * @ph1: first privhead - * @ph2: second privhead - * - * This compares the two privheads @ph1 and @ph2. - * - * Return 1 if @ph1 and @ph2 are equal and -1 otherwise. - */ -static int compare_privheads(const struct privhead *ph1, - const struct privhead *ph2) -{ - if ((ph1->ver_major == ph2->ver_major) && - (ph1->ver_minor == ph2->ver_minor) && - (ph1->logical_disk_start == ph2->logical_disk_start) && - (ph1->logical_disk_size == ph2->logical_disk_size) && - (ph1->config_start == ph2->config_start) && - (ph1->config_size == ph2->config_size) && - !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id))) - return 1; - return -1; + * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Volume object (version 5) into a vblk structure. + * + * Return: TRUE @vb contains a Volume VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2; + int r_drive, len; + struct vblk_volu *volu; + + BUG_ON (!buffer || !vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_vtype = ldm_relative (buffer, buflen, 0x18, r_name); + r_child = ldm_relative (buffer, buflen, 0x2E, r_vtype); + r_size = ldm_relative (buffer, buflen, 0x3E, r_child); + + if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) + r_id1 = ldm_relative (buffer, buflen, 0x53, r_size); + else + r_id1 = r_size; + + if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) + r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1); + else + r_id2 = r_id1; + + if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) + r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2); + else + r_size2 = r_id2; + + if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) + r_drive = ldm_relative (buffer, buflen, 0x53, r_size2); + else + r_drive = r_size2; + + len = r_drive; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_VOL5; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + volu = &vb->vblk.volu; + + ldm_get_vstr (buffer + 0x18 + r_name, volu->volume_type, + sizeof (volu->volume_type)); + memcpy (volu->volume_state, buffer + 0x19 + r_vtype, + sizeof (volu->volume_state)); + volu->size = ldm_get_vnum (buffer + 0x3E + r_child); + volu->partition_type = buffer[0x42 + r_size]; + memcpy (volu->guid, buffer + 0x43 + r_size, sizeof (volu->guid)); + if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { + ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint, + sizeof (volu->drive_hint)); + } + return TRUE; } /** - * validate_privheads - compare the privhead backups to the first one - * @dev: partition device holding the LDM database - * @ph1: first privhead which we have already validated before - * - * We already have one privhead from the beginning of the disk. - * Now we compare the two other copies for safety. - * - * Return 1 on succes and -1 on error. - */ -static int validate_privheads(struct block_device *bdev, - const struct privhead *ph1, - unsigned long base) + * ldm_parse_vblk - Read a raw VBLK object into a vblk structure + * @buf: Block of data being worked on + * @len: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK object into a vblk structure. This function just reads the + * information common to all VBLK types, then delegates the rest of the work to + * helper functions: ldm_parse_*. + * + * Return: TRUE @vb contains a VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb) { - Sector sect; - unsigned char *data; - struct privhead *ph2 = NULL, *ph3 = NULL; - int err; - - ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL); - if (!ph2) - goto no_mem; - ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL); - if (!ph3) - goto no_mem; - data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, §); - if (!data) { - printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n"); - goto err_out; - } - err = parse_privhead(data, ph2); - put_dev_sector(sect); - if (err != 1) - goto out; - data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, §); - if (!data) { - printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n"); - goto err_out; + BOOL result = FALSE; + int r_objid; + + BUG_ON (!buf || !vb); + + r_objid = ldm_relative (buf, len, 0x18, 0); + if (r_objid < 0) { + ldm_error ("VBLK header is corrupt."); + return FALSE; + } + + vb->flags = buf[0x12]; + vb->type = buf[0x13]; + vb->obj_id = ldm_get_vnum (buf + 0x18); + ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name)); + + switch (vb->type) { + case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break; + case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break; + case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break; + case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break; + case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break; + case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break; + case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break; + } + + if (result) + ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.", + (unsigned long long) vb->obj_id, vb->type); + else + ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).", + (unsigned long long) vb->obj_id, vb->type); + + return result; +} + + +/** + * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database + * @data: Raw VBLK to add to the database + * @len: Size of the raw VBLK + * @ldb: Cache of the database structures + * + * The VBLKs are sorted into categories. Partitions are also sorted by offset. + * + * N.B. This function does not check the validity of the VBLKs. + * + * Return: TRUE The VBLK was added + * FALSE An error occurred + */ +static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb) +{ + struct vblk *vb; + struct list_head *item; + + BUG_ON (!data || !ldb); + + vb = kmalloc (sizeof (*vb), GFP_KERNEL); + if (!vb) { + ldm_crit ("Out of memory."); + return FALSE; } - err = parse_privhead(data, ph3); - put_dev_sector(sect); - if (err != 1) - goto out; - err = compare_privheads(ph1, ph2); - if (err != 1) { - printk(LDM_CRIT "First and second PRIVHEADs don't match.\n"); - goto out; + + if (!ldm_parse_vblk (data, len, vb)) + return FALSE; /* Already logged */ + + /* Put vblk into the correct list. */ + switch (vb->type) { + case VBLK_DGR3: + case VBLK_DGR4: + list_add (&vb->list, &ldb->v_dgrp); + break; + case VBLK_DSK3: + case VBLK_DSK4: + list_add (&vb->list, &ldb->v_disk); + break; + case VBLK_VOL5: + list_add (&vb->list, &ldb->v_volu); + break; + case VBLK_CMP3: + list_add (&vb->list, &ldb->v_comp); + break; + case VBLK_PRT3: + /* Sort by the partition's start sector. */ + list_for_each (item, &ldb->v_part) { + struct vblk *v = list_entry (item, struct vblk, list); + if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) && + (v->vblk.part.start > vb->vblk.part.start)) { + list_add_tail (&vb->list, &v->list); + return TRUE; + } + } + list_add_tail (&vb->list, &ldb->v_part); + break; } - err = compare_privheads(ph1, ph3); - if (err != 1) - printk(LDM_CRIT "First and third PRIVHEADs don't match.\n"); - else - /* We _could_ have checked more. */ - ldm_debug("Validated PRIVHEADs successfully.\n"); -out: - kfree(ph2); - kfree(ph3); - return err; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); -err_out: - err = -1; - goto out; + return TRUE; } /** - * parse_privhead - parse the LDM database PRIVHEAD structure - * @buffer: LDM database privhead structure loaded from the device - * @ph: in memory privhead structure to return parsed information in + * ldm_frag_add - Add a VBLK fragment to a list + * @data: Raw fragment to be added to the list + * @size: Size of the raw fragment + * @frags: Linked list of VBLK fragments * - * This parses the LDM database PRIVHEAD structure supplied in @buffer and - * sets up the in memory privhead structure @ph with the obtained information. + * Fragmented VBLKs may not be consecutive in the database, so they are placed + * in a list so they can be pieced together later. * - * Return 1 on succes and -1 on error, in which case @ph is undefined. + * Return: TRUE Success, the VBLK was added to the list + * FALSE Error, a problem occurred */ -static int parse_privhead(const u8 *buffer, struct privhead *ph) +static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags) { - if (MAGIC_PRIVHEAD != BE64(buffer)) { - printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database " - "is corrupt. Aborting.\n"); - return -1; + struct frag *f; + struct list_head *item; + int rec, num, group; + + BUG_ON (!data || !frags); + + group = BE32 (data + 0x08); + rec = BE16 (data + 0x0C); + num = BE16 (data + 0x0E); + if ((num < 1) || (num > 4)) { + ldm_error ("A VBLK claims to have %d parts.", num); + return FALSE; } - ph->ver_major = BE16(buffer + 0x000C); - ph->ver_minor = BE16(buffer + 0x000E); - if ((ph->ver_major != 2) || (ph->ver_minor != 11)) { - printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. " - "Aborting.\n", 2, 11, ph->ver_major, - ph->ver_minor); - return -1; + + list_for_each (item, frags) { + f = list_entry (item, struct frag, list); + if (f->group == group) + goto found; } - ph->config_start = BE64(buffer + 0x012B); - ph->config_size = BE64(buffer + 0x0133); - if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ - printk(LDM_ERR "Database should be %u bytes, claims to be %Lu " - "bytes. Aborting.\n", LDM_DB_SIZE, - ph->config_size); - return -1; + + f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL); + if (!f) { + ldm_crit ("Out of memory."); + return FALSE; } - ph->logical_disk_start = BE64(buffer + 0x011B); - ph->logical_disk_size = BE64(buffer + 0x0123); - if (!ph->logical_disk_size || - ph->logical_disk_start + ph->logical_disk_size > ph->config_start) - return -1; - memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id)); + f->group = group; + f->num = num; + f->rec = rec; + f->map = 0xFF << num; + + list_add_tail (&f->list, frags); +found: + if (f->map & (1 << rec)) { + ldm_error ("Duplicate VBLK, part %d.", rec); + f->map &= 0x7F; /* Mark the group as broken */ + return FALSE; + } + + f->map |= (1 << rec); + + if (num > 0) { + data += VBLK_SIZE_HEAD; + size -= VBLK_SIZE_HEAD; + } + memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size); - ldm_debug("Parsed PRIVHEAD successfully.\n"); - return 1; + return TRUE; } /** - * find_db_partition - find our database - * @dev: device of which to create partition - * @ph: @dev's LDM database private header + * ldm_frag_free - Free a linked list of VBLK fragments + * @list: Linked list of fragments * - * Find the primary private header and the LDM database - * partition to wrap it. + * Free a linked list of VBLK fragments * - * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error. + * Return: none */ -static int find_db_partition(struct block_device *bdev, struct privhead *ph) +static void ldm_frag_free (struct list_head *list) { - Sector sect; - unsigned char *data; - int err; + struct list_head *item, *tmp; - data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, §); - if (!data) { - printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n"); - return -1; - } - if (BE64(data) != MAGIC_PRIVHEAD) { - ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk " - "or corrupt LDM database.\n"); - return 0; - } - err = parse_privhead(data, ph); - put_dev_sector(sect); - if (err <= 0) - return err; - if (ph->config_start < 1 || - ph->config_start + ph->config_size > bdev->bd_inode->i_size >> 9) { - printk(LDM_CRIT "LDM Partition exceeds physical disk. " - "Aborting.\n"); - err = -1; + BUG_ON (!list); + + list_for_each_safe (item, tmp, list) + kfree (list_entry (item, struct frag, list)); +} + +/** + * ldm_frag_commit - Validate fragmented VBLKs and add them to the database + * @frags: Linked list of VBLK fragments + * @ldb: Cache of the database structures + * + * Now that all the fragmented VBLKs have been collected, they must be added to + * the database for later use. + * + * Return: TRUE All the fragments we added successfully + * FALSE One or more of the fragments we invalid + */ +static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb) +{ + struct frag *f; + struct list_head *item; + + BUG_ON (!frags || !ldb); + + list_for_each (item, frags) { + f = list_entry (item, struct frag, list); + + if (f->map != 0xFF) { + ldm_error ("VBLK group %d is incomplete (0x%02x).", + f->group, f->map); + return FALSE; + } + + if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb)) + return FALSE; /* Already logged */ } - return err; + return TRUE; } /** - * validate_patition_table - check whether @dev is a dynamic disk - * @dev: device to test + * ldm_get_vblks - Read the on-disk database of VBLKs into memory + * @bdev: Device holding the LDM Database + * @base: Offset, into @bdev, of the database + * @ldb: Cache of the database structures * - * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition - * table with one or more entries of type 0x42 (the former Secure File System - * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it. - * If this succeeds we assume we have a dynamic disk, and not otherwise. + * To use the information from the VBLKs, they need to be read from the disk, + * unpacked and validated. We cache them in @ldb according to their type. * - * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error. + * Return: TRUE All the VBLKs were read successfully + * FALSE An error occurred */ -static int validate_partition_table(struct block_device *bdev) +static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base, + struct ldmdb *ldb) { + int size, perbuf, skip, finish, s, v, recs; + u8 *data = NULL; Sector sect; - unsigned char *data; - struct partition *p; - int i, nr_sfs; + BOOL result = FALSE; + LIST_HEAD (frags); - data = read_dev_sector(bdev, 0, §); - if (!data) - return -1; + BUG_ON (!bdev || !ldb); - if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { - ldm_debug("No MS-DOS partition found.\n"); - goto no_msdos_partition; - } - nr_sfs = 0; - p = (struct partition*)(data + 0x01BE); - for (i = 0; i < 4; i++) { - if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION) - continue; - if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) { - nr_sfs++; - continue; + size = ldb->vm.vblk_size; + perbuf = 512 / size; + skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */ + finish = (size * ldb->vm.last_vblk_seq) >> 9; + + for (s = skip; s < finish; s++) { /* For each sector */ + data = read_dev_sector (bdev, base + OFF_VMDB + s, §); + if (!data) { + ldm_crit ("Disk read failed."); + goto out; } - goto not_dynamic_disk; + + for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */ + if (MAGIC_VBLK != BE32 (data)) { + ldm_error ("Expected to find a VBLK."); + goto out; + } + + recs = BE16 (data + 0x0E); /* Number of records */ + if (recs == 1) { + if (!ldm_ldmdb_add (data, size, ldb)) + goto out; /* Already logged */ + } else if (recs > 1) { + if (!ldm_frag_add (data, size, &frags)) + goto out; /* Already logged */ + } + /* else Record is not in use, ignore it. */ + } + put_dev_sector (sect); + data = NULL; } - if (!nr_sfs) - goto not_dynamic_disk; - ldm_debug("Parsed partition table successfully.\n"); - put_dev_sector(sect); - return 1; -not_dynamic_disk: -// ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n"); -no_msdos_partition: - put_dev_sector(sect); - return 0; + + result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */ +out: + if (data) + put_dev_sector (sect); + ldm_frag_free (&frags); + + return result; } /** - * ldm_partition - find out whether a device is a dynamic disk and handle it - * @hd: gendisk structure in which to return the handled disk - * @dev: device we need to look at + * ldm_free_vblks - Free a linked list of vblk's + * @lh: Head of a linked list of struct vblk + * + * Free a list of vblk's and free the memory used to maintain the list. * - * Description: + * Return: none + */ +static void ldm_free_vblks (struct list_head *lh) +{ + struct list_head *item, *tmp; + + BUG_ON (!lh); + + list_for_each_safe (item, tmp, lh) + kfree (list_entry (item, struct vblk, list)); +} + + +/** + * ldm_partition - Find out whether a device is a dynamic disk and handle it + * @pp: List of the partitions parsed so far + * @bdev: Device holding the LDM Database * - * This determines whether the device @dev is a dynamic disk and if so creates + * This determines whether the device @bdev is a dynamic disk and if so creates * the partitions necessary in the gendisk structure pointed to by @hd. * - * We create a dummy device 1, which contains the LDM database, we skip - * devices 2-4 and then create each partition described by the LDM database - * in sequence as devices 5 and following. For example, if the device is hda, - * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the - * actual data containing partitions. - * - * Return values: - * - * 1 if @dev is a dynamic disk and we handled it, - * 0 if @dev is not a dynamic disk, - * -1 if an error occured. - */ -int ldm_partition(struct parsed_partitions *state, struct block_device *bdev) -{ - struct privhead *ph = NULL; - struct tocblock *toc = NULL; - struct vmdb *vm = NULL; - struct ldmdisk *dk = NULL; - unsigned long db_first; - int err; - - /* Check the partition table. */ - err = validate_partition_table(bdev); - if (err != 1) - return err; - if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL))) - goto no_mem; - /* Create the LDM database device. */ - err = find_db_partition(bdev, ph); - if (err != 1) - goto out; - db_first = ph->config_start; - put_partition(state, 1, db_first, ph->config_size); - /* Check the backup privheads. */ - err = validate_privheads(bdev, ph, db_first); - if (err != 1) - goto out; - /* Check the table of contents and its backups. */ - if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL))) - goto no_mem; - err = validate_tocblocks(bdev, toc, db_first); - if (err != 1) - goto out; - /* Check the vmdb. */ - if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL))) - goto no_mem; - err = validate_vmdb(bdev, vm, db_first); - if (err != 1) - goto out; - /* Find the object id for @dev in the LDM database. */ - if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL))) - goto no_mem; - err = get_disk_objid(bdev, vm, ph, dk, db_first); - if (err != 1) + * We create a dummy device 1, which contains the LDM database, and then create + * each partition described by the LDM database in sequence as devices 2+. For + * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3, + * and so on: the actual data containing partitions. + * + * Return: 1 Success, @bdev is a dynamic disk and we handled it + * 0 Success, @bdev is not a dynamic disk + * -1 An error occurred before enough information had been read + * Or @bdev is a dynamic disk, but it may be corrupted + */ +int ldm_partition (struct parsed_partitions *pp, struct block_device *bdev) +{ + struct ldmdb *ldb; + unsigned long base; + int result = -1; + + BUG_ON (!pp || !bdev); + + /* Look for signs of a Dynamic Disk */ + if (!ldm_validate_partition_table (bdev)) + return 0; + + ldb = kmalloc (sizeof (*ldb), GFP_KERNEL); + if (!ldb) { + ldm_crit ("Out of memory."); goto out; + } + + /* Parse and check privheads. */ + if (!ldm_validate_privheads (bdev, &ldb->ph)) + goto out; /* Already logged */ + + /* All further references are relative to base (database start). */ + base = ldb->ph.config_start; + + /* Parse and check tocs and vmdb. */ + if (!ldm_validate_tocblocks (bdev, base, ldb) || + !ldm_validate_vmdb (bdev, base, ldb)) + goto out; /* Already logged */ + + /* Initialize vblk lists in ldmdb struct */ + INIT_LIST_HEAD (&ldb->v_dgrp); + INIT_LIST_HEAD (&ldb->v_disk); + INIT_LIST_HEAD (&ldb->v_volu); + INIT_LIST_HEAD (&ldb->v_comp); + INIT_LIST_HEAD (&ldb->v_part); + + if (!ldm_get_vblks (bdev, base, ldb)) { + ldm_crit ("Failed to read the VBLKs from the database."); + goto cleanup; + } + /* Finally, create the data partition devices. */ - err = create_data_partitions(state, 1 + LDM_FIRST_PART_OFFSET, - bdev, vm, ph, dk, db_first); - if (err == 1) - ldm_debug("Parsed LDM database successfully.\n"); + if (ldm_create_data_partitions (pp, ldb)) { + ldm_debug ("Parsed LDM database successfully."); + result = 1; + } + /* else Already logged */ + +cleanup: + ldm_free_vblks (&ldb->v_dgrp); + ldm_free_vblks (&ldb->v_disk); + ldm_free_vblks (&ldb->v_volu); + ldm_free_vblks (&ldb->v_comp); + ldm_free_vblks (&ldb->v_part); out: - kfree(ph); - kfree(toc); - kfree(vm); - kfree(dk); - return err; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); - err = -1; - goto out; + kfree (ldb); + return result; } + diff -Nru a/fs/partitions/ldm.h b/fs/partitions/ldm.h --- a/fs/partitions/ldm.h Fri Jul 26 19:58:51 2002 +++ b/fs/partitions/ldm.h Fri Jul 26 19:58:51 2002 @@ -1,10 +1,9 @@ -#ifndef _FS_PT_LDM_H_ -#define _FS_PT_LDM_H_ -/* +/** * ldm - Part of the Linux-NTFS project. * - * Copyright (C) 2001 Richard Russon - * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001,2002 Richard Russon + * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001,2002 Jakob Kemi * * Documentation is available at http://linux-ntfs.sf.net/ldm * @@ -23,16 +22,18 @@ * in the file COPYING); if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _FS_PT_LDM_H_ +#define _FS_PT_LDM_H_ + #include +#include +#include +#include #include #include -#include -/* Borrowed from kernel.h. */ -#define LDM_PREFIX "LDM: " /* Prefix our error messages with this. */ -#define LDM_CRIT KERN_CRIT LDM_PREFIX /* critical conditions */ -#define LDM_ERR KERN_ERR LDM_PREFIX /* error conditions */ -#define LDM_DEBUG KERN_DEBUG LDM_PREFIX /* debug-level messages */ +struct parsed_partitions; /* Magic numbers in CPU format. */ #define MAGIC_VMDB 0x564D4442 /* VMDB */ @@ -41,41 +42,58 @@ #define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */ /* The defined vblk types. */ -#define VBLK_COMP 0x32 /* Component */ -#define VBLK_PART 0x33 /* Partition */ -#define VBLK_DSK1 0x34 /* Disk */ -#define VBLK_DSK2 0x44 /* Disk */ -#define VBLK_DGR1 0x35 /* Disk Group */ -#define VBLK_DGR2 0x45 /* Disk Group */ -#define VBLK_VOLU 0x51 /* Volume */ +#define VBLK_VOL5 0x51 /* Volume, version 5 */ +#define VBLK_CMP3 0x32 /* Component, version 3 */ +#define VBLK_PRT3 0x33 /* Partition, version 3 */ +#define VBLK_DSK3 0x34 /* Disk, version 3 */ +#define VBLK_DSK4 0x44 /* Disk, version 4 */ +#define VBLK_DGR3 0x35 /* Disk Group, version 3 */ +#define VBLK_DGR4 0x45 /* Disk Group, version 4 */ + +/* vblk flags indicating extra information will be present */ +#define VBLK_FLAG_COMP_STRIPE 0x10 +#define VBLK_FLAG_PART_INDEX 0x08 +#define VBLK_FLAG_DGR3_IDS 0x08 +#define VBLK_FLAG_DGR4_IDS 0x08 +#define VBLK_FLAG_VOLU_ID1 0x08 +#define VBLK_FLAG_VOLU_ID2 0x20 +#define VBLK_FLAG_VOLU_SIZE 0x80 +#define VBLK_FLAG_VOLU_DRIVE 0x02 + +/* size of a vblk's static parts */ +#define VBLK_SIZE_HEAD 16 +#define VBLK_SIZE_CMP3 22 /* Name and version */ +#define VBLK_SIZE_DGR3 12 +#define VBLK_SIZE_DGR4 44 +#define VBLK_SIZE_DSK3 12 +#define VBLK_SIZE_DSK4 45 +#define VBLK_SIZE_PRT3 28 +#define VBLK_SIZE_VOL5 59 + +/* component types */ +#define COMP_STRIPE 0x01 /* Stripe-set */ +#define COMP_BASIC 0x02 /* Basic disk */ +#define COMP_RAID 0x03 /* Raid-set */ /* Other constants. */ -#define LDM_BLOCKSIZE 1024 /* Size of block in bytes. */ #define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */ -#define LDM_FIRST_PART_OFFSET 4 /* Add this to first_part_minor - to get to the first data - partition device minor. */ -#define OFF_PRIVHEAD1 3 /* Offset of the first privhead +#define OFF_PRIV1 6 /* Offset of the first privhead relative to the start of the - device in units of - LDM_BLOCKSIZE. */ + device in sectors */ -/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */ -#define OFF_PRIVHEAD2 928 /* Backup private headers. */ -#define OFF_PRIVHEAD3 1023 - -#define OFF_TOCBLOCK1 0 /* Tables of contents. */ -#define OFF_TOCBLOCK2 1 -#define OFF_TOCBLOCK3 1022 -#define OFF_TOCBLOCK4 1023 - -#define OFF_VMDB 8 /* List of partitions. */ -#define OFF_VBLK 9 - -#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */ -#define WIN2K_EXTENDED_PARTITION 0x05 /* A standard extended - partition. */ +/* Offsets to structures within the LDM Database in sectors. */ +#define OFF_PRIV2 1856 /* Backup private headers. */ +#define OFF_PRIV3 2047 + +#define OFF_TOCB1 1 /* Tables of contents. */ +#define OFF_TOCB2 2 +#define OFF_TOCB3 2045 +#define OFF_TOCB4 2046 + +#define OFF_VMDB 17 /* List of partitions. */ + +#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */ #define TOC_BITMAP1 "config" /* Names of the two defined */ #define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ @@ -85,49 +103,42 @@ #define BE32(x) ((u32)be32_to_cpu(get_unaligned((u32*)(x)))) #define BE64(x) ((u64)be64_to_cpu(get_unaligned((u64*)(x)))) -/* Borrowed from msdos.c. */ +/* Borrowed from msdos.c */ #define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) -#define NR_SECTS(p) ({ __typeof__((p)->nr_sects) __a = \ - get_unaligned(&(p)->nr_sects); \ - le32_to_cpu(__a); \ - }) - -#define START_SECT(p) ({ __typeof__((p)->start_sect) __a = \ - get_unaligned(&(p)->start_sect);\ - le32_to_cpu(__a); \ - }) -/* In memory LDM database structures. */ +struct frag { /* VBLK Fragment handling */ + struct list_head list; + u32 group; + u8 num; /* Total number of records */ + u8 rec; /* This is record number n */ + u8 map; /* Which portions are in use */ + u8 data[0]; +}; -#define DISK_ID_SIZE 64 /* Size in bytes. */ +/* In memory LDM database structures. */ -struct ldmdisk { - u64 obj_id; - u8 disk_id[DISK_ID_SIZE]; -}; +#define GUID_SIZE 16 -struct privhead { /* Offsets and sizes are in sectors. */ +struct privhead { /* Offsets and sizes are in sectors. */ u16 ver_major; u16 ver_minor; u64 logical_disk_start; u64 logical_disk_size; u64 config_start; u64 config_size; - u8 disk_id[DISK_ID_SIZE]; + u8 disk_id[GUID_SIZE]; }; struct tocblock { /* We have exactly two bitmaps. */ u8 bitmap1_name[16]; u64 bitmap1_start; u64 bitmap1_size; - /*u64 bitmap1_flags;*/ u8 bitmap2_name[16]; u64 bitmap2_start; u64 bitmap2_size; - /*u64 bitmap2_flags;*/ }; -struct vmdb { +struct vmdb { /* VMDB: The database header */ u16 ver_major; u16 ver_minor; u32 vblk_size; @@ -135,22 +146,75 @@ u32 last_vblk_seq; }; -struct vblk { - u8 name[64]; - u8 vblk_type; - u64 obj_id; +struct vblk_comp { /* VBLK Component */ + u8 state[16]; + u64 parent_id; + u8 type; + u8 children; + u16 chunksize; +}; + +struct vblk_dgrp { /* VBLK Disk Group */ + u8 disk_id[64]; +}; + +struct vblk_disk { /* VBLK Disk */ + u8 disk_id[GUID_SIZE]; + u8 alt_name[128]; +}; + +struct vblk_part { /* VBLK Partition */ + u64 start; + u64 size; /* start, size and vol_off in sectors */ + u64 volume_offset; + u64 parent_id; u64 disk_id; - u64 start_sector; - u64 num_sectors; + u8 partnum; +}; + +struct vblk_volu { /* VBLK Volume */ + u8 volume_type[16]; + u8 volume_state[16]; + u8 guid[16]; + u8 drive_hint[4]; + u64 size; + u8 partition_type; }; -struct ldm_part { - struct list_head part_list; - unsigned long start; - unsigned long size; +struct vblk_head { /* VBLK standard header */ + u32 group; + u16 rec; + u16 nrec; +}; + +struct vblk { /* Generalised VBLK */ + u8 name[64]; + u64 obj_id; + u32 sequence; + u8 flags; + u8 type; + union { + struct vblk_comp comp; + struct vblk_dgrp dgrp; + struct vblk_disk disk; + struct vblk_part part; + struct vblk_volu volu; + } vblk; + struct list_head list; +}; + +struct ldmdb { /* Cache of the database */ + struct privhead ph; + struct tocblock toc; + struct vmdb vm; + struct list_head v_dgrp; + struct list_head v_disk; + struct list_head v_volu; + struct list_head v_comp; + struct list_head v_part; }; -int ldm_partition(struct parsed_partitions *state, struct block_device *bdev); +int ldm_partition (struct parsed_partitions *state, struct block_device *bdev); #endif /* _FS_PT_LDM_H_ */ diff -Nru a/fs/partitions/msdos.c b/fs/partitions/msdos.c --- a/fs/partitions/msdos.c Fri Jul 26 19:58:50 2002 +++ b/fs/partitions/msdos.c Fri Jul 26 19:58:50 2002 @@ -23,6 +23,7 @@ #include /* for invalidate_bdev() */ #ifdef CONFIG_BLK_DEV_IDE +#include #include /* IDE xlate */ #elif defined(CONFIG_BLK_DEV_IDE_MODULE) #include diff -Nru a/fs/proc/array.c b/fs/proc/array.c --- a/fs/proc/array.c Fri Jul 26 19:58:51 2002 +++ b/fs/proc/array.c Fri Jul 26 19:58:51 2002 @@ -386,7 +386,7 @@ task->nswap, task->cnswap, task->exit_signal, - task->thread_info->cpu, + task_cpu(task), task->rt_priority, task->policy); if(mm) diff -Nru a/fs/proc/base.c b/fs/proc/base.c --- a/fs/proc/base.c Fri Jul 26 19:58:50 2002 +++ b/fs/proc/base.c Fri Jul 26 19:58:50 2002 @@ -394,7 +394,7 @@ }; #define MAY_PTRACE(p) \ -(p==current||(p->parent==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED)) +(p==current||(p->parent==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED&&security_ops->ptrace(current,p)==0)) static int mem_open(struct inode* inode, struct file* file) diff -Nru a/fs/quota.c b/fs/quota.c --- a/fs/quota.c Fri Jul 26 19:58:52 2002 +++ b/fs/quota.c Fri Jul 26 19:58:52 2002 @@ -12,6 +12,7 @@ #include #include #include +#include /* Check validity of quotactl */ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) @@ -96,7 +97,8 @@ else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return 0; + + return security_ops->quotactl (cmd, type, id, sb); } /* Resolve device pathname to superblock */ diff -Nru a/fs/read_write.c b/fs/read_write.c --- a/fs/read_write.c Fri Jul 26 19:58:51 2002 +++ b/fs/read_write.c Fri Jul 26 19:58:51 2002 @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -117,6 +118,13 @@ file = fget(fd); if (!file) goto bad; + + retval = security_ops->file_llseek(file); + if (retval) { + fput(file); + goto bad; + } + retval = -EINVAL; if (origin <= 2) { loff_t res = llseek(file, offset, origin); @@ -142,6 +150,11 @@ file = fget(fd); if (!file) goto bad; + + retval = security_ops->file_llseek(file); + if (retval) + goto out_putf; + retval = -EINVAL; if (origin > 2) goto out_putf; @@ -176,9 +189,12 @@ ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count); if (!ret) { - ret = file->f_op->read(file, buf, count, pos); - if (ret > 0) - dnotify_parent(file->f_dentry, DN_ACCESS); + ret = security_ops->file_permission (file, MAY_READ); + if (!ret) { + ret = file->f_op->read(file, buf, count, pos); + if (ret > 0) + dnotify_parent(file->f_dentry, DN_ACCESS); + } } return ret; @@ -198,9 +214,12 @@ ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count); if (!ret) { - ret = file->f_op->write(file, buf, count, pos); - if (ret > 0) - dnotify_parent(file->f_dentry, DN_MODIFY); + ret = security_ops->file_permission (file, MAY_WRITE); + if (!ret) { + ret = file->f_op->write(file, buf, count, pos); + if (ret > 0) + dnotify_parent(file->f_dentry, DN_MODIFY); + } } return ret; @@ -301,17 +320,23 @@ if (copy_from_user(iov, vector, count*sizeof(*vector))) goto out; - /* BSD readv/writev returns EINVAL if one of the iov_len - values < 0 or tot_len overflowed a 32-bit integer. -ink */ + /* + * Single unix specification: + * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t + * The total length is fitting an ssize_t + * + * Be careful here because iov_len is a size_t not an ssize_t + */ + tot_len = 0; ret = -EINVAL; for (i = 0 ; i < count ; i++) { - size_t tmp = tot_len; - int len = iov[i].iov_len; - if (len < 0) + ssize_t tmp = tot_len; + ssize_t len = (ssize_t)iov[i].iov_len; + if (len < 0) /* size_t not fitting an ssize_t .. */ goto out; - (u32)tot_len += len; - if (tot_len < tmp || tot_len < (u32)len) + tot_len += len; + if (tot_len < tmp) /* maths overflow on the ssize_t */ goto out; } @@ -378,8 +403,11 @@ if (!file) goto bad_file; if (file->f_op && (file->f_mode & FMODE_READ) && - (file->f_op->readv || file->f_op->read)) - ret = do_readv_writev(VERIFY_WRITE, file, vector, count); + (file->f_op->readv || file->f_op->read)) { + ret = security_ops->file_permission (file, MAY_READ); + if (!ret) + ret = do_readv_writev(VERIFY_WRITE, file, vector, count); + } fput(file); bad_file: @@ -398,8 +426,11 @@ if (!file) goto bad_file; if (file->f_op && (file->f_mode & FMODE_WRITE) && - (file->f_op->writev || file->f_op->write)) - ret = do_readv_writev(VERIFY_READ, file, vector, count); + (file->f_op->writev || file->f_op->write)) { + ret = security_ops->file_permission (file, MAY_WRITE); + if (!ret) + ret = do_readv_writev(VERIFY_READ, file, vector, count); + } fput(file); bad_file: diff -Nru a/fs/readdir.c b/fs/readdir.c --- a/fs/readdir.c Fri Jul 26 19:58:51 2002 +++ b/fs/readdir.c Fri Jul 26 19:58:51 2002 @@ -20,6 +20,11 @@ int res = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; + + res = security_ops->file_permission(file, MAY_READ); + if (res) + goto out; + down(&inode->i_sem); res = -ENOENT; if (!IS_DEADDIR(inode)) { diff -Nru a/fs/stat.c b/fs/stat.c --- a/fs/stat.c Fri Jul 26 19:58:50 2002 +++ b/fs/stat.c Fri Jul 26 19:58:50 2002 @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -36,6 +37,11 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; + int retval; + + retval = security_ops->inode_getattr(mnt, dentry); + if (retval) + return retval; if (inode->i_op->getattr) return inode->i_op->getattr(mnt, dentry, stat); @@ -232,8 +238,11 @@ error = -EINVAL; if (inode->i_op && inode->i_op->readlink) { - UPDATE_ATIME(inode); - error = inode->i_op->readlink(nd.dentry, buf, bufsiz); + error = security_ops->inode_readlink(nd.dentry); + if (!error) { + UPDATE_ATIME(inode); + error = inode->i_op->readlink(nd.dentry, buf, bufsiz); + } } path_release(&nd); } diff -Nru a/fs/super.c b/fs/super.c --- a/fs/super.c Fri Jul 26 19:58:51 2002 +++ b/fs/super.c Fri Jul 26 19:58:51 2002 @@ -31,6 +31,8 @@ #include /* for fsync_super() */ #include +#include + void get_filesystem(struct file_system_type *fs); void put_filesystem(struct file_system_type *fs); struct file_system_type *get_fs_type(const char *name); @@ -49,6 +51,11 @@ struct super_block *s = kmalloc(sizeof(struct super_block), GFP_USER); if (s) { memset(s, 0, sizeof(struct super_block)); + if (security_ops->sb_alloc_security(s)) { + kfree(s); + s = NULL; + goto out; + } INIT_LIST_HEAD(&s->s_dirty); INIT_LIST_HEAD(&s->s_io); INIT_LIST_HEAD(&s->s_locked_inodes); @@ -67,6 +74,7 @@ s->dq_op = sb_dquot_ops; s->s_qcop = sb_quotactl_ops; } +out: return s; } @@ -78,6 +86,7 @@ */ static inline void destroy_super(struct super_block *s) { + security_ops->sb_free_security(s); kfree(s); } diff -Nru a/fs/xattr.c b/fs/xattr.c --- a/fs/xattr.c Fri Jul 26 19:58:51 2002 +++ b/fs/xattr.c Fri Jul 26 19:58:51 2002 @@ -85,11 +85,16 @@ error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { + error = security_ops->inode_setxattr(d, kname, kvalue, + size, flags); + if (error) + goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); up(&d->d_inode->i_sem); } +out: xattr_free(kvalue, size); return error; } @@ -158,6 +163,9 @@ error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { + error = security_ops->inode_getxattr(d, kname); + if (error) + goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); up(&d->d_inode->i_sem); @@ -166,6 +174,7 @@ if (kvalue && error > 0) if (copy_to_user(value, kvalue, error)) error = -EFAULT; +out: xattr_free(kvalue, size); return error; } @@ -227,6 +236,9 @@ error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { + error = security_ops->inode_listxattr(d); + if (error) + goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->listxattr(d, klist, size); up(&d->d_inode->i_sem); @@ -235,6 +247,7 @@ if (klist && error > 0) if (copy_to_user(list, klist, error)) error = -EFAULT; +out: xattr_free(klist, size); return error; } @@ -298,10 +311,14 @@ error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->removexattr) { + error = security_ops->inode_removexattr(d, kname); + if (error) + goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->removexattr(d, kname); up(&d->d_inode->i_sem); } +out: return error; } diff -Nru a/include/asm-generic/sections.h b/include/asm-generic/sections.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-generic/sections.h Fri Jul 26 19:58:52 2002 @@ -0,0 +1,11 @@ +#ifndef _ASM_GENERIC_SECTIONS_H_ +#define _ASM_GENERIC_SECTIONS_H_ + +/* References to section boundaries */ + +extern char _text, _etext; +extern char _data, _edata; +extern char __bss_start; +extern char __init_begin, __init_end; + +#endif /* _ASM_GENERIC_SECTIONS_H_ */ diff -Nru a/include/asm-i386/apic.h b/include/asm-i386/apic.h --- a/include/asm-i386/apic.h Fri Jul 26 19:58:52 2002 +++ b/include/asm-i386/apic.h Fri Jul 26 19:58:52 2002 @@ -76,7 +76,8 @@ extern void setup_local_APIC (void); extern void init_apic_mappings (void); extern void smp_local_timer_interrupt (struct pt_regs * regs); -extern void setup_APIC_clocks (void); +extern void setup_boot_APIC_clock (void); +extern void setup_secondary_APIC_clock (void); extern void setup_apic_nmi_watchdog (void); extern inline void nmi_watchdog_tick (struct pt_regs * regs); extern int APIC_init_uniprocessor (void); diff -Nru a/include/asm-i386/desc.h b/include/asm-i386/desc.h --- a/include/asm-i386/desc.h Fri Jul 26 19:58:50 2002 +++ b/include/asm-i386/desc.h Fri Jul 26 19:58:50 2002 @@ -4,72 +4,59 @@ #include /* - * The layout of the GDT under Linux: + * The layout of the per-CPU GDT under Linux: * * 0 - null - * 1 - not used + * 1 - Thread-Local Storage (TLS) segment * 2 - kernel code segment * 3 - kernel data segment - * 4 - user code segment <-- new cacheline + * 4 - user code segment <==== new cacheline * 5 - user data segment - * 6 - not used - * 7 - not used - * 8 - APM BIOS support <-- new cacheline + * 6 - TSS + * 7 - LDT + * 8 - APM BIOS support <==== new cacheline * 9 - APM BIOS support * 10 - APM BIOS support * 11 - APM BIOS support - * 12 - PNPBIOS support + * 12 - PNPBIOS support <==== new cacheline * 13 - PNPBIOS support * 14 - PNPBIOS support * 15 - PNPBIOS support - * 16 - PNPBIOS support + * 16 - PNPBIOS support <==== new cacheline * 17 - not used * 18 - not used * 19 - not used + */ +#define TLS_ENTRY 1 +#define TSS_ENTRY 6 +#define LDT_ENTRY 7 +/* + * The interrupt descriptor table has room for 256 idt's, + * the global descriptor table is dependent on the number + * of tasks we can have.. * - * The TSS+LDT descriptors are spread out a bit so that every CPU - * has an exclusive cacheline for the per-CPU TSS and LDT: - * - * 20 - CPU#0 TSS <-- new cacheline - * 21 - CPU#0 LDT - * 22 - not used - * 23 - not used - * 24 - CPU#1 TSS <-- new cacheline - * 25 - CPU#1 LDT - * 26 - not used - * 27 - not used - * ... NR_CPUS per-CPU TSS+LDT's if on SMP - * - * Entry into gdt where to find first TSS. + * We pad the GDT to cacheline boundary. */ -#define __FIRST_TSS_ENTRY 20 -#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1) - -#define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY) -#define __LDT(n) (((n)<<2) + __FIRST_LDT_ENTRY) +#define IDT_ENTRIES 256 +#define GDT_ENTRIES 20 #ifndef __ASSEMBLY__ #include -struct desc_struct { - unsigned long a,b; -}; +#define GDT_SIZE (GDT_ENTRIES*sizeof(struct desc_struct)) -extern struct desc_struct gdt_table[]; -extern struct desc_struct *idt, *gdt; +extern struct desc_struct cpu_gdt_table[NR_CPUS][GDT_ENTRIES]; struct Xgt_desc_struct { unsigned short size; unsigned long address __attribute__((packed)); -}; +} __attribute__ ((packed)); -#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2)) -#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2)) +extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS]; -#define load_TR(n) __asm__ __volatile__("ltr %%ax"::"a" (__TSS(n)<<3)) - -#define __load_LDT(n) __asm__ __volatile__("lldt %%ax"::"a" (__LDT(n)<<3)) +#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (TSS_ENTRY<<3)) +#define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (LDT_ENTRY<<3)) /* * This is the ldt that every process will get unless we need @@ -77,14 +64,43 @@ */ extern struct desc_struct default_ldt[]; extern void set_intr_gate(unsigned int irq, void * addr); -extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size); -extern void set_tss_desc(unsigned int n, void *addr); + +#define _set_tssldt_desc(n,addr,limit,type) \ +__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ + "movw %%ax,2(%2)\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,4(%2)\n\t" \ + "movb %4,5(%2)\n\t" \ + "movb $0,6(%2)\n\t" \ + "movb %%ah,7(%2)\n\t" \ + "rorl $16,%%eax" \ + : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) + +static inline void set_tss_desc(unsigned int cpu, void *addr) +{ + _set_tssldt_desc(&cpu_gdt_table[cpu][TSS_ENTRY], (int)addr, 235, 0x89); +} + +static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size) +{ + _set_tssldt_desc(&cpu_gdt_table[cpu][LDT_ENTRY], (int)addr, ((size << 3)-1), 0x82); +} + +#define TLS_FLAGS_MASK 0x00000007 + +#define TLS_FLAG_LIMIT_IN_PAGES 0x00000001 +#define TLS_FLAG_WRITABLE 0x00000002 +#define TLS_FLAG_CLEAR 0x00000004 + +static inline void load_TLS_desc(struct thread_struct *t, unsigned int cpu) +{ + cpu_gdt_table[cpu][TLS_ENTRY] = t->tls_desc; +} static inline void clear_LDT(void) { - int cpu = smp_processor_id(); - set_ldt_desc(cpu, &default_ldt[0], 5); - __load_LDT(cpu); + set_ldt_desc(smp_processor_id(), &default_ldt[0], 5); + load_LDT_desc(); } /* @@ -92,17 +108,16 @@ */ static inline void load_LDT (mm_context_t *pc) { - int cpu = smp_processor_id(); void *segments = pc->ldt; int count = pc->size; - if (!count) { + if (likely(!count)) { segments = &default_ldt[0]; count = 5; } - set_ldt_desc(cpu, segments, count); - __load_LDT(cpu); + set_ldt_desc(smp_processor_id(), segments, count); + load_LDT_desc(); } #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h --- a/include/asm-i386/mmu_context.h Fri Jul 26 19:58:50 2002 +++ b/include/asm-i386/mmu_context.h Fri Jul 26 19:58:50 2002 @@ -17,7 +17,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { - if(cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (cpu_tlbstate[cpu].state == TLBSTATE_OK) cpu_tlbstate[cpu].state = TLBSTATE_LAZY; } #else @@ -40,18 +40,18 @@ /* Re-load page tables */ load_cr3(next->pgd); - /* load_LDT, if either the previous or next thread - * has a non-default LDT. + /* + * load the LDT, if the LDT is different: */ - if (next->context.size+prev->context.size) + if (unlikely(prev->context.ldt != next->context.ldt)) load_LDT(&next->context); } #ifdef CONFIG_SMP else { cpu_tlbstate[cpu].state = TLBSTATE_OK; - if(cpu_tlbstate[cpu].active_mm != next) + if (cpu_tlbstate[cpu].active_mm != next) BUG(); - if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) { + if (!test_and_set_bit(cpu, &next->cpu_vm_mask)) { /* We were in lazy tlb mode and leave_mm disabled * tlb flush IPI delivery. We must reload %cr3. */ diff -Nru a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h --- a/include/asm-i386/pgtable-3level.h Fri Jul 26 19:58:52 2002 +++ b/include/asm-i386/pgtable-3level.h Fri Jul 26 19:58:52 2002 @@ -106,4 +106,6 @@ return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); } +extern struct kmem_cache_s *pae_pgd_cachep; + #endif /* _I386_PGTABLE_3LEVEL_H */ diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h --- a/include/asm-i386/processor.h Fri Jul 26 19:58:50 2002 +++ b/include/asm-i386/processor.h Fri Jul 26 19:58:50 2002 @@ -18,6 +18,10 @@ #include #include +struct desc_struct { + unsigned long a,b; +}; + /* * Default implementation of macro that returns current * instruction pointer ("program counter"). @@ -372,6 +376,9 @@ unsigned long v86flags, v86mask, v86mode, saved_esp0; /* IO permissions */ unsigned long *ts_io_bitmap; +/* TLS info and cached descriptor */ + unsigned int tls_base, tls_limit, tls_flags; + struct desc_struct tls_desc; }; #define INIT_THREAD { \ @@ -395,7 +402,7 @@ 0,0,0,0, /* esp,ebp,esi,edi */ \ 0,0,0,0,0,0, /* es,cs,ss */ \ 0,0,0,0,0,0, /* ds,fs,gs */ \ - __LDT(0),0, /* ldt */ \ + LDT_ENTRY,0, /* ldt */ \ 0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */ \ {~0, } /* ioperm */ \ } diff -Nru a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h --- a/include/asm-i386/rwsem.h Fri Jul 26 19:58:51 2002 +++ b/include/asm-i386/rwsem.h Fri Jul 26 19:58:51 2002 @@ -46,6 +46,7 @@ extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem)); extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem)); extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *)); +extern struct rw_semaphore *FASTCALL(rwsem_downgrade_write(struct rw_semaphore *sem)); /* * the semaphore definition @@ -193,6 +194,31 @@ : "=m"(sem->count) : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count) : "memory", "cc", "edx"); +} + +/* + * downgrade write lock to read lock + */ +static inline void __downgrade_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning __downgrade_write\n\t" +LOCK_PREFIX " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + LOCK_SECTION_START("") + "2:\n\t" + " pushl %%ecx\n\t" + " pushl %%edx\n\t" + " call rwsem_downgrade_wake\n\t" + " popl %%edx\n\t" + " popl %%ecx\n\t" + " jmp 1b\n" + LOCK_SECTION_END + "# ending __downgrade_write\n" + : "=m"(sem->count) + : "a"(sem), "i"(-RWSEM_WAITING_BIAS), "m"(sem->count) + : "memory", "cc"); } /* diff -Nru a/include/asm-i386/sections.h b/include/asm-i386/sections.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/sections.h Fri Jul 26 19:58:52 2002 @@ -0,0 +1,7 @@ +#ifndef _I386_SECTIONS_H +#define _I386_SECTIONS_H + +/* nothing to see, move along */ +#include + +#endif diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h --- a/include/asm-i386/smp.h Fri Jul 26 19:58:50 2002 +++ b/include/asm-i386/smp.h Fri Jul 26 19:58:50 2002 @@ -79,19 +79,13 @@ extern volatile int logical_apicid_to_cpu[MAX_APICID]; /* - * General functions that each host system must provide. - */ - -extern void smp_boot_cpus(void); -extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial udelay numbers */ - -/* * This function is needed by all SMP systems. It must _always_ be valid * from the initial startup. We map APIC_BASE very early in page_setup(), * so this is correct in the x86 case. */ #define smp_processor_id() (current_thread_info()->cpu) +#define cpu_possible(cpu) (phys_cpu_present_map & (1<<(cpu))) #define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) extern inline unsigned int num_online_cpus(void) @@ -117,6 +111,13 @@ { /* we don't want to mark this access volatile - bad code generation */ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR)); +} + +extern volatile unsigned long cpu_callout_map; +/* We don't mark CPUs online until __cpu_up(), so we need another measure */ +static inline int num_booting_cpus(void) +{ + return hweight32(cpu_callout_map); } #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h --- a/include/asm-ppc/keyboard.h Fri Jul 26 19:58:52 2002 +++ b/include/asm-ppc/keyboard.h Fri Jul 26 19:58:52 2002 @@ -25,10 +25,6 @@ #include #include #include -/* IBM Spruce platform is different. */ -#ifdef CONFIG_SPRUCE -#include -#endif #ifndef KEYBOARD_IRQ #define KEYBOARD_IRQ 1 diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h --- a/include/asm-ppc/machdep.h Fri Jul 26 19:58:51 2002 +++ b/include/asm-ppc/machdep.h Fri Jul 26 19:58:51 2002 @@ -6,6 +6,7 @@ #define _PPC_MACHDEP_H #include +#include #ifdef CONFIG_APUS #include @@ -129,7 +130,14 @@ int (*probe)(void); void (*kick_cpu)(int nr); void (*setup_cpu)(int nr); + void (*space_timers)(int nr); + void (*take_timebase)(void); + void (*give_timebase)(void); }; + +/* Poor default implementations */ +extern void __devinit smp_generic_give_timebase(void); +extern void __devinit smp_generic_take_timebase(void); #endif /* CONFIG_SMP */ #endif /* _PPC_MACHDEP_H */ diff -Nru a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h --- a/include/asm-ppc/smp.h Fri Jul 26 19:58:50 2002 +++ b/include/asm-ppc/smp.h Fri Jul 26 19:58:50 2002 @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef CONFIG_SMP @@ -31,11 +32,11 @@ extern struct cpuinfo_PPC cpu_data[]; extern unsigned long cpu_online_map; +extern unsigned long cpu_possible_map; extern unsigned long smp_proc_in_lock[]; extern volatile unsigned long cpu_callin_map[]; extern int smp_tb_synchronized; -extern void smp_store_cpu_info(int id); extern void smp_send_tlb_invalidate(int); extern void smp_send_xmon_break(int cpu); struct pt_regs; @@ -48,6 +49,7 @@ #define smp_processor_id() (current_thread_info()->cpu) #define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) +#define cpu_possible(cpu) (cpu_possible_map & (1<<(cpu))) extern inline unsigned int num_online_cpus(void) { @@ -61,6 +63,8 @@ return -1; } + +extern int __cpu_up(unsigned int cpu); extern int smp_hw_index[]; #define hard_smp_processor_id() (smp_hw_index[smp_processor_id()]) diff -Nru a/include/asm-s390/hdreg.h b/include/asm-s390/hdreg.h --- a/include/asm-s390/hdreg.h Fri Jul 26 19:58:52 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* - * linux/include/asm-arm/hdreg.h - * - * Copyright (C) 1994-1996 Linus Torvalds & authors - */ - -#ifndef __ASMS390_HDREG_H -#define __ASMS390_HDREG_H - -typedef unsigned long ide_ioreg_t; - -#endif /* __ASMS390_HDREG_H */ - diff -Nru a/include/asm-s390/ide.h b/include/asm-s390/ide.h --- a/include/asm-s390/ide.h Fri Jul 26 19:58:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,27 +0,0 @@ -/* - * linux/include/asm-s390/ide.h - * - * Copyright (C) 1994-1996 Linus Torvalds & authors - */ - -/* s390 does not have IDE */ - -#ifndef __ASMS390_IDE_H -#define __ASMS390_IDE_H - -#ifdef __KERNEL__ - -#ifndef MAX_HWIFS -#define MAX_HWIFS 0 -#endif - -/* - * We always use the new IDE port registering, - * so these are fixed here. - */ -#define ide_default_io_base(i) ((ide_ioreg_t)0) -#define ide_default_irq(b) (0) - -#endif /* __KERNEL__ */ - -#endif /* __ASMS390_IDE_H */ diff -Nru a/include/asm-s390x/hdreg.h b/include/asm-s390x/hdreg.h --- a/include/asm-s390x/hdreg.h Fri Jul 26 19:58:52 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* - * linux/include/asm-arm/hdreg.h - * - * Copyright (C) 1994-1996 Linus Torvalds & authors - */ - -#ifndef __ASMS390_HDREG_H -#define __ASMS390_HDREG_H - -typedef unsigned long ide_ioreg_t; - -#endif /* __ASMS390_HDREG_H */ - diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/blkdev.h Fri Jul 26 19:58:51 2002 @@ -281,12 +281,13 @@ extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); extern void generic_make_request(struct bio *bio); extern inline request_queue_t *bdev_get_queue(struct block_device *bdev); -extern void blkdev_release_request(struct request *); +extern void blk_put_request(struct request *); extern void blk_attempt_remerge(request_queue_t *, struct request *); extern void __blk_attempt_remerge(request_queue_t *, struct request *); extern struct request *blk_get_request(request_queue_t *, int, int); extern struct request *__blk_get_request(request_queue_t *, int); extern void blk_put_request(struct request *); +extern void blk_insert_request(request_queue_t *, struct request *, int, void *); extern void blk_plug_device(request_queue_t *); extern int blk_remove_plug(request_queue_t *); extern void blk_recount_segments(request_queue_t *, struct bio *); @@ -309,20 +310,21 @@ extern void blk_cleanup_queue(request_queue_t *); extern void blk_queue_make_request(request_queue_t *, make_request_fn *); extern void blk_queue_bounce_limit(request_queue_t *, u64); -extern void blk_queue_max_sectors(request_queue_t *q, unsigned short); -extern void blk_queue_max_phys_segments(request_queue_t *q, unsigned short); -extern void blk_queue_max_hw_segments(request_queue_t *q, unsigned short); -extern void blk_queue_max_segment_size(request_queue_t *q, unsigned int); -extern void blk_queue_hardsect_size(request_queue_t *q, unsigned short); -extern void blk_queue_segment_boundary(request_queue_t *q, unsigned long); -extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *); -extern void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn); +extern void blk_queue_max_sectors(request_queue_t *, unsigned short); +extern void blk_queue_max_phys_segments(request_queue_t *, unsigned short); +extern void blk_queue_max_hw_segments(request_queue_t *, unsigned short); +extern void blk_queue_max_segment_size(request_queue_t *, unsigned int); +extern void blk_queue_hardsect_size(request_queue_t *, unsigned short); +extern void blk_queue_segment_boundary(request_queue_t *, unsigned long); +extern void blk_queue_assign_lock(request_queue_t *, spinlock_t *); +extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *); extern void blk_dump_rq_flags(struct request *, char *); extern void generic_unplug_device(void *); + /* * tag stuff */ @@ -348,15 +350,12 @@ extern void drive_stat_acct(struct request *, int, int); -extern inline void blk_clear(int major) +static inline void blk_clear(int major) { blk_size[major] = NULL; -#if 0 - blk_size_in_bytes[major] = NULL; -#endif } -extern inline int queue_hardsect_size(request_queue_t *q) +static inline int queue_hardsect_size(request_queue_t *q) { int retval = 512; @@ -366,7 +365,7 @@ return retval; } -extern inline int bdev_hardsect_size(struct block_device *bdev) +static inline int bdev_hardsect_size(struct block_device *bdev) { return queue_hardsect_size(bdev_get_queue(bdev)); } @@ -375,7 +374,7 @@ #define blk_started_io(nsects) do { } while (0) /* assumes size > 256 */ -extern inline unsigned int blksize_bits(unsigned int size) +static inline unsigned int blksize_bits(unsigned int size) { unsigned int bits = 8; do { diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/fs.h Fri Jul 26 19:58:51 2002 @@ -72,6 +72,7 @@ #define MAY_EXEC 1 #define MAY_WRITE 2 #define MAY_READ 4 +#define MAY_APPEND 8 #define FMODE_READ 1 #define FMODE_WRITE 2 @@ -399,6 +400,7 @@ unsigned char i_sock; atomic_t i_writecount; + void *i_security; __u32 i_generation; union { void *generic_ip; @@ -429,6 +431,7 @@ int pid; /* pid or -pgrp where SIGIO should be sent */ uid_t uid, euid; /* uid/euid of process setting the owner */ int signum; /* posix.1b rt signal to be delivered on IO */ + void *security; }; static inline void inode_add_bytes(struct inode *inode, loff_t bytes) @@ -492,6 +495,7 @@ struct file_ra_state f_ra; unsigned long f_version; + void *f_security; /* needed for tty driver, and maybe others */ void *private_data; @@ -645,6 +649,7 @@ int s_count; int s_syncing; atomic_t s_active; + void *s_security; struct list_head s_dirty; /* dirty inodes */ struct list_head s_io; /* parked for writeback */ diff -Nru a/include/linux/gameport.h b/include/linux/gameport.h --- a/include/linux/gameport.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/gameport.h Fri Jul 26 19:58:51 2002 @@ -39,10 +39,7 @@ char *name; char *phys; - unsigned short idbus; - unsigned short idvendor; - unsigned short idproduct; - unsigned short idversion; + struct input_id id; int io; int speed; diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h --- a/include/linux/hdreg.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/hdreg.h Fri Jul 26 19:58:51 2002 @@ -261,17 +261,17 @@ #define SECURITY_DISABLE_PASSWORD 0xBF struct hd_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; + u8 heads; + u8 sectors; + u16 cylinders; unsigned long start; }; /* BIG GEOMETRY - dying, used only by HDIO_GETGEO_BIG_RAW */ struct hd_big_geometry { - unsigned char heads; - unsigned char sectors; - unsigned int cylinders; + u8 heads; + u8 sectors; + u32 cylinders; unsigned long start; }; @@ -326,249 +326,243 @@ * ide/probe.c. */ struct hd_driveid { - unsigned short config; /* lots of obsolete bit flags */ - unsigned short cyls; /* Obsolete, "physical" cyls */ - unsigned short reserved2; /* reserved (word 2) */ - unsigned short heads; /* Obsolete, "physical" heads */ - unsigned short track_bytes; /* unformatted bytes per track */ - unsigned short sector_bytes; /* unformatted bytes per sector */ - unsigned short sectors; /* Obsolete, "physical" sectors per track */ - unsigned short vendor0; /* vendor unique */ - unsigned short vendor1; /* vendor unique */ - unsigned short vendor2; /* Retired vendor unique */ - unsigned char serial_no[20]; /* 0 = not_specified */ - unsigned short buf_type; /* Retired */ - unsigned short buf_size; /* Retired, 512 byte increments - * 0 = not_specified - */ - unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */ - unsigned char fw_rev[8]; /* 0 = not_specified */ - unsigned char model[40]; /* 0 = not_specified */ - unsigned char max_multsect; /* 0=not_implemented */ - unsigned char vendor3; /* vendor unique */ - unsigned short dword_io; /* 0=not_implemented; 1=implemented */ - unsigned char vendor4; /* vendor unique */ - unsigned char capability; /* (upper byte of word 49) - * 3: IORDYsup - * 2: IORDYsw - * 1: LBA - * 0: DMA - */ - unsigned short reserved50; /* reserved (word 50) */ - unsigned char vendor5; /* Obsolete, vendor unique */ - unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ - unsigned char vendor6; /* Obsolete, vendor unique */ - unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ - unsigned short field_valid; /* (word 53) - * 2: ultra_ok word 88 - * 1: eide_ok words 64-70 - * 0: cur_ok words 54-58 - */ - unsigned short cur_cyls; /* Obsolete, logical cylinders */ - unsigned short cur_heads; /* Obsolete, l heads */ - unsigned short cur_sectors; /* Obsolete, l sectors per track */ - unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */ - unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */ - unsigned char multsect; /* current multiple sector count */ - unsigned char multsect_valid; /* when (bit0==1) multsect is ok */ - unsigned int lba_capacity; /* Obsolete, total number of sectors */ - unsigned short dma_1word; /* Obsolete, single-word dma info */ - unsigned short dma_mword; /* multiple-word dma info */ - unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ - unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ - unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ - unsigned short eide_pio; /* min cycle time (ns), no IORDY */ - unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ - unsigned short words69_70[2]; /* reserved words 69-70 - * future command overlap and queuing - */ + u16 config; /* lots of obsolete bit flags */ + u16 cyls; /* Obsolete, "physical" cyls */ + u16 reserved2; /* reserved (word 2) */ + u16 heads; /* Obsolete, "physical" heads */ + u16 track_bytes; /* unformatted bytes per track */ + u16 sector_bytes; /* unformatted bytes per sector */ + u16 sectors; /* Obsolete, "physical" sectors per track */ + u16 vendor0; /* vendor unique */ + u16 vendor1; /* vendor unique */ + u16 vendor2; /* Retired vendor unique */ + u8 serial_no[20]; /* 0 = not_specified */ + u16 buf_type; /* Retired */ + u16 buf_size; /* Retired, 512 byte increments + * 0 = not_specified + */ + u16 ecc_bytes; /* for r/w long cmds; 0 = not_specified */ + u8 fw_rev[8]; /* 0 = not_specified */ + char model[40]; /* 0 = not_specified */ + u8 max_multsect; /* 0=not_implemented */ + u8 vendor3; /* vendor unique */ + u16 dword_io; /* 0=not_implemented; 1=implemented */ + u8 vendor4; /* vendor unique */ + u8 capability; /* (upper byte of word 49) + * 3: IORDYsup + * 2: IORDYsw + * 1: LBA + * 0: DMA + */ + u16 reserved50; /* reserved (word 50) */ + u8 vendor5; /* Obsolete, vendor unique */ + u8 tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ + u8 vendor6; /* Obsolete, vendor unique */ + u8 tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ + u16 field_valid; /* (word 53) + * 2: ultra_ok word 88 + * 1: eide_ok words 64-70 + * 0: cur_ok words 54-58 + */ + u16 cur_cyls; /* Obsolete, logical cylinders */ + u16 cur_heads; /* Obsolete, l heads */ + u16 cur_sectors; /* Obsolete, l sectors per track */ + u16 cur_capacity0; /* Obsolete, l total sectors on drive */ + u16 cur_capacity1; /* Obsolete, (2 words, misaligned int) */ + u8 multsect; /* current multiple sector count */ + u8 multsect_valid; /* when (bit0==1) multsect is ok */ + u32 lba_capacity; /* Obsolete, total number of sectors */ + u16 dma_1word; /* Obsolete, single-word dma info */ + u16 dma_mword; /* multiple-word dma info */ + u16 eide_pio_modes; /* bits 0:mode3 1:mode4 */ + u16 eide_dma_min; /* min mword dma cycle time (ns) */ + u16 eide_dma_time; /* recommended mword dma cycle time (ns) */ + u16 eide_pio; /* min cycle time (ns), no IORDY */ + u16 eide_pio_iordy; /* min cycle time (ns), with IORDY */ + u16 words69_70[2]; /* reserved words 69-70 + * future command overlap and queuing + */ /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ - unsigned short words71_74[4]; /* reserved words 71-74 - * for IDENTIFY PACKET DEVICE command - */ - unsigned short queue_depth; /* (word 75) - * 15:5 reserved - * 4:0 Maximum queue depth -1 - */ - unsigned short words76_79[4]; /* reserved words 76-79 */ - unsigned short major_rev_num; /* (word 80) */ - unsigned short minor_rev_num; /* (word 81) */ - unsigned short command_set_1; /* (word 82) supported - * 15: Obsolete - * 14: NOP command - * 13: READ_BUFFER - * 12: WRITE_BUFFER - * 11: Obsolete - * 10: Host Protected Area - * 9: DEVICE Reset - * 8: SERVICE Interrupt - * 7: Release Interrupt - * 6: look-ahead - * 5: write cache - * 4: PACKET Command - * 3: Power Management Feature Set - * 2: Removable Feature Set - * 1: Security Feature Set - * 0: SMART Feature Set - */ - unsigned short command_set_2; /* (word 83) - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: FLUSH CACHE EXT - * 12: FLUSH CACHE - * 11: Device Configuration Overlay - * 10: 48-bit Address Feature Set - * 9: Automatic Acoustic Management - * 8: SET MAX security - * 7: reserved 1407DT PARTIES - * 6: SetF sub-command Power-Up - * 5: Power-Up in Standby Feature Set - * 4: Removable Media Notification - * 3: APM Feature Set - * 2: CFA Feature Set - * 1: READ/WRITE DMA QUEUED - * 0: Download MicroCode - */ - unsigned short cfsse; /* (word 84) - * cmd set-feature supported extensions - * 15: Shall be ZERO - * 14: Shall be ONE - * 13:3 reserved - * 2: Media Serial Number Valid - * 1: SMART selt-test supported - * 0: SMART error logging - */ - unsigned short cfs_enable_1; /* (word 85) - * command set-feature enabled - * 15: Obsolete - * 14: NOP command - * 13: READ_BUFFER - * 12: WRITE_BUFFER - * 11: Obsolete - * 10: Host Protected Area - * 9: DEVICE Reset - * 8: SERVICE Interrupt - * 7: Release Interrupt - * 6: look-ahead - * 5: write cache - * 4: PACKET Command - * 3: Power Management Feature Set - * 2: Removable Feature Set - * 1: Security Feature Set - * 0: SMART Feature Set - */ - unsigned short cfs_enable_2; /* (word 86) - * command set-feature enabled - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: FLUSH CACHE EXT - * 12: FLUSH CACHE - * 11: Device Configuration Overlay - * 10: 48-bit Address Feature Set - * 9: Automatic Acoustic Management - * 8: SET MAX security - * 7: reserved 1407DT PARTIES - * 6: SetF sub-command Power-Up - * 5: Power-Up in Standby Feature Set - * 4: Removable Media Notification - * 3: APM Feature Set - * 2: CFA Feature Set - * 1: READ/WRITE DMA QUEUED - * 0: Download MicroCode - */ - unsigned short csf_default; /* (word 87) - * command set-feature default - * 15: Shall be ZERO - * 14: Shall be ONE - * 13:3 reserved - * 2: Media Serial Number Valid - * 1: SMART selt-test supported - * 0: SMART error logging - */ - unsigned short dma_ultra; /* (word 88) */ - unsigned short word89; /* reserved (word 89) */ - unsigned short word90; /* reserved (word 90) */ - unsigned short CurAPMvalues; /* current APM values */ - unsigned short word92; /* reserved (word 92) */ - unsigned short hw_config; /* hardware config (word 93) - * 15: - * 14: - * 13: - * 12: - * 11: - * 10: - * 9: - * 8: - * 7: - * 6: - * 5: - * 4: - * 3: - * 2: - * 1: - * 0: - */ - unsigned short acoustic; /* (word 94) - * 15:8 Vendor's recommended value - * 7:0 current value - */ - unsigned short words95_99[5]; /* reserved words 95-99 */ - unsigned long long lba_capacity_2;/* 48-bit total number of sectors */ - unsigned short words104_125[22];/* reserved words 104-125 */ - unsigned short last_lun; /* (word 126) */ - unsigned short word127; /* (word 127) Feature Set - * Removable Media Notification - * 15:2 reserved - * 1:0 00 = not supported - * 01 = supported - * 10 = reserved - * 11 = reserved - */ - unsigned short dlf; /* (word 128) - * device lock function - * 15:9 reserved - * 8 security level 1:max 0:high - * 7:6 reserved - * 5 enhanced erase - * 4 expire - * 3 frozen - * 2 locked - * 1 en/disabled - * 0 capability - */ - unsigned short csfo; /* (word 129) - * current set features options - * 15:4 reserved - * 3: auto reassign - * 2: reverting - * 1: read-look-ahead - * 0: write cache - */ - unsigned short words130_155[26];/* reserved vendor words 130-155 */ - unsigned short word156; /* reserved vendor word 156 */ - unsigned short words157_159[3];/* reserved vendor words 157-159 */ - unsigned short cfa_power; /* (word 160) CFA Power Mode - * 15 word 160 supported - * 14 reserved - * 13 - * 12 - * 11:0 - */ - unsigned short words161_175[14];/* Reserved for CFA */ - unsigned short words176_205[31];/* Current Media Serial Number */ - unsigned short words206_254[48];/* reserved words 206-254 */ - unsigned short integrity_word; /* (word 255) - * 15:8 Checksum - * 7:0 Signature - */ + u16 words71_74[4]; /* reserved words 71-74 + * for IDENTIFY PACKET DEVICE command + */ + u16 queue_depth; /* (word 75) + * 15:5 reserved + * 4:0 Maximum queue depth -1 + */ + u16 words76_79[4]; /* reserved words 76-79 */ + u16 major_rev_num; /* (word 80) */ + u16 minor_rev_num; /* (word 81) */ + u16 command_set_1; /* (word 82) supported + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + u16 command_set_2; /* (word 83) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + u16 cfsse; /* (word 84) + * cmd set-feature supported extensions + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:3 reserved + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + u16 cfs_enable_1; /* (word 85) + * command set-feature enabled + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + u16 cfs_enable_2; /* (word 86) + * command set-feature enabled + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + u16 csf_default; /* (word 87) + * command set-feature default + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:3 reserved + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + u16 dma_ultra; /* (word 88) */ + u16 word89; /* reserved (word 89) */ + u16 word90; /* reserved (word 90) */ + u16 CurAPMvalues; /* current APM values */ + u16 word92; /* reserved (word 92) */ + u16 hw_config; /* hardware config (word 93) + * 15: + * 14: + * 13: + * 12: + * 11: + * 10: + * 9: + * 8: + * 7: + * 6: + * 5: + * 4: + * 3: + * 2: + * 1: + * 0: + */ + u16 acoustic; /* (word 94) + * 15:8 Vendor's recommended value + * 7:0 current value + */ + u16 words95_99[5]; /* reserved words 95-99 */ + u64 lba_capacity_2; /* 48-bit total number of sectors */ + u16 words104_125[22];/* reserved words 104-125 */ + u16 last_lun; /* (word 126) */ + u16 word127; /* (word 127) Feature Set + * Removable Media Notification + * 15:2 reserved + * 1:0 00 = not supported + * 01 = supported + * 10 = reserved + * 11 = reserved + */ + u16 dlf; /* (word 128) + * device lock function + * 15:9 reserved + * 8 security level 1:max 0:high + * 7:6 reserved + * 5 enhanced erase + * 4 expire + * 3 frozen + * 2 locked + * 1 en/disabled + * 0 capability + */ + u16 csfo; /* (word 129) + * current set features options + * 15:4 reserved + * 3: auto reassign + * 2: reverting + * 1: read-look-ahead + * 0: write cache + */ + u16 words130_155[26];/* reserved vendor words 130-155 */ + u16 word156; /* reserved vendor word 156 */ + u16 words157_159[3];/* reserved vendor words 157-159 */ + u16 cfa_power; /* (word 160) CFA Power Mode + * 15 word 160 supported + * 14 reserved + * 13 + * 12 + * 11:0 + */ + u16 words161_175[14];/* Reserved for CFA */ + u16 words176_205[31];/* Current Media Serial Number */ + u16 words206_254[48];/* reserved words 206-254 */ + u16 integrity_word; /* (word 255) + * 15:8 Checksum + * 7:0 Signature + */ } __attribute__((packed)); -/* - * IDE "nice" flags. These are used on a per drive basis to determine - * when to be nice and give more bandwidth to the other devices which - * share the same IDE bus. - */ #define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */ -#define IDE_NICE_ATAPI_OVERLAP (1) /* not supported yet */ -#endif /* _LINUX_HDREG_H */ +#endif diff -Nru a/include/linux/i2o.h b/include/linux/i2o.h --- a/include/linux/i2o.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/i2o.h Fri Jul 26 19:58:51 2002 @@ -81,9 +81,9 @@ struct i2o_pci { int irq; - int queue_buggy:3; /* Don't send a lot of messages */ int short_req:1; /* Use small block sizes */ int dpt:1; /* Don't quiesce */ + int promise:1; /* Promise controller */ #ifdef CONFIG_MTRR int mtrr_reg0; int mtrr_reg1; @@ -112,9 +112,9 @@ atomic_t users; struct i2o_device *devices; /* I2O device chain */ struct i2o_controller *next; /* Controller chain */ - volatile u32 *post_port; /* Inbout port */ - volatile u32 *reply_port; /* Outbound port */ - volatile u32 *irq_mask; /* Interrupt register */ + unsigned long post_port; /* Inbout port address */ + unsigned long reply_port; /* Outbound port address */ + unsigned long irq_mask; /* Interrupt register address */ /* Dynamic LCT related data */ struct semaphore lct_sem; @@ -122,12 +122,17 @@ int lct_running; i2o_status_block *status_block; /* IOP status block */ + dma_addr_t status_block_phys; i2o_lct *lct; /* Logical Config Table */ + dma_addr_t lct_phys; i2o_lct *dlct; /* Temp LCT */ + dma_addr_t dlct_phys; i2o_hrt *hrt; /* HW Resource Table */ + dma_addr_t hrt_phys; + u32 hrt_len; - u32 mem_offset; /* MFA offset */ - u32 mem_phys; /* MFA physical */ + unsigned long mem_offset; /* MFA offset */ + unsigned long mem_phys; /* MFA physical */ int battery:1; /* Has a battery backup */ int io_alloc:1; /* An I/O resource was allocated */ @@ -252,34 +257,34 @@ */ static inline u32 I2O_POST_READ32(struct i2o_controller *c) { - return *c->post_port; + return readl(c->post_port); } -static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val) +static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 val) { - *c->post_port = Val; + writel(val, c->post_port); } static inline u32 I2O_REPLY_READ32(struct i2o_controller *c) { - return *c->reply_port; + return readl(c->reply_port); } -static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val) +static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 val) { - *c->reply_port = Val; + writel(val, c->reply_port); } static inline u32 I2O_IRQ_READ32(struct i2o_controller *c) { - return *c->irq_mask; + return readl(c->irq_mask); } -static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val) +static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 val) { - *c->irq_mask = Val; + writel(val, c->irq_mask); } @@ -295,6 +300,13 @@ I2O_REPLY_WRITE32(c, m); } +/* + * Endian handling wrapped into the macro - keeps the core code + * cleaner. + */ + +#define i2o_raw_writel(val, mem) __raw_writel(cpu_to_le32(val), mem) + extern struct i2o_controller *i2o_find_controller(int); extern void i2o_unlock_controller(struct i2o_controller *); extern struct i2o_controller *i2o_controller_chain; @@ -313,7 +325,7 @@ extern int i2o_post_this(struct i2o_controller *, u32 *, int); extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int); extern int i2o_post_wait_mem(struct i2o_controller *, u32 *, int, int, - void *, void *); + void *, void *, dma_addr_t, dma_addr_t, int, int); extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int); @@ -339,13 +351,66 @@ extern void i2o_run_queue(struct i2o_controller *); extern int i2o_delete_controller(struct i2o_controller *); +/* + * Cache strategies + */ + + +/* The NULL strategy leaves everything up to the controller. This tends to be a + * pessimal but functional choice. + */ +#define CACHE_NULL 0 +/* Prefetch data when reading. We continually attempt to load the next 32 sectors + * into the controller cache. + */ +#define CACHE_PREFETCH 1 +/* Prefetch data when reading. We sometimes attempt to load the next 32 sectors + * into the controller cache. When an I/O is less <= 8K we assume its probably + * not sequential and don't prefetch (default) + */ +#define CACHE_SMARTFETCH 2 +/* Data is written to the cache and then out on to the disk. The I/O must be + * physically on the medium before the write is acknowledged (default without + * NVRAM) + */ +#define CACHE_WRITETHROUGH 17 +/* Data is written to the cache and then out on to the disk. The controller + * is permitted to write back the cache any way it wants. (default if battery + * backed NVRAM is present). It can be useful to set this for swap regardless of + * battery state. + */ +#define CACHE_WRITEBACK 18 +/* Optimise for under powered controllers, especially on RAID1 and RAID0. We + * write large I/O's directly to disk bypassing the cache to avoid the extra + * memory copy hits. Small writes are writeback cached + */ +#define CACHE_SMARTBACK 19 +/* Optimise for under powered controllers, especially on RAID1 and RAID0. We + * write large I/O's directly to disk bypassing the cache to avoid the extra + * memory copy hits. Small writes are writethrough cached. Suitable for devices + * lacking battery backup + */ +#define CACHE_SMARTTHROUGH 20 + +/* + * Ioctl structures + */ + + +#define BLKI2OGRSTRAT _IOR('2', 1, int) +#define BLKI2OGWSTRAT _IOR('2', 2, int) +#define BLKI2OSRSTRAT _IOW('2', 3, int) +#define BLKI2OSWSTRAT _IOW('2', 4, int) + + + /* - * I2O Function codes + * I2O Function codes */ /* - * Executive Class + * Executive Class */ #define I2O_CMD_ADAPTER_ASSIGN 0xB3 #define I2O_CMD_ADAPTER_READ 0xB2 @@ -416,6 +481,7 @@ #define I2O_CMD_BLOCK_MUNLOCK 0x4B #define I2O_CMD_BLOCK_MMOUNT 0x41 #define I2O_CMD_BLOCK_MEJECT 0x43 +#define I2O_CMD_BLOCK_POWER 0x70 #define I2O_PRIVATE_MSG 0xFF @@ -574,6 +640,7 @@ #define EIGHT_WORD_MSG_SIZE 0x00080000 #define NINE_WORD_MSG_SIZE 0x00090000 #define TEN_WORD_MSG_SIZE 0x000A0000 +#define ELEVEN_WORD_MSG_SIZE 0x000B0000 #define I2O_MESSAGE_SIZE(x) ((x)<<16) @@ -582,10 +649,10 @@ #define ADAPTER_TID 0 #define HOST_TID 1 -#define MSG_FRAME_SIZE 128 +#define MSG_FRAME_SIZE 64 /* i2o_scsi assumes >= 32 */ #define NMBR_MSG_FRAMES 128 -#define MSG_POOL_SIZE 16384 +#define MSG_POOL_SIZE (MSG_FRAME_SIZE*NMBR_MSG_FRAMES*sizeof(u32)) #define I2O_POST_WAIT_OK 0 #define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT diff -Nru a/include/linux/ide.h b/include/linux/ide.h --- a/include/linux/ide.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/ide.h Fri Jul 26 19:58:50 2002 @@ -285,8 +285,8 @@ unsigned long sleep; /* sleep until this time */ - byte retry_pio; /* retrying dma capable host in pio */ - byte state; /* retry state */ + u8 retry_pio; /* retrying dma capable host in pio */ + u8 state; /* retry state */ unsigned using_dma : 1; /* disk is using dma for read/write */ unsigned using_tcq : 1; /* disk is using queueing */ @@ -307,20 +307,20 @@ unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */ unsigned ata_flash : 1; /* 1=present, 0=default */ unsigned addressing; /* : 2; 0=28-bit, 1=48-bit, 2=64-bit */ - byte scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */ + u8 scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */ select_t select; /* basic drive/head select reg value */ u8 status; /* last retrived status value for device */ - byte ready_stat; /* min status value for drive ready */ - byte mult_count; /* current multiple sector setting */ - byte bad_wstat; /* used for ignoring WRERR_STAT */ - byte nowerr; /* used for ignoring WRERR_STAT */ - byte sect0; /* offset of first sector for DM6:DDO */ - byte head; /* "real" number of heads */ - byte sect; /* "real" sectors per track */ - byte bios_head; /* BIOS/fdisk/LILO number of heads */ - byte bios_sect; /* BIOS/fdisk/LILO sectors per track */ + u8 ready_stat; /* min status value for drive ready */ + u8 mult_count; /* current multiple sector setting */ + u8 bad_wstat; /* used for ignoring WRERR_STAT */ + u8 nowerr; /* used for ignoring WRERR_STAT */ + u8 sect0; /* offset of first sector for DM6:DDO */ + u8 head; /* "real" number of heads */ + u8 sect; /* "real" sectors per track */ + u8 bios_head; /* BIOS/fdisk/LILO number of heads */ + u8 bios_sect; /* BIOS/fdisk/LILO sectors per track */ unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ u64 capacity; /* total number of sectors */ @@ -343,13 +343,12 @@ int lun; /* logical unit */ int crc_count; /* crc counter to reduce drive speed */ - byte quirk_list; /* drive is considered quirky if set for a specific host */ - byte suspend_reset; /* drive suspend mode flag, soft-reset recovers */ - byte current_speed; /* current transfer rate set */ - byte dn; /* now wide spread use */ - byte wcache; /* status of write cache */ - byte acoustic; /* acoustic management */ - byte queue_depth; /* max queue depth */ + int quirk_list; /* drive is considered quirky if set for a specific host */ + u8 current_speed; /* current transfer rate set */ + u8 dn; /* now wide spread use */ + u8 wcache; /* status of write cache */ + u8 acoustic; /* acoustic management */ + unsigned int queue_depth; /* max queue depth */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ struct device dev; /* global device tree handle */ @@ -370,7 +369,7 @@ ATA_OP_FINISHED, /* no drive operation was started */ ATA_OP_CONTINUES, /* a drive operation was started, and a handler was set */ ATA_OP_RELEASED, /* started and released bus */ - ATA_OP_READY, /* indicate status poll finished fine */ + ATA_OP_READY /* indicate status poll finished fine */ } ide_startstop_t; /* @@ -428,10 +427,10 @@ */ /* setup disk on a channel for a particular PIO transfer mode */ - void (*tuneproc) (struct ata_device *, byte pio); + void (*tuneproc) (struct ata_device *, u8 pio); /* setup the chipset timing for a particular transfer mode */ - int (*speedproc) (struct ata_device *, byte pio); + int (*speedproc) (struct ata_device *, u8 pio); /* tweaks hardware to select drive */ void (*selectproc) (struct ata_device *); @@ -640,10 +639,8 @@ extern void ata_write(struct ata_device *, void *, unsigned int); extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *, char *); -extern int ide_config_drive_speed(struct ata_device *, byte); -extern byte eighty_ninty_three(struct ata_device *); - -extern void ide_stall_queue(struct ata_device *, unsigned long); +extern int ide_config_drive_speed(struct ata_device *, u8); +extern int eighty_ninty_three(struct ata_device *); extern int system_bus_speed; @@ -656,11 +653,11 @@ extern int drive_is_flashcard(struct ata_device *); -int ide_spin_wait_hwgroup(struct ata_device *); -void ide_timer_expiry (unsigned long data); +extern int ide_spin_wait_hwgroup(struct ata_device *); +extern void ide_timer_expiry(unsigned long data); extern void ata_irq_request(int irq, void *data, struct pt_regs *regs); -void do_ide_request (request_queue_t * q); -void ide_init_subdrivers (void); +extern void do_ide_request(request_queue_t * q); +extern void ide_init_subdrivers(void); extern struct block_device_operations ide_fops[]; @@ -742,12 +739,12 @@ static inline void udma_timeout(struct ata_device *drive) { - return drive->channel->udma_timeout(drive); + drive->channel->udma_timeout(drive); } static inline void udma_irq_lost(struct ata_device *drive) { - return drive->channel->udma_irq_lost(drive); + drive->channel->udma_irq_lost(drive); } #ifdef CONFIG_BLK_DEV_IDEDMA diff -Nru a/include/linux/input.h b/include/linux/input.h --- a/include/linux/input.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/input.h Fri Jul 26 19:58:51 2002 @@ -56,8 +56,15 @@ * IOCTLs (0x00 - 0x7f) */ +struct input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ -#define EVIOCGID _IOR('E', 0x02, short[4]) /* get device ID */ +#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ #define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */ #define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */ #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ @@ -73,6 +80,7 @@ #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, int[5]) /* get abs value/limits */ +#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, int[5]) /* set abs value/limits */ #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ @@ -82,7 +90,7 @@ * Event types */ -#define EV_RST 0x00 +#define EV_SYN 0x00 #define EV_KEY 0x01 #define EV_REL 0x02 #define EV_ABS 0x03 @@ -96,6 +104,13 @@ #define EV_MAX 0x1f /* + * Synchronization events. + */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 + +/* * Keys and buttons */ @@ -454,17 +469,15 @@ #define KEY_FIRST 0x194 #define KEY_LAST 0x195 #define KEY_AB 0x196 -#define KEY_PLAY 0x197 +#define KEY_NEXT 0x197 #define KEY_RESTART 0x198 #define KEY_SLOW 0x199 #define KEY_SHUFFLE 0x19a -#define KEY_FASTFORWARD 0x19b +#define KEY_BREAK 0x1ab #define KEY_PREVIOUS 0x19c -#define KEY_NEXT 0x19d -#define KEY_DIGITS 0x19e -#define KEY_TEEN 0x19f -#define KEY_TWEN 0x1a0 -#define KEY_BREAK 0x1a1 +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x1af #define KEY_MAX 0x1ff @@ -742,10 +755,7 @@ char *name; char *phys; char *uniq; - unsigned short idbus; - unsigned short idvendor; - unsigned short idproduct; - unsigned short idversion; + struct input_id id; unsigned long evbit[NBITS(EV_MAX)]; unsigned long keybit[NBITS(KEY_MAX)]; @@ -767,6 +777,8 @@ struct pm_dev *pm_dev; int state; + int sync; + int abs[ABS_MAX + 1]; int rep[REP_MAX + 1]; @@ -818,10 +830,7 @@ unsigned long flags; - unsigned short idbus; - unsigned short idvendor; - unsigned short idproduct; - unsigned short idversion; + struct input_id id; unsigned long evbit[NBITS(EV_MAX)]; unsigned long keybit[NBITS(KEY_MAX)]; @@ -884,6 +893,7 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); +#define input_sync(a) input_event(a, EV_SYN, SYN_REPORT, 0) #define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) #define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) #define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) diff -Nru a/include/linux/nbd.h b/include/linux/nbd.h --- a/include/linux/nbd.h Fri Jul 26 19:58:52 2002 +++ b/include/linux/nbd.h Fri Jul 26 19:58:52 2002 @@ -61,7 +61,7 @@ bio->bi_next = NULL; bio_endio(bio, uptodate); } - blkdev_release_request(req); + blk_put_request(req); spin_unlock_irqrestore(q->queue_lock, flags); } diff -Nru a/include/linux/ncp.h b/include/linux/ncp.h --- a/include/linux/ncp.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/ncp.h Fri Jul 26 19:58:50 2002 @@ -44,7 +44,7 @@ }; #define NCP_VOLNAME_LEN (16) -#define NCP_NUMBER_OF_VOLUMES (64) +#define NCP_NUMBER_OF_VOLUMES (256) struct ncp_volume_info { __u32 total_blocks; __u32 free_blocks; @@ -85,6 +85,18 @@ #define RIM_ALL (ntohl(0xFF0F0000L)) #define RIM_COMPRESSED_INFO (ntohl(0x00000080L)) +/* Defines for NSInfoBitMask */ +#define NSIBM_NFS_NAME 0x0001 +#define NSIBM_NFS_MODE 0x0002 +#define NSIBM_NFS_GID 0x0004 +#define NSIBM_NFS_NLINKS 0x0008 +#define NSIBM_NFS_RDEV 0x0010 +#define NSIBM_NFS_LINK 0x0020 +#define NSIBM_NFS_CREATED 0x0040 +#define NSIBM_NFS_UID 0x0080 +#define NSIBM_NFS_ACSFLAG 0x0100 +#define NSIBM_NFS_MYFLAG 0x0200 + /* open/create modes */ #define OC_MODE_OPEN 0x01 #define OC_MODE_TRUNCATE 0x02 @@ -109,6 +121,11 @@ #define AR_OPEN_COMPRESSED 0x0100 #endif +struct nw_nfs_info { + __u32 mode; + __u32 rdev; +}; + struct nw_info_struct { __u32 spaceAlloc __attribute__((packed)); __u32 attributes __attribute__((packed)); @@ -136,6 +153,10 @@ __u32 NSCreator __attribute__((packed)); __u8 nameLen __attribute__((packed)); __u8 entryName[256] __attribute__((packed)); + /* libncp may depend on there being nothing after entryName */ +#ifdef __KERNEL__ + struct nw_nfs_info nfs; +#endif }; /* modify mask - use with MODIFY_DOS_INFO structure */ diff -Nru a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h --- a/include/linux/ncp_fs.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/ncp_fs.h Fri Jul 26 19:58:51 2002 @@ -182,9 +182,8 @@ ino_t ino; int opened; int access; - __u32 server_file_handle __attribute__((packed)); - __u8 open_create_action __attribute__((packed)); - __u8 file_handle[6] __attribute__((packed)); + unsigned int volume; + __u8 file_handle[6]; }; /* Guess, what 0x564c is :-) */ diff -Nru a/include/linux/ncp_fs_i.h b/include/linux/ncp_fs_i.h --- a/include/linux/ncp_fs_i.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/ncp_fs_i.h Fri Jul 26 19:58:51 2002 @@ -22,7 +22,8 @@ struct semaphore open_sem; atomic_t opened; int access; - __u32 server_file_handle; + int flags; +#define NCPI_KLUDGE_SYMLINK 0x0001 __u8 file_handle[6]; struct inode vfs_inode; }; diff -Nru a/include/linux/ncp_mount.h b/include/linux/ncp_mount.h --- a/include/linux/ncp_mount.h Fri Jul 26 19:58:52 2002 +++ b/include/linux/ncp_mount.h Fri Jul 26 19:58:52 2002 @@ -21,6 +21,7 @@ #define NCP_MOUNT_NO_NFS 0x0010 /* do not use NFS namespace */ #define NCP_MOUNT_EXTRAS 0x0020 #define NCP_MOUNT_SYMLINKS 0x0040 /* enable symlinks */ +#define NCP_MOUNT_NFS_EXTRAS 0x0080 /* Enable use of NFS NS meta-info */ struct ncp_mount_data { int version; diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h --- a/include/linux/nfs_fs.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/nfs_fs.h Fri Jul 26 19:58:51 2002 @@ -90,6 +90,16 @@ #ifdef __KERNEL__ /* + * NFSv3 Access mode cache + */ +struct nfs_access_cache { + unsigned long jiffies; + struct rpc_cred * cred; + int mask; + int err; +}; + +/* * nfs fs inode data in memory */ struct nfs_inode { @@ -137,6 +147,8 @@ * This is of use for dentry revalidation */ unsigned long cache_mtime_jiffies; + + struct nfs_access_cache cache_access; /* * This is the cookie verifier used for NFSv3 readdir diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h --- a/include/linux/nfs_xdr.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/nfs_xdr.h Fri Jul 26 19:58:51 2002 @@ -300,7 +300,7 @@ struct iattr *); int (*lookup) (struct inode *, struct qstr *, struct nfs_fh *, struct nfs_fattr *); - int (*access) (struct inode *, int , int); + int (*access) (struct inode *, struct rpc_cred *, int); int (*readlink)(struct inode *, struct page *); int (*read) (struct inode *, struct rpc_cred *, struct nfs_fattr *, diff -Nru a/include/linux/notifier.h b/include/linux/notifier.h --- a/include/linux/notifier.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/notifier.h Fri Jul 26 19:58:50 2002 @@ -60,5 +60,7 @@ #define NETLINK_URELEASE 0x0001 /* Unicast netlink socket released */ +#define CPU_ONLINE 0x0002 /* CPU (unsigned)v coming up */ + #endif /* __KERNEL__ */ #endif /* _LINUX_NOTIFIER_H */ diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h --- a/include/linux/page-flags.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/page-flags.h Fri Jul 26 19:58:50 2002 @@ -249,6 +249,7 @@ static inline void pte_chain_unlock(struct page *page) { + smp_mb__before_clear_bit(); clear_bit(PG_chainlock, &page->flags); preempt_enable(); } diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/pci_ids.h Fri Jul 26 19:58:51 2002 @@ -1612,6 +1612,9 @@ #define PCI_DEVICE_ID_DCI_PCCOM4 0x0001 #define PCI_DEVICE_ID_DCI_PCCOM8 0x0002 +#define PCI_VENDOR_ID_DUNORD 0x5544 +#define PCI_DEVICE_ID_DUNORD_I3000 0x0001 + #define PCI_VENDOR_ID_GENROCO 0x5555 #define PCI_DEVICE_ID_GENROCO_HFP832 0x0003 diff -Nru a/include/linux/rwsem.h b/include/linux/rwsem.h --- a/include/linux/rwsem.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/rwsem.h Fri Jul 26 19:58:51 2002 @@ -75,6 +75,16 @@ rwsemtrace(sem,"Leaving up_write"); } +/* + * downgrade write lock to read lock + */ +static inline void downgrade_write(struct rw_semaphore *sem) +{ + rwsemtrace(sem,"Entering downgrade_write"); + __downgrade_write(sem); + rwsemtrace(sem,"Leaving downgrade_write"); +} + #endif /* __KERNEL__ */ #endif /* _LINUX_RWSEM_H */ diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/sched.h Fri Jul 26 19:58:50 2002 @@ -150,7 +150,6 @@ extern void update_one_process(struct task_struct *p, unsigned long user, unsigned long system, int cpu); extern void scheduler_tick(int user_tick, int system); -extern void migration_init(void); extern unsigned long cache_decay_ticks; diff -Nru a/include/linux/security.h b/include/linux/security.h --- a/include/linux/security.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/security.h Fri Jul 26 19:58:50 2002 @@ -103,6 +103,345 @@ * @bprm contains the linux_binprm structure. * Return 0 if the hook is successful and permission is granted. * + * Security hooks for filesystem operations. + * + * @sb_alloc_security: + * Allocate and attach a security structure to the sb->s_security field. + * The s_security field is initialized to NULL when the structure is + * allocated. + * @sb contains the super_block structure to be modified. + * Return 0 if operation was successful. + * @sb_free_security: + * Deallocate and clear the sb->s_security field. + * @sb contains the super_block structure to be modified. + * @sb_statfs: + * Check permission before obtaining filesystem statistics for the @sb + * filesystem. + * @sb contains the super_block structure for the filesystem. + * Return 0 if permission is granted. + * @sb_mount: + * Check permission before an object specified by @dev_name is mounted on + * the mount point named by @nd. For an ordinary mount, @dev_name + * identifies a device if the file system type requires a device. For a + * remount (@flags & MS_REMOUNT), @dev_name is irrelevant. For a + * loopback/bind mount (@flags & MS_BIND), @dev_name identifies the + * pathname of the object being mounted. + * @dev_name contains the name for object being mounted. + * @nd contains the nameidata structure for mount point object. + * @type contains the filesystem type. + * @flags contains the mount flags. + * @data contains the filesystem-specific data. + * Return 0 if permission is granted. + * @sb_check_sb: + * Check permission before the device with superblock @mnt->sb is mounted + * on the mount point named by @nd. + * @mnt contains the vfsmount for device being mounted. + * @nd contains the nameidata object for the mount point. + * Return 0 if permission is granted. + * @sb_umount: + * Check permission before the @mnt file system is unmounted. + * @mnt contains the mounted file system. + * @flags contains the unmount flags, e.g. MNT_FORCE. + * Return 0 if permission is granted. + * @sb_umount_close: + * Close any files in the @mnt mounted filesystem that are held open by + * the security module. This hook is called during an umount operation + * prior to checking whether the filesystem is still busy. + * @mnt contains the mounted filesystem. + * @sb_umount_busy: + * Handle a failed umount of the @mnt mounted filesystem, e.g. re-opening + * any files that were closed by umount_close. This hook is called during + * an umount operation if the umount fails after a call to the + * umount_close hook. + * @mnt contains the mounted filesystem. + * @sb_post_remount: + * Update the security module's state when a filesystem is remounted. + * This hook is only called if the remount was successful. + * @mnt contains the mounted file system. + * @flags contains the new filesystem flags. + * @data contains the filesystem-specific data. + * @sb_post_mountroot: + * Update the security module's state when the root filesystem is mounted. + * This hook is only called if the mount was successful. + * @sb_post_addmount: + * Update the security module's state when a filesystem is mounted. + * This hook is called any time a mount is successfully grafetd to + * the tree. + * @mnt contains the mounted filesystem. + * @mountpoint_nd contains the nameidata structure for the mount point. + * @sb_pivotroot: + * Check permission before pivoting the root filesystem. + * @old_nd contains the nameidata structure for the new location of the current root (put_old). + * @new_nd contains the nameidata structure for the new root (new_root). + * Return 0 if permission is granted. + * @sb_post_pivotroot: + * Update module state after a successful pivot. + * @old_nd contains the nameidata structure for the old root. + * @new_nd contains the nameidata structure for the new root. + * + * Security hooks for inode operations. + * + * @inode_alloc_security: + * Allocate and attach a security structure to @inode->i_security. The + * i_security field is initialized to NULL when the inode structure is + * allocated. + * @inode contains the inode structure. + * Return 0 if operation was successful. + * @inode_free_security: + * @inode contains the inode structure. + * Deallocate the inode security structure and set @inode->i_security to + * NULL. + * @inode_create: + * Check permission to create a regular file. + * @dir contains inode structure of the parent of the new file. + * @dentry contains the dentry structure for the file to be created. + * @mode contains the file mode of the file to be created. + * Return 0 if permission is granted. + * @inode_post_create: + * Set the security attributes on a newly created regular file. This hook + * is called after a file has been successfully created. + * @dir contains the inode structure of the parent directory of the new file. + * @dentry contains the the dentry structure for the newly created file. + * @mode contains the file mode. + * @inode_link: + * Check permission before creating a new hard link to a file. + * @old_dentry contains the dentry structure for an existing link to the file. + * @dir contains the inode structure of the parent directory of the new link. + * @new_dentry contains the dentry structure for the new link. + * Return 0 if permission is granted. + * @inode_post_link: + * Set security attributes for a new hard link to a file. + * @old_dentry contains the dentry structure for the existing link. + * @dir contains the inode structure of the parent directory of the new file. + * @new_dentry contains the dentry structure for the new file link. + * @inode_unlink: + * Check the permission to remove a hard link to a file. + * @dir contains the inode structure of parent directory of the file. + * @dentry contains the dentry structure for file to be unlinked. + * Return 0 if permission is granted. + * @inode_symlink: + * Check the permission to create a symbolic link to a file. + * @dir contains the inode structure of parent directory of the symbolic link. + * @dentry contains the dentry structure of the symbolic link. + * @old_name contains the pathname of file. + * Return 0 if permission is granted. + * @inode_post_symlink: + * @dir contains the inode structure of the parent directory of the new link. + * @dentry contains the dentry structure of new symbolic link. + * @old_name contains the pathname of file. + * Set security attributes for a newly created symbolic link. Note that + * @dentry->d_inode may be NULL, since the filesystem might not + * instantiate the dentry (e.g. NFS). + * @inode_mkdir: + * Check permissions to create a new directory in the existing directory + * associated with inode strcture @dir. + * @dir containst the inode structure of parent of the directory to be created. + * @dentry contains the dentry structure of new directory. + * @mode contains the mode of new directory. + * Return 0 if permission is granted. + * @inode_post_mkdir: + * Set security attributes on a newly created directory. + * @dir contains the inode structure of parent of the directory to be created. + * @dentry contains the dentry structure of new directory. + * @mode contains the mode of new directory. + * @inode_rmdir: + * Check the permission to remove a directory. + * @dir contains the inode structure of parent of the directory to be removed. + * @dentry contains the dentry structure of directory to be removed. + * Return 0 if permission is granted. + * @inode_mknod: + * Check permissions when creating a special file (or a socket or a fifo + * file created via the mknod system call). Note that if mknod operation + * is being done for a regular file, then the create hook will be called + * and not this hook. + * @dir contains the inode structure of parent of the new file. + * @dentry contains the dentry structure of the new file. + * @mode contains the mode of the new file. + * @dev contains the the device number. + * Return 0 if permission is granted. + * @inode_post_mknod: + * Set security attributes on a newly created special file (or socket or + * fifo file created via the mknod system call). + * @dir contains the inode structure of parent of the new node. + * @dentry contains the dentry structure of the new node. + * @mode contains the mode of the new node. + * @dev contains the the device number. + * @inode_rename: + * Check for permission to rename a file or directory. + * @old_dir contains the inode structure for parent of the old link. + * @old_dentry contains the dentry structure of the old link. + * @new_dir contains the inode structure for parent of the new link. + * @new_dentry contains the dentry structure of the new link. + * Return 0 if permission is granted. + * @inode_post_rename: + * Set security attributes on a renamed file or directory. + * @old_dir contains the inode structure for parent of the old link. + * @old_dentry contains the dentry structure of the old link. + * @new_dir contains the inode structure for parent of the new link. + * @new_dentry contains the dentry structure of the new link. + * @inode_readlink: + * Check the permission to read the symbolic link. + * @dentry contains the dentry structure for the file link. + * Return 0 if permission is granted. + * @inode_follow_link: + * Check permission to follow a symbolic link when looking up a pathname. + * @dentry contains the dentry structure for the link. + * @nd contains the nameidata structure for the parent directory. + * Return 0 if permission is granted. + * @inode_permission: + * Check permission before accessing an inode. This hook is called by the + * existing Linux permission function, so a security module can use it to + * provide additional checking for existing Linux permission checks. + * Notice that this hook is called when a file is opened (as well as many + * other operations), whereas the file_security_ops permission hook is + * called when the actual read/write operations are performed. + * @inode contains the inode structure to check. + * @mask contains the permission mask. + * Return 0 if permission is granted. + * @inode_permission_lite: + * Check permission before accessing an inode. This hook is + * currently only called when checking MAY_EXEC access during + * pathname resolution. The dcache lock is held and thus modules + * that could sleep or contend the lock should return -EAGAIN to + * inform the kernel to drop the lock and try again calling the + * full permission hook. + * @inode contains the inode structure to check. + * @mask contains the permission mask. + * Return 0 if permission is granted. + * @inode_setattr: + * Check permission before setting file attributes. Note that the kernel + * call to notify_change is performed from several locations, whenever + * file attributes change (such as when a file is truncated, chown/chmod + * operations, transferring disk quotas, etc). + * @dentry contains the dentry structure for the file. + * @attr is the iattr structure containing the new file attributes. + * Return 0 if permission is granted. + * @inode_getattr: + * Check permission before obtaining file attributes. + * @mnt is the vfsmount where the dentry was looked up + * @dentry contains the dentry structure for the file. + * Return 0 if permission is granted. + * @inode_post_lookup: + * Set the security attributes for a file after it has been looked up. + * @inode contains the inode structure for parent directory. + * @d contains the dentry structure for the file. + * @inode_delete: + * @inode contains the inode structure for deleted inode. + * This hook is called when a deleted inode is released (i.e. an inode + * with no hard links has its use count drop to zero). A security module + * can use this hook to release any persistent label associated with the + * inode. + * @inode_setxattr: + * Check permission before setting the extended attributes + * @value identified by @name for @dentry. + * Return 0 if permission is granted. + * @inode_getxattr: + * Check permission before obtaining the extended attributes + * identified by @name for @dentry. + * Return 0 if permission is granted. + * @inode_listxattr: + * Check permission before obtaining the list of extended attribute + * names for @dentry. + * Return 0 if permission is granted. + * @inode_removexattr: + * Check permission before removing the extended attribute + * identified by @name for @dentry. + * Return 0 if permission is granted. + * + * Security hooks for file operations + * + * @file_permission: + * Check file permissions before accessing an open file. This hook is + * called by various operations that read or write files. A security + * module can use this hook to perform additional checking on these + * operations, e.g. to revalidate permissions on use to support privilege + * bracketing or policy changes. Notice that this hook is used when the + * actual read/write operations are performed, whereas the + * inode_security_ops hook is called when a file is opened (as well as + * many other operations). + * Caveat: Although this hook can be used to revalidate permissions for + * various system call operations that read or write files, it does not + * address the revalidation of permissions for memory-mapped files. + * Security modules must handle this separately if they need such + * revalidation. + * @file contains the file structure being accessed. + * @mask contains the requested permissions. + * Return 0 if permission is granted. + * @file_alloc_security: + * Allocate and attach a security structure to the file->f_security field. + * The security field is initialized to NULL when the structure is first + * created. + * @file contains the file structure to secure. + * Return 0 if the hook is successful and permission is granted. + * @file_free_security: + * Deallocate and free any security structures stored in file->f_security. + * @file contains the file structure being modified. + * @file_llseek: + * Check permission before re-positioning the file offset in @file. + * @file contains the file structure being modified. + * Return 0 if permission is granted. + * @file_ioctl: + * @file contains the file structure. + * @cmd contains the operation to perform. + * @arg contains the operational arguments. + * Check permission for an ioctl operation on @file. Note that @arg can + * sometimes represents a user space pointer; in other cases, it may be a + * simple integer value. When @arg represents a user space pointer, it + * should never be used by the security module. + * Return 0 if permission is granted. + * @file_mmap : + * Check permissions for a mmap operation. The @file may be NULL, e.g. + * if mapping anonymous memory. + * @file contains the file structure for file to map (may be NULL). + * @prot contains the requested permissions. + * @flags contains the operational flags. + * Return 0 if permission is granted. + * @file_mprotect: + * Check permissions before changing memory access permissions. + * @vma contains the memory region to modify. + * @prot contains the requested permissions. + * Return 0 if permission is granted. + * @file_lock: + * Check permission before performing file locking operations. + * Note: this hook mediates both flock and fcntl style locks. + * @file contains the file structure. + * @cmd contains the posix-translated lock operation to perform + * (e.g. F_RDLCK, F_WRLCK). + * @blocking indicates if the request is for a blocking lock. + * Return 0 if permission is granted. + * @file_fcntl: + * Check permission before allowing the file operation specified by @cmd + * from being performed on the file @file. Note that @arg can sometimes + * represents a user space pointer; in other cases, it may be a simple + * integer value. When @arg represents a user space pointer, it should + * never be used by the security module. + * @file contains the file structure. + * @cmd contains the operation to be performed. + * @arg contains the operational arguments. + * Return 0 if permission is granted. + * @file_set_fowner: + * Save owner security information (typically from current->security) in + * file->f_security for later use by the send_sigiotask hook. + * @file contains the file structure to update. + * Return 0 on success. + * @file_send_sigiotask: + * Check permission for the file owner @fown to send SIGIO to the process + * @tsk. Note that this hook is always called from interrupt. Note that + * the fown_struct, @fown, is never outside the context of a struct file, + * so the file structure (and associated security information) can always + * be obtained: + * (struct file *)((long)fown - offsetof(struct file,f_owner)); + * @tsk contains the structure of task receiving signal. + * @fown contains the file owner information. + * @fd contains the file descriptor. + * @reason contains the operational flags. + * Return 0 if permission is granted. + * @file_receive: + * This hook allows security modules to control the ability of a process + * to receive an open file descriptor via socket IPC. + * @file contains the file structure being received. + * Return 0 if permission is granted. + * * Security hooks for task operations. * * @task_create: @@ -277,6 +616,13 @@ * @effective contains the effective capability set. * @inheritable contains the inheritable capability set. * @permitted contains the permitted capability set. + * @acct: + * Check permission before enabling or disabling process accounting. If + * accounting is being enabled, then @file refers to the open file used to + * store accounting records. If accounting is being disabled, then @file + * is NULL. + * @file contains the file structure for the accounting file (may be NULL). + * Return 0 if permission is granted. * @capable: * Check whether the @tsk process has the @cap capability. * @tsk contains the task_struct for the process. @@ -322,15 +668,99 @@ kernel_cap_t * effective, kernel_cap_t * inheritable, kernel_cap_t * permitted); + int (*acct) (struct file * file); int (*capable) (struct task_struct * tsk, int cap); int (*sys_security) (unsigned int id, unsigned call, unsigned long *args); + int (*quotactl) (int cmds, int type, int id, struct super_block * sb); + int (*quota_on) (struct file * f); int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); void (*bprm_compute_creds) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_check_security) (struct linux_binprm * bprm); + + int (*sb_alloc_security) (struct super_block * sb); + void (*sb_free_security) (struct super_block * sb); + int (*sb_statfs) (struct super_block * sb); + int (*sb_mount) (char *dev_name, struct nameidata * nd, + char *type, unsigned long flags, void *data); + int (*sb_check_sb) (struct vfsmount * mnt, struct nameidata * nd); + int (*sb_umount) (struct vfsmount * mnt, int flags); + void (*sb_umount_close) (struct vfsmount * mnt); + void (*sb_umount_busy) (struct vfsmount * mnt); + void (*sb_post_remount) (struct vfsmount * mnt, + unsigned long flags, void *data); + void (*sb_post_mountroot) (void); + void (*sb_post_addmount) (struct vfsmount * mnt, + struct nameidata * mountpoint_nd); + int (*sb_pivotroot) (struct nameidata * old_nd, + struct nameidata * new_nd); + void (*sb_post_pivotroot) (struct nameidata * old_nd, + struct nameidata * new_nd); + + int (*inode_alloc_security) (struct inode *inode); + void (*inode_free_security) (struct inode *inode); + int (*inode_create) (struct inode *dir, + struct dentry *dentry, int mode); + void (*inode_post_create) (struct inode *dir, + struct dentry *dentry, int mode); + int (*inode_link) (struct dentry *old_dentry, + struct inode *dir, struct dentry *new_dentry); + void (*inode_post_link) (struct dentry *old_dentry, + struct inode *dir, struct dentry *new_dentry); + int (*inode_unlink) (struct inode *dir, struct dentry *dentry); + int (*inode_symlink) (struct inode *dir, + struct dentry *dentry, const char *old_name); + void (*inode_post_symlink) (struct inode *dir, + struct dentry *dentry, + const char *old_name); + int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode); + void (*inode_post_mkdir) (struct inode *dir, struct dentry *dentry, + int mode); + int (*inode_rmdir) (struct inode *dir, struct dentry *dentry); + int (*inode_mknod) (struct inode *dir, struct dentry *dentry, + int mode, dev_t dev); + void (*inode_post_mknod) (struct inode *dir, struct dentry *dentry, + int mode, dev_t dev); + int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); + void (*inode_post_rename) (struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry); + int (*inode_readlink) (struct dentry *dentry); + int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); + int (*inode_permission) (struct inode *inode, int mask); + int (*inode_permission_lite) (struct inode *inode, int mask); + int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); + int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); + void (*inode_post_lookup) (struct inode *inode, struct dentry *d); + void (*inode_delete) (struct inode *inode); + int (*inode_setxattr) (struct dentry *dentry, char *name, void *value, + size_t size, int flags); + int (*inode_getxattr) (struct dentry *dentry, char *name); + int (*inode_listxattr) (struct dentry *dentry); + int (*inode_removexattr) (struct dentry *dentry, char *name); + + int (*file_permission) (struct file * file, int mask); + int (*file_alloc_security) (struct file * file); + void (*file_free_security) (struct file * file); + int (*file_llseek) (struct file * file); + int (*file_ioctl) (struct file * file, unsigned int cmd, + unsigned long arg); + int (*file_mmap) (struct file * file, + unsigned long prot, unsigned long flags); + int (*file_mprotect) (struct vm_area_struct * vma, unsigned long prot); + int (*file_lock) (struct file * file, unsigned int cmd, int blocking); + int (*file_fcntl) (struct file * file, unsigned int cmd, + unsigned long arg); + int (*file_set_fowner) (struct file * file); + int (*file_send_sigiotask) (struct task_struct * tsk, + struct fown_struct * fown, + int fd, int reason); + int (*file_receive) (struct file * file); int (*task_create) (unsigned long clone_flags); int (*task_alloc_security) (struct task_struct * p); diff -Nru a/include/linux/serio.h b/include/linux/serio.h --- a/include/linux/serio.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/serio.h Fri Jul 26 19:58:51 2002 @@ -94,8 +94,12 @@ serio->dev->write_wakeup(serio); } +/* + * bit masks for use in "interrupt" flags (3rd argument) + */ #define SERIO_TIMEOUT 1 #define SERIO_PARITY 2 +#define SERIO_FRAME 4 #define SERIO_TYPE 0xff000000UL #define SERIO_XT 0x00000000UL diff -Nru a/include/linux/smp.h b/include/linux/smp.h --- a/include/linux/smp.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/smp.h Fri Jul 26 19:58:51 2002 @@ -32,19 +32,19 @@ /* - * Boot processor call to load the other CPU's + * Prepare machine for booting other CPUs. */ -extern void smp_boot_cpus(void); +extern void smp_prepare_cpus(unsigned int max_cpus); /* - * Processor call in. Must hold processors until .. + * Bring a CPU up */ -extern void smp_callin(void); +extern int __cpu_up(unsigned int cpunum); /* - * Multiprocessors may now schedule + * Final polishing of CPUs */ -extern void smp_commence(void); +extern void smp_cpus_done(unsigned int max_cpus); /* * Call a function on all other processors @@ -71,6 +71,13 @@ #define MSG_RESCHEDULE 0x0003 /* Reschedule request from master CPU*/ #define MSG_CALL_FUNCTION 0x0004 /* Call function on all other CPUs */ +struct notifier_block; + +/* Need to know about CPUs going up/down? */ +extern int register_cpu_notifier(struct notifier_block *nb); +extern void unregister_cpu_notifier(struct notifier_block *nb); + +int cpu_up(unsigned int cpu); #else /* !SMP */ /* @@ -87,11 +94,15 @@ static inline void smp_send_reschedule(int cpu) { } static inline void smp_send_reschedule_all(void) { } #define cpu_online_map 1 -#define cpu_online(cpu) 1 +#define cpu_online(cpu) ({ cpu; 1; }) #define num_online_cpus() 1 #define __per_cpu_data #define per_cpu(var, cpu) var #define this_cpu(var) var + +/* Need to know about CPUs going up/down? */ +#define register_cpu_notifier(nb) 0 +#define unregister_cpu_notifier(nb) do { } while(0) #endif /* !SMP */ diff -Nru a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h --- a/include/linux/sunrpc/clnt.h Fri Jul 26 19:58:51 2002 +++ b/include/linux/sunrpc/clnt.h Fri Jul 26 19:58:51 2002 @@ -127,6 +127,7 @@ void rpc_restart_call(struct rpc_task *); void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); +void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); static __inline__ int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h --- a/include/linux/sunrpc/xprt.h Fri Jul 26 19:58:52 2002 +++ b/include/linux/sunrpc/xprt.h Fri Jul 26 19:58:52 2002 @@ -122,6 +122,9 @@ unsigned long cong; /* current congestion */ unsigned long cwnd; /* congestion window */ + unsigned int rcvsize, /* socket receive buffer size */ + sndsize; /* socket send buffer size */ + struct rpc_wait_queue sending; /* requests waiting to send */ struct rpc_wait_queue resend; /* requests waiting to resend */ struct rpc_wait_queue pending; /* requests in flight */ @@ -177,13 +180,9 @@ void xprt_release(struct rpc_task *); void xprt_reconnect(struct rpc_task *); int xprt_clear_backlog(struct rpc_xprt *); +void xprt_sock_setbufsize(struct rpc_xprt *); -#define XPRT_WSPACE 0 -#define XPRT_CONNECT 1 - -#define xprt_wspace(xp) (test_bit(XPRT_WSPACE, &(xp)->sockstate)) -#define xprt_test_and_set_wspace(xp) (test_and_set_bit(XPRT_WSPACE, &(xp)->sockstate)) -#define xprt_clear_wspace(xp) (clear_bit(XPRT_WSPACE, &(xp)->sockstate)) +#define XPRT_CONNECT 0 #define xprt_connected(xp) (!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) diff -Nru a/include/linux/uinput.h b/include/linux/uinput.h --- a/include/linux/uinput.h Fri Jul 26 19:58:50 2002 +++ b/include/linux/uinput.h Fri Jul 26 19:58:50 2002 @@ -64,10 +64,7 @@ #define UINPUT_MAX_NAME_SIZE 80 struct uinput_user_dev { char name[UINPUT_MAX_NAME_SIZE]; - unsigned short idbus; - unsigned short idvendor; - unsigned short idproduct; - unsigned short idversion; + struct input_id id; int ff_effects_max; int absmax[ABS_MAX + 1]; int absmin[ABS_MAX + 1]; diff -Nru a/init/do_mounts.c b/init/do_mounts.c --- a/init/do_mounts.c Fri Jul 26 19:58:51 2002 +++ b/init/do_mounts.c Fri Jul 26 19:58:51 2002 @@ -845,6 +845,7 @@ sys_umount("/dev", 0); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); + security_ops->sb_post_mountroot(); mount_devfs_fs (); } diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Fri Jul 26 19:58:50 2002 +++ b/init/main.c Fri Jul 26 19:58:50 2002 @@ -95,6 +95,35 @@ char *execute_command; +/* Setup configured maximum number of CPUs to activate */ +static unsigned int max_cpus = UINT_MAX; + +/* + * Setup routine for controlling SMP activation + * + * Command-line option of "nosmp" or "maxcpus=0" will disable SMP + * activation entirely (the MPS table probe still happens, though). + * + * Command-line option of "maxcpus=", where is an integer + * greater than 0, limits the maximum number of CPUs activated in + * SMP mode to . + */ +static int __init nosmp(char *str) +{ + max_cpus = 0; + return 1; +} + +__setup("nosmp", nosmp); + +static int __init maxcpus(char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); + static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; @@ -275,6 +304,7 @@ #endif static inline void setup_per_cpu_areas(void) { } +static inline void smp_prepare_cpus(unsigned int maxcpus) { } #else @@ -305,11 +335,27 @@ /* Called by boot processor to activate the rest. */ static void __init smp_init(void) { + unsigned int i; + + /* FIXME: This should be done in userspace --RR */ + for (i = 0; i < NR_CPUS; i++) { + if (num_online_cpus() >= max_cpus) + break; + if (cpu_possible(i) && !cpu_online(i)) { + printk("Bringing up %i\n", i); + cpu_up(i); + } + } + + /* Any cleanup work */ + printk("CPUS done %u\n", max_cpus); + smp_cpus_done(max_cpus); +#if 0 /* Get other processors into their bootup holding patterns. */ - smp_boot_cpus(); smp_threads_ready=1; smp_commence(); +#endif } #endif @@ -405,14 +451,12 @@ check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); - init_idle(current, smp_processor_id()); - /* * We count on the initial thread going ok * Like idlers init is an unlocked kernel thread, which will * make syscalls (and thus be locked). */ - smp_init(); + init_idle(current, smp_processor_id()); /* Do the rest non-__init'ed, we're now alive */ rest_init(); @@ -444,12 +488,6 @@ static void __init do_basic_setup(void) { /* - * Let the per-CPU migration threads start up: - */ -#if CONFIG_SMP - migration_init(); -#endif - /* * Tell the world that we're going to be the grim * reaper of innocent orphaned children. * @@ -493,6 +531,9 @@ static char * argv_sh[] = { "sh", NULL, }; lock_kernel(); + /* Sets up cpus_possible() */ + smp_prepare_cpus(max_cpus); + smp_init(); do_basic_setup(); prepare_namespace(); diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Fri Jul 26 19:58:50 2002 +++ b/kernel/Makefile Fri Jul 26 19:58:51 2002 @@ -17,6 +17,7 @@ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o context.o futex.o platform.o +obj-$(CONFIG_SMP) += cpu.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o diff -Nru a/kernel/acct.c b/kernel/acct.c --- a/kernel/acct.c Fri Jul 26 19:58:51 2002 +++ b/kernel/acct.c Fri Jul 26 19:58:51 2002 @@ -195,6 +195,7 @@ { struct file *file = NULL; char *tmp; + int error; if (!capable(CAP_SYS_PACCT)) return -EPERM; @@ -220,6 +221,10 @@ return (-EIO); } } + + error = security_ops->acct(file); + if (error) + return error; spin_lock(&acct_globals.lock); acct_file_reopen(file); diff -Nru a/kernel/cpu.c b/kernel/cpu.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/kernel/cpu.c Fri Jul 26 19:58:52 2002 @@ -0,0 +1,54 @@ +/* CPU control. + * (C) 2001 Rusty Russell + * This code is licenced under the GPL. + */ +#include +#include +#include +#include +#include +#include +#include + +/* This protects CPUs going up and down... */ +DECLARE_MUTEX(cpucontrol); + +static struct notifier_block *cpu_chain = NULL; + +/* Need to know about CPUs going up/down? */ +int register_cpu_notifier(struct notifier_block *nb) +{ + return notifier_chain_register(&cpu_chain, nb); +} + +void unregister_cpu_notifier(struct notifier_block *nb) +{ + notifier_chain_unregister(&cpu_chain,nb); +} + +int __devinit cpu_up(unsigned int cpu) +{ + int ret; + + if ((ret = down_interruptible(&cpucontrol)) != 0) + return ret; + + if (cpu_online(cpu)) { + ret = -EINVAL; + goto out; + } + + /* Arch-specific enabling code. */ + ret = __cpu_up(cpu); + if (ret != 0) goto out; + if (!cpu_online(cpu)) + BUG(); + + /* Now call notifier in preparation. */ + printk("CPU %u IS NOW UP!\n", cpu); + notifier_call_chain(&cpu_chain, CPU_ONLINE, (void *)cpu); + + out: + up(&cpucontrol); + return ret; +} diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Fri Jul 26 19:58:51 2002 +++ b/kernel/sched.c Fri Jul 26 19:58:51 2002 @@ -27,6 +27,8 @@ #include #include #include +#include +#include /* * Convert user-nice values [ -20 ... 0 ... 19 ] @@ -357,7 +359,7 @@ */ void kick_if_running(task_t * p) { - if ((task_running(task_rq(p), p)) && (p->thread_info->cpu != smp_processor_id())) + if ((task_running(task_rq(p), p)) && (task_cpu(p) != smp_processor_id())) resched_task(p); } @@ -1777,9 +1779,11 @@ migration_req_t req; runqueue_t *rq; +#if 0 /* FIXME: Grab cpu_lock, return error on this case. --RR */ new_mask &= cpu_online_map; if (!new_mask) BUG(); +#endif preempt_disable(); rq = task_rq_lock(p, &flags); @@ -1812,8 +1816,6 @@ preempt_enable(); } -static __initdata int master_migration_thread; - static int migration_thread(void * bind_cpu) { int cpu = (int) (long) bind_cpu; @@ -1825,15 +1827,7 @@ sigfillset(¤t->blocked); set_fs(KERNEL_DS); - /* - * The first migration thread is started on the boot CPU, it - * migrates the other migration threads to their destination CPUs. - */ - if (cpu != master_migration_thread) { - while (!cpu_rq(master_migration_thread)->migration_thread) - yield(); - set_cpus_allowed(current, 1UL << cpu); - } + set_cpus_allowed(current, 1UL << cpu); printk("migration_task %d on cpu=%d\n", cpu, smp_processor_id()); ret = setscheduler(0, SCHED_FIFO, ¶m); @@ -1890,29 +1884,33 @@ } } -void __init migration_init(void) -{ - int cpu; - - master_migration_thread = smp_processor_id(); - current->cpus_allowed = 1UL << master_migration_thread; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - if (kernel_thread(migration_thread, (void *) (long) cpu, - CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) - BUG(); +static int migration_call(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + switch (action) { + case CPU_ONLINE: + printk("Starting migration thread for cpu %li\n", + (long)hcpu); + kernel_thread(migration_thread, hcpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + break; } - current->cpus_allowed = -1L; + return NOTIFY_OK; +} - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - while (!cpu_rq(cpu)->migration_thread) - schedule_timeout(2); - } +static struct notifier_block migration_notifier = { &migration_call, NULL, 0 }; + +int __init migration_init(void) +{ + /* Start one for boot CPU. */ + migration_call(&migration_notifier, CPU_ONLINE, + (void *)smp_processor_id()); + register_cpu_notifier(&migration_notifier); + return 0; } + +__initcall(migration_init); #endif extern void init_timervecs(void); diff -Nru a/kernel/softirq.c b/kernel/softirq.c --- a/kernel/softirq.c Fri Jul 26 19:58:51 2002 +++ b/kernel/softirq.c Fri Jul 26 19:58:51 2002 @@ -17,6 +17,7 @@ #include #include #include +#include /* - No shared variables, all the data are CPU local. @@ -387,20 +388,32 @@ } } +static int __devinit cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + int hotcpu = (unsigned long)hcpu; + + if (action == CPU_ONLINE) { + if (kernel_thread(ksoftirqd, hcpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) { + printk("ksoftirqd for %i failed\n", hotcpu); + return NOTIFY_BAD; + } + + while (!ksoftirqd_task(hotcpu)) + yield(); + return NOTIFY_OK; + } + return NOTIFY_BAD; +} + +static struct notifier_block cpu_nfb = { &cpu_callback, NULL, 0 }; + static __init int spawn_ksoftirqd(void) { - int cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - if (kernel_thread(ksoftirqd, (void *) (long) cpu, - CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) - printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); - else - while (!ksoftirqd_task(cpu)) - yield(); - } + cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)smp_processor_id()); + register_cpu_notifier(&cpu_nfb); return 0; } diff -Nru a/kernel/timer.c b/kernel/timer.c --- a/kernel/timer.c Fri Jul 26 19:58:51 2002 +++ b/kernel/timer.c Fri Jul 26 19:58:51 2002 @@ -169,7 +169,7 @@ } /* Initialize both explicitly - let's try to have them in the same cache line */ -spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED; +spinlock_t timerlist_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; #ifdef CONFIG_SMP volatile struct timer_list * volatile running_timer; @@ -327,7 +327,7 @@ spin_unlock_irq(&timerlist_lock); } -spinlock_t tqueue_lock = SPIN_LOCK_UNLOCKED; +spinlock_t tqueue_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; void tqueue_bh(void) { @@ -633,7 +633,7 @@ * This read-write spinlock protects us from races in SMP while * playing with xtime and avenrun. */ -rwlock_t xtime_lock = RW_LOCK_UNLOCKED; +rwlock_t xtime_lock __cacheline_aligned_in_smp = RW_LOCK_UNLOCKED; unsigned long last_time_offset; static inline void update_times(void) diff -Nru a/lib/rwsem.c b/lib/rwsem.c --- a/lib/rwsem.c Fri Jul 26 19:58:50 2002 +++ b/lib/rwsem.c Fri Jul 26 19:58:50 2002 @@ -34,8 +34,9 @@ * - there must be someone on the queue * - the spinlock must be held by the caller * - woken process blocks are discarded from the list after having flags zeroised + * - writers are only woken if wakewrite is non-zero */ -static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem) +static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) { struct rwsem_waiter *waiter; struct list_head *next; @@ -44,6 +45,9 @@ rwsemtrace(sem,"Entering __rwsem_do_wake"); + if (!wakewrite) + goto dont_wake_writers; + /* only wake someone up if we can transition the active part of the count from 0 -> 1 */ try_again: oldcount = rwsem_atomic_update(RWSEM_ACTIVE_BIAS,sem) - RWSEM_ACTIVE_BIAS; @@ -64,6 +68,12 @@ wake_up_process(waiter->task); goto out; + /* don't want to wake any writers */ + dont_wake_writers: + waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list); + if (waiter->flags & RWSEM_WAITING_FOR_WRITE) + goto out; + /* grant an infinite number of read locks to the readers at the front of the queue * - note we increment the 'active part' of the count by the number of readers (less one * for the activity decrement we've already done) before waking any processes up @@ -132,7 +142,7 @@ * - it might even be this process, since the waker takes a more active part */ if (!(count & RWSEM_ACTIVE_MASK)) - sem = __rwsem_do_wake(sem); + sem = __rwsem_do_wake(sem,1); spin_unlock(&sem->wait_lock); @@ -193,12 +203,33 @@ /* do nothing if list empty */ if (!list_empty(&sem->wait_list)) - sem = __rwsem_do_wake(sem); + sem = __rwsem_do_wake(sem,1); spin_unlock(&sem->wait_lock); rwsemtrace(sem,"Leaving rwsem_wake"); + return sem; +} + +/* + * downgrade a write lock into a read lock + * - caller incremented waiting part of count, and discovered it to be still negative + * - just wake up any readers at the front of the queue + */ +struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem) +{ + rwsemtrace(sem,"Entering rwsem_downgrade_wake"); + + spin_lock(&sem->wait_lock); + + /* do nothing if list empty */ + if (!list_empty(&sem->wait_list)) + sem = __rwsem_do_wake(sem,0); + + spin_unlock(&sem->wait_lock); + + rwsemtrace(sem,"Leaving rwsem_downgrade_wake"); return sem; } diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Fri Jul 26 19:58:51 2002 +++ b/mm/filemap.c Fri Jul 26 19:58:51 2002 @@ -21,6 +21,7 @@ #include #include #include +#include /* * This is needed for the following functions: * - try_to_release_page @@ -1143,6 +1144,10 @@ if (retval) goto fput_in; + retval = security_ops->file_permission (in_file, MAY_READ); + if (retval) + goto fput_in; + /* * Get output file, and verify that it is ok.. */ @@ -1157,6 +1162,10 @@ goto fput_out; out_inode = out_file->f_dentry->d_inode; retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count); + if (retval) + goto fput_out; + + retval = security_ops->file_permission (out_file, MAY_WRITE); if (retval) goto fput_out; diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c Fri Jul 26 19:58:50 2002 +++ b/mm/mmap.c Fri Jul 26 19:58:50 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -475,6 +476,10 @@ } } + error = security_ops->file_mmap(file, prot, flags); + if (error) + return error; + /* Clear old maps */ error = -ENOMEM; munmap_back: diff -Nru a/mm/mprotect.c b/mm/mprotect.c --- a/mm/mprotect.c Fri Jul 26 19:58:51 2002 +++ b/mm/mprotect.c Fri Jul 26 19:58:51 2002 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -305,6 +306,10 @@ error = -EACCES; goto out; } + + error = security_ops->file_mprotect(vma, prot); + if (error) + goto out; if (vma->vm_end > end) { error = mprotect_fixup(vma, &prev, nstart, end, newflags); diff -Nru a/net/core/scm.c b/net/core/scm.c --- a/net/core/scm.c Fri Jul 26 19:58:51 2002 +++ b/net/core/scm.c Fri Jul 26 19:58:51 2002 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -216,6 +217,9 @@ for (i=0, cmfptr=(int*)CMSG_DATA(cm); ifile_receive(fp[i]); + if (err) + break; err = get_unused_fd(); if (err < 0) break; diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c --- a/net/ipx/af_ipx.c Fri Jul 26 19:58:50 2002 +++ b/net/ipx/af_ipx.c Fri Jul 26 19:58:50 2002 @@ -145,6 +145,7 @@ static struct proto_ops ipx_dgram_ops; static struct net_proto_family *spx_family_ops; +static DECLARE_RWSEM(spx_family_ops_lock); static ipx_route *ipx_routes; static rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED; @@ -1929,10 +1930,13 @@ * From this point on SPX sockets are handled * by af_spx.c and the methods replaced. */ + down_read(&spx_family_ops_lock); if (spx_family_ops) { ret = spx_family_ops->create(sock, protocol); + up_read(&spx_family_ops_lock); goto decmod; } + up_read(&spx_family_ops_lock); /* Fall through if SPX is not loaded */ case SOCK_STREAM: /* Allow higher levels to piggyback */ default: @@ -2463,20 +2467,27 @@ int ipx_register_spx(struct proto_ops **p, struct net_proto_family *spx) { - if (spx_family_ops) - return -EBUSY; - cli(); - MOD_INC_USE_COUNT; - *p = &ipx_dgram_ops; - spx_family_ops = spx; - sti(); + int err; + + err = -EBUSY; + down_write(&spx_family_ops_lock); + if (!spx_family_ops) { + MOD_INC_USE_COUNT; + *p = &ipx_dgram_ops; + spx_family_ops = spx; + } + up_write(&spx_family_ops_lock); return 0; } int ipx_unregister_spx(void) { - spx_family_ops = NULL; - MOD_DEC_USE_COUNT; + down_write(&spx_family_ops_lock); + if (spx_family_ops) { + spx_family_ops = NULL; + MOD_DEC_USE_COUNT; + } + up_write(&spx_family_ops_lock); return 0; } diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c --- a/net/sunrpc/clnt.c Fri Jul 26 19:58:51 2002 +++ b/net/sunrpc/clnt.c Fri Jul 26 19:58:51 2002 @@ -335,6 +335,20 @@ rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++; } +void +rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) +{ + struct rpc_xprt *xprt = clnt->cl_xprt; + + xprt->sndsize = 0; + if (sndsize) + xprt->sndsize = sndsize + RPC_SLACK_SPACE; + xprt->rcvsize = 0; + if (rcvsize) + xprt->rcvsize = rcvsize + RPC_SLACK_SPACE; + xprt_sock_setbufsize(xprt); +} + /* * Restart an (async) RPC call. Usually called from within the * exit handler. diff -Nru a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c --- a/net/sunrpc/sunrpc_syms.c Fri Jul 26 19:58:52 2002 +++ b/net/sunrpc/sunrpc_syms.c Fri Jul 26 19:58:52 2002 @@ -50,6 +50,7 @@ EXPORT_SYMBOL(rpc_clnt_sigunmask); EXPORT_SYMBOL(rpc_delay); EXPORT_SYMBOL(rpc_restart_call); +EXPORT_SYMBOL(rpc_setbufsize); /* Client transport */ EXPORT_SYMBOL(xprt_create_proto); diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c --- a/net/sunrpc/xprt.c Fri Jul 26 19:58:50 2002 +++ b/net/sunrpc/xprt.c Fri Jul 26 19:58:50 2002 @@ -233,6 +233,7 @@ msg.msg_controllen = 0; oldfs = get_fs(); set_fs(get_ds()); + clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); result = sock_sendmsg(sock, &msg, slen); set_fs(oldfs); @@ -248,10 +249,7 @@ /* When the server has died, an ICMP port unreachable message * prompts ECONNREFUSED. */ - break; case -EAGAIN: - if (test_bit(SOCK_NOSPACE, &sock->flags)) - result = -ENOMEM; break; case -ENOTCONN: case -EPIPE: @@ -965,19 +963,15 @@ if (!sock_writeable(sk)) return; - if (!xprt_test_and_set_wspace(xprt)) { - spin_lock_bh(&xprt->sock_lock); - if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) - rpc_wake_up_task(xprt->snd_task); - spin_unlock_bh(&xprt->sock_lock); - } + if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) + return; - if (test_bit(SOCK_NOSPACE, &sock->flags)) { - if (sk->sleep && waitqueue_active(sk->sleep)) { - clear_bit(SOCK_NOSPACE, &sock->flags); - wake_up_interruptible(sk->sleep); - } - } + spin_lock_bh(&xprt->sock_lock); + if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) + rpc_wake_up_task(xprt->snd_task); + spin_unlock_bh(&xprt->sock_lock); + if (sk->sleep && waitqueue_active(sk->sleep)) + wake_up_interruptible(sk->sleep); } /* @@ -1083,7 +1077,6 @@ * called xprt_sendmsg(). */ while (1) { - xprt_clear_wspace(xprt); req->rq_xtime = jiffies; status = xprt_sendmsg(xprt, req); @@ -1098,7 +1091,7 @@ } else { if (status >= req->rq_slen) goto out_receive; - status = -ENOMEM; + status = -EAGAIN; break; } @@ -1121,16 +1114,17 @@ task->tk_status = status; switch (status) { - case -ENOMEM: - /* Protect against (udp|tcp)_write_space */ - spin_lock_bh(&xprt->sock_lock); - if (!xprt_wspace(xprt)) { - task->tk_timeout = req->rq_timeout.to_current; - rpc_sleep_on(&xprt->pending, task, NULL, NULL); - } - spin_unlock_bh(&xprt->sock_lock); - return; case -EAGAIN: + if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { + /* Protect against races with xprt_write_space */ + spin_lock_bh(&xprt->sock_lock); + if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { + task->tk_timeout = req->rq_timeout.to_current; + rpc_sleep_on(&xprt->pending, task, NULL, NULL); + } + spin_unlock_bh(&xprt->sock_lock); + return; + } /* Keep holding the socket if it is blocked */ rpc_delay(task, HZ>>4); return; @@ -1424,6 +1418,27 @@ rpciod_up(); return 0; +} + +/* + * Set socket buffer length + */ +void +xprt_sock_setbufsize(struct rpc_xprt *xprt) +{ + struct sock *sk = xprt->inet; + + if (xprt->stream) + return; + if (xprt->rcvsize) { + sk->userlocks |= SOCK_RCVBUF_LOCK; + sk->rcvbuf = xprt->rcvsize * RPC_MAXCONG * 2; + } + if (xprt->sndsize) { + sk->userlocks |= SOCK_SNDBUF_LOCK; + sk->sndbuf = xprt->sndsize * RPC_MAXCONG * 2; + sk->write_space(sk); + } } /* diff -Nru a/scripts/Makefile b/scripts/Makefile --- a/scripts/Makefile Fri Jul 26 19:58:51 2002 +++ b/scripts/Makefile Fri Jul 26 19:58:51 2002 @@ -5,9 +5,9 @@ # The following temporary rule will make sure that people's # trees get updated to the right permissions, since patch(1) # can't do it -CHMOD_FILES := docgen gen-all-syms kernel-doc mkcompile_h makelst +CHMOD_FILES := kernel-doc mkcompile_h makelst -all: fixdep split-include $(CHMOD_FILES) +all: fixdep split-include docproc $(CHMOD_FILES) $(CHMOD_FILES): FORCE @chmod a+x $@ @@ -36,11 +36,6 @@ cat $(TAIL) \ ) > $@ chmod 755 $@ - -# DocBook stuff -# --------------------------------------------------------------------------- - -doc-progs: docproc # --------------------------------------------------------------------------- diff -Nru a/scripts/docgen b/scripts/docgen --- a/scripts/docgen Fri Jul 26 19:58:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,10 +0,0 @@ -#!/bin/sh -set -e -if [ -z "$scripts_objtree" ] -then - X=`$TOPDIR/scripts/gen-all-syms "$*"` - $TOPDIR/scripts/docproc $X -else - X=`${scripts_objtree}gen-all-syms "$*"` - TOPDIR=. ${scripts_objtree}docproc $X -fi diff -Nru a/scripts/docproc.c b/scripts/docproc.c --- a/scripts/docproc.c Fri Jul 26 19:58:50 2002 +++ b/scripts/docproc.c Fri Jul 26 19:58:50 2002 @@ -1,104 +1,387 @@ +/* + * docproc is a simple preprocessor for the template files + * used as placeholders for the kernel internal documentation. + * docproc is used for documentation-frontend and + * dependency-generator. + * The two usages have in common that they require + * some knowledge of the .tmpl syntax, therefore they + * are kept together. + * + * documentation-frontend + * Scans the template file and call kernel-doc for + * all occurrences of ![EIF]file + * Beforehand each referenced file are scanned for + * any exported sympols "EXPORT_SYMBOL()" statements. + * This is used to create proper -function and + * -nofunction arguments in calls to kernel-doc. + * Usage: docproc doc file.tmpl + * + * dependency-generator: + * Scans the template file and list all files + * referenced in a format recognized by make. + * Usage: docproc depend file.tmpl + * Writes dependency information to stdout + * in the following format: + * file.tmpl src.c src2.c + * The filenames are obtained from the following constructs: + * !Efilename + * !Ifilename + * !Dfilename + * !Ffilename + * + */ + #include #include #include +#include #include +#include #include #include +/* exitstatus is used to keep track of any failing calls to kernel-doc, + * but execution continues. */ +int exitstatus = 0; + +typedef void DFL(char *); +DFL *defaultline; + +typedef void FILEONLY(char * file); +FILEONLY *internalfunctions; +FILEONLY *externalfunctions; +FILEONLY *symbolsonly; + +typedef void FILELINE(char * file, char * line); +FILELINE * singlefunctions; +FILELINE * entity_system; + +#define MAXLINESZ 2048 +#define MAXFILES 250 +#define KERNELDOCPATH "scripts/" +#define KERNELDOC "kernel-doc" +#define DOCBOOK "-docbook" +#define FUNCTION "-function" +#define NOFUNCTION "-nofunction" + +void usage (void) +{ + fprintf(stderr, "Usage: docproc {doc|depend} file\n"); + fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n"); + fprintf(stderr, "doc: frontend when generating kernel documentation\n"); + fprintf(stderr, "depend: generate list of files referenced within file\n"); +} + /* - * A simple filter for the templates + * Execute kernel-doc with parameters givin in svec */ +void exec_kernel_doc(char **svec) +{ + pid_t pid; + int ret; + /* Make sure output generated so far are flushed */ + fflush(stdout); + switch(pid=fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + execvp(KERNELDOCPATH KERNELDOC, svec); + perror("exec " KERNELDOCPATH KERNELDOC); + exit(1); + default: + waitpid(pid, &ret ,0); + } + if (WIFEXITED(ret)) + exitstatus = WEXITSTATUS(ret); + else + exitstatus = 0xff; +} -int main(int argc, char *argv[]) +/* Types used to create list of all exported symbols in a number of files */ +struct symbols +{ + char *name; +}; + +struct symfile +{ + char *filename; + struct symbols *symbollist; + int symbolcnt; +}; + +struct symfile symfilelist[MAXFILES]; +int symfilecnt = 0; + +void add_new_symbol(struct symfile *sym, char * symname) +{ + sym->symbollist = + realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *)); + sym->symbollist[sym->symbolcnt++].name = strdup(symname); +} + +/* Add a filename to the list */ +struct symfile * add_new_file(char * filename) +{ + symfilelist[symfilecnt++].filename = strdup(filename); + return &symfilelist[symfilecnt - 1]; +} +/* Check if file already are present in the list */ +struct symfile * filename_exist(char * filename) { - char buf[1024]; - char *vec[8192]; - char *fvec[200]; - char **svec; - char type[64]; int i; - int vp=2; - int ret=0; - pid_t pid; + for (i=0; i < symfilecnt; i++) + if (strcmp(symfilelist[i].filename, filename) == 0) + return &symfilelist[i]; + return NULL; +} +/* + * List all files referenced within the template file. + * Files are separated by tabs. + */ +void adddep(char * file) { printf("\t%s", file); } +void adddep2(char * file, char * line) { line = line; adddep(file); } +void noaction(char * line) { line = line; } +void noaction2(char * file, char * line) { file = file; line = line; } - if(chdir(getenv("TOPDIR"))) - { - perror("chdir"); - exit(1); +/* Echo the line without further action */ +void printline(char * line) { printf("%s", line); } + +/* + * Find all symbols exported with EXPORT_SYMBOL and EXPORT_SYMBOL_GPL + * in filename. + * All symbols located are stored in symfilelist. + */ +void find_export_symbols(char * filename) +{ + FILE * fp; + struct symfile *sym; + char line[MAXLINESZ]; + if (filename_exist(filename) == NULL) { + sym = add_new_file(filename); + fp = fopen(filename, "r"); + if (fp == NULL) + { + fprintf(stderr, "docproc: "); + perror(filename); + } + while(fgets(line, MAXLINESZ, fp)) { + char *p; + char *e; + if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) || + ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) { + /* Skip EXPORT_SYMBOL{_GPL} */ + while (isalnum(*p) || *p == '_') + p++; + /* Remove paranteses and additional ws */ + while (isspace(*p)) + p++; + if (*p != '(') + continue; /* Syntax error? */ + else + p++; + while (isspace(*p)) + p++; + e = p; + while (isalnum(*e) || *e == '_') + e++; + *e = '\0'; + add_new_symbol(sym, p); + } + } + fclose(fp); } +} + +/* + * Document all external or internal functions in a file. + * Call kernel-doc with following parameters: + * kernel-doc -docbook -nofunction function_name1 filename + * function names are obtained from all the the src files + * by find_export_symbols. + * intfunc uses -nofunction + * extfunc uses -function + */ +void docfunctions(char * filename, char * type) +{ + int i,j; + int symcnt = 0; + int idx = 0; + char **vec; - /* - * Build the exec array ahead of time. - */ - vec[0]="kernel-doc"; - vec[1]="-docbook"; - for(i=1;vp<8189;i++) - { - if(argv[i]==NULL) - break; - vec[vp++]=type; - vec[vp++]=argv[i]; + for (i=0; i <= symfilecnt; i++) + symcnt += symfilelist[i].symbolcnt; + vec = malloc((2 + 2 * symcnt + 2) * sizeof(char*)); + if (vec == NULL) { + perror("docproc: "); + exit(1); } - vec[vp++]=buf+2; - vec[vp++]=NULL; - - /* - * Now process the template - */ - - while(fgets(buf, 1024, stdin)) - { - if(*buf!='!') { - printf("%s", buf); - continue; + vec[idx++] = KERNELDOC; + vec[idx++] = DOCBOOK; + for (i=0; i < symfilecnt; i++) { + struct symfile * sym = &symfilelist[i]; + for (j=0; j < sym->symbolcnt; j++) { + vec[idx++] = type; + vec[idx++] = sym->symbollist[j].name; } + } + vec[idx++] = filename; + vec[idx] = NULL; + printf("\n", filename); + exec_kernel_doc(vec); + fflush(stdout); + free(vec); +} +void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); } +void extfunc(char * filename) { docfunctions(filename, FUNCTION); } - fflush(stdout); - svec = vec; - if(buf[1]=='E') - strcpy(type, "-function"); - else if(buf[1]=='I') - strcpy(type, "-nofunction"); - else if(buf[1]=='F') { - int snarf = 0; - fvec[0] = "kernel-doc"; - fvec[1] = "-docbook"; - strcpy (type, "-function"); - vp = 2; - for (i = 2; buf[i]; i++) { - if (buf[i] == ' ' || buf[i] == '\n') { - buf[i] = '\0'; - snarf = 1; - continue; - } - - if (snarf) { - snarf = 0; - fvec[vp++] = type; - fvec[vp++] = &buf[i]; - } +/* + * Document spåecific function(s) in a file. + * Call kernel-doc with the following parameters: + * kernel-doc -docbook -function function1 [-function function2] + */ +void singfunc(char * filename, char * line) +{ + char *vec[200]; /* Enough for specific functions */ + int i, idx = 0; + int startofsym = 1; + vec[idx++] = KERNELDOC; + vec[idx++] = DOCBOOK; + + /* Split line up in individual parameters preceeded by FUNCTION */ + for (i=0; line[i]; i++) { + if (isspace(line[i])) { + line[i] = '\0'; + startofsym = 1; + continue; + } + if (startofsym) { + startofsym = 0; + vec[idx++] = FUNCTION; + vec[idx++] = &line[i]; + } + } + vec[idx++] = filename; + vec[idx] = NULL; + exec_kernel_doc(vec); +} + +/* + * Parse file, calling action specific functions for: + * 1) Lines containing !E + * 2) Lines containing !I + * 3) Lines containing !D + * 4) Lines containing !F + * 5) Default lines - lines not matching the above + */ +void parse_file(FILE *infile) +{ + char line[MAXLINESZ]; + char * s; + while(fgets(line, MAXLINESZ, infile)) { + if (line[0] == '!') { + s = line + 2; + switch (line[1]) { + case 'E': + while (*s && !isspace(*s)) s++; + *s = '\0'; + externalfunctions(line+2); + break; + case 'I': + while (*s && !isspace(*s)) s++; + *s = '\0'; + internalfunctions(line+2); + break; + case 'D': + while (*s && !isspace(*s)) s++; + *s = '\0'; + symbolsonly(line+2); + break; + case 'F': + /* filename */ + while (*s && !isspace(*s)) s++; + *s++ = '\0'; + /* function names */ + while (isspace(*s)) + s++; + singlefunctions(line +2, s); + break; + default: + defaultline(line); } - fvec[vp++] = &buf[2]; - fvec[vp] = NULL; - svec = fvec; - } else - { - fprintf(stderr, "Unknown ! escape.\n"); - exit(1); } - switch(pid=fork()) - { - case -1: - perror("fork"); - exit(1); - case 0: - execvp("scripts/kernel-doc", svec); - perror("exec scripts/kernel-doc"); - exit(1); - default: - waitpid(pid, &ret ,0); + else { + defaultline(line); } } - exit(ret); + fflush(stdout); } + + +int main(int argc, char *argv[]) +{ + FILE * infile; + if (argc != 3) { + usage(); + exit(1); + } + /* Open file, exit on error */ + infile = fopen(argv[2], "r"); + if (infile == NULL) { + fprintf(stderr, "docproc: "); + perror(argv[2]); + exit(2); + } + + if (strcmp("doc", argv[1]) == 0) + { + /* Need to do this in two passes. + * First pass is used to collect all symbols exported + * in the various files. + * Second pass generate the documentation. + * This is required because function are declared + * and exported in different files :-(( + */ + /* Collect symbols */ + defaultline = noaction; + internalfunctions = find_export_symbols; + externalfunctions = find_export_symbols; + symbolsonly = find_export_symbols; + singlefunctions = noaction2; + parse_file(infile); + + /* Rewind to start from beginning of file again */ + fseek(infile, 0, SEEK_SET); + defaultline = printline; + internalfunctions = intfunc; + externalfunctions = extfunc; + symbolsonly = printline; + singlefunctions = singfunc; + + parse_file(infile); + } + else if (strcmp("depend", argv[1]) == 0) + { + /* Create first part of dependency chain + * file.tmpl */ + printf("%s\t", argv[2]); + defaultline = noaction; + internalfunctions = adddep; + externalfunctions = adddep; + symbolsonly = adddep; + singlefunctions = adddep2; + parse_file(infile); + printf("\n"); + } + else + { + fprintf(stderr, "Unknown option: %s\n", argv[1]); + exit(1); + } + fclose(infile); + fflush(stdout); + return exitstatus; +} + diff -Nru a/scripts/gen-all-syms b/scripts/gen-all-syms --- a/scripts/gen-all-syms Fri Jul 26 19:58:50 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,7 +0,0 @@ -#!/bin/sh -for i in $* -do - grep "EXPORT_SYMBOL.*(.*)" "$i" \ - | sed -e "s/EXPORT_SYMBOL.*(/ /" \ - | sed -e "s/).*$//" | sed -e "s/^ //" -done diff -Nru a/scripts/kernel-doc b/scripts/kernel-doc --- a/scripts/kernel-doc Fri Jul 26 19:58:51 2002 +++ b/scripts/kernel-doc Fri Jul 26 19:58:51 2002 @@ -233,9 +233,17 @@ # CAVEAT EMPTOR! Some of the others I localised may not want to be which # could cause "use of undefined value" or other bugs. my ($function, %function_table,%parametertypes,$declaration_purpose); -my ($type,$file,$declaration_name,$return_type); +my ($type,$declaration_name,$return_type); my ($newsection,$newcontents,$prototype,$filelist, $brcount, %source_map); +# Generated docbook code is inserted in a template at a point where +# docbook v3.1 requires a non-zero sequence of RefEntry's; see: +# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html +# We keep track of number of generated entries and generate a dummy +# if needs be to ensure the expanded template can be postprocessed +# into html. +my $section_counter = 0; + my $lineprefix=""; # states @@ -638,6 +646,7 @@ print " \n"; print $args{'type'}." ".$args{'struct'}." {\n"; foreach $parameter (@{$args{'parameterlist'}}) { + defined($args{'parameterdescs'}{$parameter}) || next; ($args{'parameterdescs'}{$parameter} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { @@ -658,6 +667,7 @@ print " \n"; foreach $parameter (@{$args{'parameterlist'}}) { + defined($args{'parameterdescs'}{$parameter}) || next; ($args{'parameterdescs'}{$parameter} ne $undescribed) || next; print " "; print " $parameter\n"; @@ -870,7 +880,7 @@ my ($parameter, $section); my $count; - print ".TH \"$args{'module'}\" 9 \"$args{'function'}\" \"$man_date\" \"API Manual\" LINUX\n"; + print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; print ".SH NAME\n"; print $args{'function'}." \\- ".$args{'purpose'}."\n"; @@ -896,13 +906,13 @@ $parenth = ""; } - print ".SH Arguments\n"; + print ".SH ARGUMENTS\n"; foreach $parameter (@{$args{'parameterlist'}}) { print ".IP \"".$parameter."\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; + print ".SH \"", uc $section, "\"\n"; output_highlight($args{'sections'}{$section}); } } @@ -1158,6 +1168,7 @@ ( $function_only == 2 && !defined($function_table{$name}))) { &$func(@_); + $section_counter++; } } @@ -1168,6 +1179,7 @@ no strict 'refs'; my $func = "output_intro_".$output_mode; &$func(@_); + $section_counter++; } ## @@ -1195,7 +1207,7 @@ # ignore embedded structs or unions $members =~ s/{.*}//g; - create_parameterlist($members, ';'); + create_parameterlist($members, ';', $file); output_declaration($declaration_name, 'struct', @@ -1211,7 +1223,8 @@ }); } else { - print STDERR "Cannot parse struct or union!\n"; + print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; + ++$errors; } } @@ -1228,8 +1241,8 @@ push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; - print STDERR "Warning($file:$.): Enum value '$arg' ". - "described in enum '$declaration_name'\n"; + print STDERR "Warning(${file}:$.): Enum value '$arg' ". + "not described in enum '$declaration_name'\n"; } } @@ -1246,7 +1259,8 @@ }); } else { - print STDERR "Cannot parse enum!\n"; + print STDERR "Error(${file}:$.): Cannot parse enum!\n"; + ++$errors; } } @@ -1272,13 +1286,15 @@ }); } else { - print STDERR "Cannot parse typedef!\n"; + print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; + ++$errors; } } -sub create_parameterlist($$) { +sub create_parameterlist($$$) { my $args = shift; my $splitter = shift; + my $file = shift; my $type; my $param; @@ -1332,7 +1348,7 @@ $parameterdescs{$param} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { - print STDERR "Warning($file:$.): Function parameter ". + print STDERR "Warning(${file}:$.): Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } @@ -1392,9 +1408,9 @@ $declaration_name = $2; my $args = $3; - create_parameterlist($args, ','); + create_parameterlist($args, ',', $file); } else { - print STDERR "Error($.): cannot understand prototype: '$prototype'\n"; + print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n"; ++$errors; return; } @@ -1456,8 +1472,9 @@ $state = 0; } -sub process_state3_function($) { +sub process_state3_function($$) { my $x = shift; + my $file = shift; if ($x =~ m#\s*/\*\s+MACDOC\s*#io) { # do nothing @@ -1474,8 +1491,9 @@ } } -sub process_state3_type($) { +sub process_state3_type($$) { my $x = shift; + my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's. @@ -1504,6 +1522,7 @@ my ($file) = @_; my $identifier; my $func; + my $initial_section_counter = $section_counter; if (defined($source_map{$file})) { $file = $source_map{$file}; @@ -1515,6 +1534,7 @@ return; } + $section_counter = 0; while () { if ($state == 0) { if (/$doc_start/o) { @@ -1555,10 +1575,10 @@ } if ($verbose) { - print STDERR "Info($.): Scanning doc for $identifier\n"; + print STDERR "Info(${file}:$.): Scanning doc for $identifier\n"; } } else { - print STDERR "WARN($.): Cannot understand $_ on line $.", + print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.", " - I thought it was a doc line\n"; ++$errors; $state = 0; @@ -1612,14 +1632,14 @@ } } else { # i dont know - bad line? ignore. - print STDERR "WARNING($.): bad line: $_"; + print STDERR "Warning(${file}:$.): bad line: $_"; ++$errors; } } elsif ($state == 3) { # scanning for function { (end of prototype) if ($decl_type eq 'function') { - process_state3_function($_); + process_state3_function($_, $file); } else { - process_state3_type($_); + process_state3_type($_, $file); } } elsif ($state == 4) { # Documentation block @@ -1671,5 +1691,35 @@ } } } + if ($initial_section_counter == $section_counter) { + print STDERR "Warning(${file}): no structured comments found\n"; + if ($output_mode eq "sgml") { + # The template wants at least one RefEntry here; make one. + print "\n"; + print " \n"; + print " \n"; + print " ${file}\n"; + print " \n"; + print " \n"; + print " Document generation inconsistency\n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + print " Oops\n"; + print " \n"; + print " \n"; + print " \n"; + print " The template for this document tried to insert\n"; + print " the structured comment from the file\n"; + print " ${file} at this point,\n"; + print " but none was found.\n"; + print " This dummy section is inserted to allow\n"; + print " generation to continue.\n"; + print " \n"; + print " \n"; + print " \n"; + print "\n"; + } + } } - diff -Nru a/security/capability.c b/security/capability.c --- a/security/capability.c Fri Jul 26 19:58:51 2002 +++ b/security/capability.c Fri Jul 26 19:58:51 2002 @@ -37,6 +37,16 @@ return -ENOSYS; } +static int cap_quotactl (int cmds, int type, int id, struct super_block *sb) +{ + return 0; +} + +static int cap_quota_on (struct file *f) +{ + return 0; +} + static int cap_ptrace (struct task_struct *parent, struct task_struct *child) { /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ @@ -95,6 +105,11 @@ target->cap_permitted = *permitted; } +static int cap_acct (struct file *file) +{ + return 0; +} + static int cap_bprm_alloc_security (struct linux_binprm *bprm) { return 0; @@ -189,6 +204,294 @@ current->keep_capabilities = 0; } +static int cap_sb_alloc_security (struct super_block *sb) +{ + return 0; +} + +static void cap_sb_free_security (struct super_block *sb) +{ + return; +} + +static int cap_sb_statfs (struct super_block *sb) +{ + return 0; +} + +static int cap_mount (char *dev_name, struct nameidata *nd, char *type, + unsigned long flags, void *data) +{ + return 0; +} + +static int cap_check_sb (struct vfsmount *mnt, struct nameidata *nd) +{ + return 0; +} + +static int cap_umount (struct vfsmount *mnt, int flags) +{ + return 0; +} + +static void cap_umount_close (struct vfsmount *mnt) +{ + return; +} + +static void cap_umount_busy (struct vfsmount *mnt) +{ + return; +} + +static void cap_post_remount (struct vfsmount *mnt, unsigned long flags, + void *data) +{ + return; +} + +static void cap_post_mountroot (void) +{ + return; +} + +static void cap_post_addmount (struct vfsmount *mnt, struct nameidata *nd) +{ + return; +} + +static int cap_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +{ + return 0; +} + +static void cap_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +{ + return; +} + +static int cap_inode_alloc_security (struct inode *inode) +{ + return 0; +} + +static void cap_inode_free_security (struct inode *inode) +{ + return; +} + +static int cap_inode_create (struct inode *inode, struct dentry *dentry, + int mask) +{ + return 0; +} + +static void cap_inode_post_create (struct inode *inode, struct dentry *dentry, + int mask) +{ + return; +} + +static int cap_inode_link (struct dentry *old_dentry, struct inode *inode, + struct dentry *new_dentry) +{ + return 0; +} + +static void cap_inode_post_link (struct dentry *old_dentry, struct inode *inode, + struct dentry *new_dentry) +{ + return; +} + +static int cap_inode_unlink (struct inode *inode, struct dentry *dentry) +{ + return 0; +} + +static int cap_inode_symlink (struct inode *inode, struct dentry *dentry, + const char *name) +{ + return 0; +} + +static void cap_inode_post_symlink (struct inode *inode, struct dentry *dentry, + const char *name) +{ + return; +} + +static int cap_inode_mkdir (struct inode *inode, struct dentry *dentry, + int mask) +{ + return 0; +} + +static void cap_inode_post_mkdir (struct inode *inode, struct dentry *dentry, + int mask) +{ + return; +} + +static int cap_inode_rmdir (struct inode *inode, struct dentry *dentry) +{ + return 0; +} + +static int cap_inode_mknod (struct inode *inode, struct dentry *dentry, + int major, dev_t minor) +{ + return 0; +} + +static void cap_inode_post_mknod (struct inode *inode, struct dentry *dentry, + int major, dev_t minor) +{ + return; +} + +static int cap_inode_rename (struct inode *old_inode, struct dentry *old_dentry, + struct inode *new_inode, struct dentry *new_dentry) +{ + return 0; +} + +static void cap_inode_post_rename (struct inode *old_inode, + struct dentry *old_dentry, + struct inode *new_inode, + struct dentry *new_dentry) +{ + return; +} + +static int cap_inode_readlink (struct dentry *dentry) +{ + return 0; +} + +static int cap_inode_follow_link (struct dentry *dentry, + struct nameidata *nameidata) +{ + return 0; +} + +static int cap_inode_permission (struct inode *inode, int mask) +{ + return 0; +} + +static int cap_inode_permission_lite (struct inode *inode, int mask) +{ + return 0; +} + +static int cap_inode_setattr (struct dentry *dentry, struct iattr *iattr) +{ + return 0; +} + +static int cap_inode_getattr (struct vfsmount *mnt, struct dentry *dentry) +{ + return 0; +} + +static void cap_post_lookup (struct inode *ino, struct dentry *d) +{ + return; +} + +static void cap_delete (struct inode *ino) +{ + return; +} + +static int cap_inode_setxattr (struct dentry *dentry, char *name, void *value, + size_t size, int flags) +{ + return 0; +} + +static int cap_inode_getxattr (struct dentry *dentry, char *name) +{ + return 0; +} + +static int cap_inode_listxattr (struct dentry *dentry) +{ + return 0; +} + +static int cap_inode_removexattr (struct dentry *dentry, char *name) +{ + return 0; +} + +static int cap_file_permission (struct file *file, int mask) +{ + return 0; +} + +static int cap_file_alloc_security (struct file *file) +{ + return 0; +} + +static void cap_file_free_security (struct file *file) +{ + return; +} + +static int cap_file_llseek (struct file *file) +{ + return 0; +} + +static int cap_file_ioctl (struct file *file, unsigned int command, + unsigned long arg) +{ + return 0; +} + +static int cap_file_mmap (struct file *file, unsigned long prot, + unsigned long flags) +{ + return 0; +} + +static int cap_file_mprotect (struct vm_area_struct *vma, unsigned long prot) +{ + return 0; +} + +static int cap_file_lock (struct file *file, unsigned int cmd, int blocking) +{ + return 0; +} + +static int cap_file_fcntl (struct file *file, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +static int cap_file_set_fowner (struct file *file) +{ + return 0; +} + +static int cap_file_send_sigiotask (struct task_struct *tsk, + struct fown_struct *fown, int fd, + int reason) +{ + return 0; +} + +static int cap_file_receive (struct file *file) +{ + return 0; +} + static int cap_task_create (unsigned long clone_flags) { return 0; @@ -387,41 +690,100 @@ } static struct security_operations capability_ops = { - ptrace: cap_ptrace, - capget: cap_capget, - capset_check: cap_capset_check, - capset_set: cap_capset_set, - capable: cap_capable, - sys_security: cap_sys_security, - - bprm_alloc_security: cap_bprm_alloc_security, - bprm_free_security: cap_bprm_free_security, - bprm_compute_creds: cap_bprm_compute_creds, - bprm_set_security: cap_bprm_set_security, - bprm_check_security: cap_bprm_check_security, + .ptrace = cap_ptrace, + .capget = cap_capget, + .capset_check = cap_capset_check, + .capset_set = cap_capset_set, + .acct = cap_acct, + .capable = cap_capable, + .sys_security = cap_sys_security, + .quotactl = cap_quotactl, + .quota_on = cap_quota_on, + + .bprm_alloc_security = cap_bprm_alloc_security, + .bprm_free_security = cap_bprm_free_security, + .bprm_compute_creds = cap_bprm_compute_creds, + .bprm_set_security = cap_bprm_set_security, + .bprm_check_security = cap_bprm_check_security, + + .sb_alloc_security = cap_sb_alloc_security, + .sb_free_security = cap_sb_free_security, + .sb_statfs = cap_sb_statfs, + .sb_mount = cap_mount, + .sb_check_sb = cap_check_sb, + .sb_umount = cap_umount, + .sb_umount_close = cap_umount_close, + .sb_umount_busy = cap_umount_busy, + .sb_post_remount = cap_post_remount, + .sb_post_mountroot = cap_post_mountroot, + .sb_post_addmount = cap_post_addmount, + .sb_pivotroot = cap_pivotroot, + .sb_post_pivotroot = cap_post_pivotroot, - task_create: cap_task_create, - task_alloc_security: cap_task_alloc_security, - task_free_security: cap_task_free_security, - task_setuid: cap_task_setuid, - task_post_setuid: cap_task_post_setuid, - task_setgid: cap_task_setgid, - task_setpgid: cap_task_setpgid, - task_getpgid: cap_task_getpgid, - task_getsid: cap_task_getsid, - task_setgroups: cap_task_setgroups, - task_setnice: cap_task_setnice, - task_setrlimit: cap_task_setrlimit, - task_setscheduler: cap_task_setscheduler, - task_getscheduler: cap_task_getscheduler, - task_wait: cap_task_wait, - task_kill: cap_task_kill, - task_prctl: cap_task_prctl, - task_kmod_set_label: cap_task_kmod_set_label, - task_reparent_to_init: cap_task_reparent_to_init, + .inode_alloc_security = cap_inode_alloc_security, + .inode_free_security = cap_inode_free_security, + .inode_create = cap_inode_create, + .inode_post_create = cap_inode_post_create, + .inode_link = cap_inode_link, + .inode_post_link = cap_inode_post_link, + .inode_unlink = cap_inode_unlink, + .inode_symlink = cap_inode_symlink, + .inode_post_symlink = cap_inode_post_symlink, + .inode_mkdir = cap_inode_mkdir, + .inode_post_mkdir = cap_inode_post_mkdir, + .inode_rmdir = cap_inode_rmdir, + .inode_mknod = cap_inode_mknod, + .inode_post_mknod = cap_inode_post_mknod, + .inode_rename = cap_inode_rename, + .inode_post_rename = cap_inode_post_rename, + .inode_readlink = cap_inode_readlink, + .inode_follow_link = cap_inode_follow_link, + .inode_permission = cap_inode_permission, + .inode_permission_lite = cap_inode_permission_lite, + .inode_setattr = cap_inode_setattr, + .inode_getattr = cap_inode_getattr, + .inode_post_lookup = cap_post_lookup, + .inode_delete = cap_delete, + .inode_setxattr = cap_inode_setxattr, + .inode_getxattr = cap_inode_getxattr, + .inode_listxattr = cap_inode_listxattr, + .inode_removexattr = cap_inode_removexattr, - register_security: cap_register, - unregister_security: cap_unregister, + .file_permission = cap_file_permission, + .file_alloc_security = cap_file_alloc_security, + .file_free_security = cap_file_free_security, + .file_llseek = cap_file_llseek, + .file_ioctl = cap_file_ioctl, + .file_mmap = cap_file_mmap, + .file_mprotect = cap_file_mprotect, + .file_lock = cap_file_lock, + .file_fcntl = cap_file_fcntl, + .file_set_fowner = cap_file_set_fowner, + .file_send_sigiotask = cap_file_send_sigiotask, + .file_receive = cap_file_receive, + + .task_create = cap_task_create, + .task_alloc_security = cap_task_alloc_security, + .task_free_security = cap_task_free_security, + .task_setuid = cap_task_setuid, + .task_post_setuid = cap_task_post_setuid, + .task_setgid = cap_task_setgid, + .task_setpgid = cap_task_setpgid, + .task_getpgid = cap_task_getpgid, + .task_getsid = cap_task_getsid, + .task_setgroups = cap_task_setgroups, + .task_setnice = cap_task_setnice, + .task_setrlimit = cap_task_setrlimit, + .task_setscheduler = cap_task_setscheduler, + .task_getscheduler = cap_task_getscheduler, + .task_wait = cap_task_wait, + .task_kill = cap_task_kill, + .task_prctl = cap_task_prctl, + .task_kmod_set_label = cap_task_kmod_set_label, + .task_reparent_to_init = cap_task_reparent_to_init, + + .register_security = cap_register, + .unregister_security = cap_unregister, }; #if defined(CONFIG_SECURITY_CAPABILITIES_MODULE) diff -Nru a/security/dummy.c b/security/dummy.c --- a/security/dummy.c Fri Jul 26 19:58:51 2002 +++ b/security/dummy.c Fri Jul 26 19:58:51 2002 @@ -46,6 +46,11 @@ return; } +static int dummy_acct (struct file *file) +{ + return 0; +} + static int dummy_capable (struct task_struct *tsk, int cap) { if (cap_is_fs_cap (cap) ? tsk->fsuid == 0 : tsk->euid == 0) @@ -62,6 +67,16 @@ return -ENOSYS; } +static int dummy_quotactl (int cmds, int type, int id, struct super_block *sb) +{ + return 0; +} + +static int dummy_quota_on (struct file *f) +{ + return 0; +} + static int dummy_bprm_alloc_security (struct linux_binprm *bprm) { return 0; @@ -87,6 +102,298 @@ return 0; } +static int dummy_sb_alloc_security (struct super_block *sb) +{ + return 0; +} + +static void dummy_sb_free_security (struct super_block *sb) +{ + return; +} + +static int dummy_sb_statfs (struct super_block *sb) +{ + return 0; +} + +static int dummy_mount (char *dev_name, struct nameidata *nd, char *type, + unsigned long flags, void *data) +{ + return 0; +} + +static int dummy_check_sb (struct vfsmount *mnt, struct nameidata *nd) +{ + return 0; +} + +static int dummy_umount (struct vfsmount *mnt, int flags) +{ + return 0; +} + +static void dummy_umount_close (struct vfsmount *mnt) +{ + return; +} + +static void dummy_umount_busy (struct vfsmount *mnt) +{ + return; +} + +static void dummy_post_remount (struct vfsmount *mnt, unsigned long flags, + void *data) +{ + return; +} + + +static void dummy_post_mountroot (void) +{ + return; +} + +static void dummy_post_addmount (struct vfsmount *mnt, struct nameidata *nd) +{ + return; +} + +static int dummy_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +{ + return 0; +} + +static void dummy_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +{ + return; +} + +static int dummy_inode_alloc_security (struct inode *inode) +{ + return 0; +} + +static void dummy_inode_free_security (struct inode *inode) +{ + return; +} + +static int dummy_inode_create (struct inode *inode, struct dentry *dentry, + int mask) +{ + return 0; +} + +static void dummy_inode_post_create (struct inode *inode, struct dentry *dentry, + int mask) +{ + return; +} + +static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode, + struct dentry *new_dentry) +{ + return 0; +} + +static void dummy_inode_post_link (struct dentry *old_dentry, + struct inode *inode, + struct dentry *new_dentry) +{ + return; +} + +static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry) +{ + return 0; +} + +static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry, + const char *name) +{ + return 0; +} + +static void dummy_inode_post_symlink (struct inode *inode, + struct dentry *dentry, const char *name) +{ + return; +} + +static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry, + int mask) +{ + return 0; +} + +static void dummy_inode_post_mkdir (struct inode *inode, struct dentry *dentry, + int mask) +{ + return; +} + +static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry) +{ + return 0; +} + +static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry, + int major, dev_t minor) +{ + return 0; +} + +static void dummy_inode_post_mknod (struct inode *inode, struct dentry *dentry, + int major, dev_t minor) +{ + return; +} + +static int dummy_inode_rename (struct inode *old_inode, + struct dentry *old_dentry, + struct inode *new_inode, + struct dentry *new_dentry) +{ + return 0; +} + +static void dummy_inode_post_rename (struct inode *old_inode, + struct dentry *old_dentry, + struct inode *new_inode, + struct dentry *new_dentry) +{ + return; +} + +static int dummy_inode_readlink (struct dentry *dentry) +{ + return 0; +} + +static int dummy_inode_follow_link (struct dentry *dentry, + struct nameidata *nameidata) +{ + return 0; +} + +static int dummy_inode_permission (struct inode *inode, int mask) +{ + return 0; +} + +static int dummy_inode_permission_lite (struct inode *inode, int mask) +{ + return 0; +} + +static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr) +{ + return 0; +} + +static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry) +{ + return 0; +} + +static void dummy_post_lookup (struct inode *ino, struct dentry *d) +{ + return; +} + +static void dummy_delete (struct inode *ino) +{ + return; +} + +static int dummy_inode_setxattr (struct dentry *dentry, char *name, void *value, + size_t size, int flags) +{ + return 0; +} + +static int dummy_inode_getxattr (struct dentry *dentry, char *name) +{ + return 0; +} + +static int dummy_inode_listxattr (struct dentry *dentry) +{ + return 0; +} + +static int dummy_inode_removexattr (struct dentry *dentry, char *name) +{ + return 0; +} + +static int dummy_file_permission (struct file *file, int mask) +{ + return 0; +} + +static int dummy_file_alloc_security (struct file *file) +{ + return 0; +} + +static void dummy_file_free_security (struct file *file) +{ + return; +} + +static int dummy_file_llseek (struct file *file) +{ + return 0; +} + +static int dummy_file_ioctl (struct file *file, unsigned int command, + unsigned long arg) +{ + return 0; +} + +static int dummy_file_mmap (struct file *file, unsigned long prot, + unsigned long flags) +{ + return 0; +} + +static int dummy_file_mprotect (struct vm_area_struct *vma, unsigned long prot) +{ + return 0; +} + +static int dummy_file_lock (struct file *file, unsigned int cmd, int blocking) +{ + return 0; +} + +static int dummy_file_fcntl (struct file *file, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +static int dummy_file_set_fowner (struct file *file) +{ + return 0; +} + +static int dummy_file_send_sigiotask (struct task_struct *tsk, + struct fown_struct *fown, int fd, + int reason) +{ + return 0; +} + +static int dummy_file_receive (struct file *file) +{ + return 0; +} + static int dummy_task_create (unsigned long clone_flags) { return 0; @@ -197,40 +504,99 @@ } struct security_operations dummy_security_ops = { - ptrace: dummy_ptrace, - capget: dummy_capget, - capset_check: dummy_capset_check, - capset_set: dummy_capset_set, - capable: dummy_capable, - sys_security: dummy_sys_security, - - bprm_alloc_security: dummy_bprm_alloc_security, - bprm_free_security: dummy_bprm_free_security, - bprm_compute_creds: dummy_bprm_compute_creds, - bprm_set_security: dummy_bprm_set_security, - bprm_check_security: dummy_bprm_check_security, - - task_create: dummy_task_create, - task_alloc_security: dummy_task_alloc_security, - task_free_security: dummy_task_free_security, - task_setuid: dummy_task_setuid, - task_post_setuid: dummy_task_post_setuid, - task_setgid: dummy_task_setgid, - task_setpgid: dummy_task_setpgid, - task_getpgid: dummy_task_getpgid, - task_getsid: dummy_task_getsid, - task_setgroups: dummy_task_setgroups, - task_setnice: dummy_task_setnice, - task_setrlimit: dummy_task_setrlimit, - task_setscheduler: dummy_task_setscheduler, - task_getscheduler: dummy_task_getscheduler, - task_wait: dummy_task_wait, - task_kill: dummy_task_kill, - task_prctl: dummy_task_prctl, - task_kmod_set_label: dummy_task_kmod_set_label, - task_reparent_to_init: dummy_task_reparent_to_init, + .ptrace = dummy_ptrace, + .capget = dummy_capget, + .capset_check = dummy_capset_check, + .capset_set = dummy_capset_set, + .acct = dummy_acct, + .capable = dummy_capable, + .sys_security = dummy_sys_security, + .quotactl = dummy_quotactl, + .quota_on = dummy_quota_on, + + .bprm_alloc_security = dummy_bprm_alloc_security, + .bprm_free_security = dummy_bprm_free_security, + .bprm_compute_creds = dummy_bprm_compute_creds, + .bprm_set_security = dummy_bprm_set_security, + .bprm_check_security = dummy_bprm_check_security, + + .sb_alloc_security = dummy_sb_alloc_security, + .sb_free_security = dummy_sb_free_security, + .sb_statfs = dummy_sb_statfs, + .sb_mount = dummy_mount, + .sb_check_sb = dummy_check_sb, + .sb_umount = dummy_umount, + .sb_umount_close = dummy_umount_close, + .sb_umount_busy = dummy_umount_busy, + .sb_post_remount = dummy_post_remount, + .sb_post_mountroot = dummy_post_mountroot, + .sb_post_addmount = dummy_post_addmount, + .sb_pivotroot = dummy_pivotroot, + .sb_post_pivotroot = dummy_post_pivotroot, - register_security: dummy_register, - unregister_security: dummy_unregister, + .inode_alloc_security = dummy_inode_alloc_security, + .inode_free_security = dummy_inode_free_security, + .inode_create = dummy_inode_create, + .inode_post_create = dummy_inode_post_create, + .inode_link = dummy_inode_link, + .inode_post_link = dummy_inode_post_link, + .inode_unlink = dummy_inode_unlink, + .inode_symlink = dummy_inode_symlink, + .inode_post_symlink = dummy_inode_post_symlink, + .inode_mkdir = dummy_inode_mkdir, + .inode_post_mkdir = dummy_inode_post_mkdir, + .inode_rmdir = dummy_inode_rmdir, + .inode_mknod = dummy_inode_mknod, + .inode_post_mknod = dummy_inode_post_mknod, + .inode_rename = dummy_inode_rename, + .inode_post_rename = dummy_inode_post_rename, + .inode_readlink = dummy_inode_readlink, + .inode_follow_link = dummy_inode_follow_link, + .inode_permission = dummy_inode_permission, + .inode_permission_lite = dummy_inode_permission_lite, + .inode_setattr = dummy_inode_setattr, + .inode_getattr = dummy_inode_getattr, + .inode_post_lookup = dummy_post_lookup, + .inode_delete = dummy_delete, + .inode_setxattr = dummy_inode_setxattr, + .inode_getxattr = dummy_inode_getxattr, + .inode_listxattr = dummy_inode_listxattr, + .inode_removexattr = dummy_inode_removexattr, + + .file_permission = dummy_file_permission, + .file_alloc_security = dummy_file_alloc_security, + .file_free_security = dummy_file_free_security, + .file_llseek = dummy_file_llseek, + .file_ioctl = dummy_file_ioctl, + .file_mmap = dummy_file_mmap, + .file_mprotect = dummy_file_mprotect, + .file_lock = dummy_file_lock, + .file_fcntl = dummy_file_fcntl, + .file_set_fowner = dummy_file_set_fowner, + .file_send_sigiotask = dummy_file_send_sigiotask, + .file_receive = dummy_file_receive, + + .task_create = dummy_task_create, + .task_alloc_security = dummy_task_alloc_security, + .task_free_security = dummy_task_free_security, + .task_setuid = dummy_task_setuid, + .task_post_setuid = dummy_task_post_setuid, + .task_setgid = dummy_task_setgid, + .task_setpgid = dummy_task_setpgid, + .task_getpgid = dummy_task_getpgid, + .task_getsid = dummy_task_getsid, + .task_setgroups = dummy_task_setgroups, + .task_setnice = dummy_task_setnice, + .task_setrlimit = dummy_task_setrlimit, + .task_setscheduler = dummy_task_setscheduler, + .task_getscheduler = dummy_task_getscheduler, + .task_wait = dummy_task_wait, + .task_kill = dummy_task_kill, + .task_prctl = dummy_task_prctl, + .task_kmod_set_label = dummy_task_kmod_set_label, + .task_reparent_to_init = dummy_task_reparent_to_init, + + .register_security = dummy_register, + .unregister_security = dummy_unregister, }; diff -Nru a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c --- a/sound/isa/ad1848/ad1848_lib.c Fri Jul 26 19:58:51 2002 +++ b/sound/isa/ad1848/ad1848_lib.c Fri Jul 26 19:58:51 2002 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff -Nru a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c --- a/sound/oss/i810_audio.c Fri Jul 26 19:58:52 2002 +++ b/sound/oss/i810_audio.c Fri Jul 26 19:58:52 2002 @@ -1733,7 +1733,7 @@ } spin_unlock_irqrestore(&state->card->lock, flags); - synchronize_irq(); + synchronize_irq(state->card->irq); dmabuf->ready = 0; dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; @@ -2814,15 +2814,14 @@ } dmabuf->count = dmabuf->dmasize; outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); - save_flags(flags); - cli(); + local_irq_save(flags); start_dac(state); offset = i810_get_dma_addr(state, 0); mdelay(50); new_offset = i810_get_dma_addr(state, 0); stop_dac(state); outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); - restore_flags(flags); + local_irq_restore(flags); i = new_offset - offset; #ifdef DEBUG printk("i810_audio: %d bytes in 50 milliseconds\n", i); diff -Nru a/sound/pci/Config.in b/sound/pci/Config.in --- a/sound/pci/Config.in Fri Jul 26 19:58:51 2002 +++ b/sound/pci/Config.in Fri Jul 26 19:58:51 2002 @@ -8,6 +8,7 @@ if [ "$CONFIG_SND_CS46XX" != "n" ]; then bool ' Cirrus Logic (Sound Fusion) MMAP support for OSS' CONFIG_SND_CS46XX_ACCEPT_VALID fi +dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c --- a/sound/pci/ali5451/ali5451.c Fri Jul 26 19:58:52 2002 +++ b/sound/pci/ali5451/ali5451.c Fri Jul 26 19:58:52 2002 @@ -1968,7 +1968,7 @@ static int snd_ali_free(ali_t * codec) { snd_ali_disable_address_interrupt(codec); - synchronize_irq(); + synchronize_irq(codec->irq); if (codec->irq >=0) free_irq(codec->irq, (void *)codec); if (codec->res_port) { @@ -2116,7 +2116,7 @@ return -EBUSY; } - synchronize_irq(); + synchronize_irq(pci->irq); codec->synth.chmap = 0; codec->synth.chcnt = 0; diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c --- a/sound/pci/cmipci.c Fri Jul 26 19:58:50 2002 +++ b/sound/pci/cmipci.c Fri Jul 26 19:58:50 2002 @@ -2479,7 +2479,7 @@ /* reset mixer */ snd_cmipci_mixer_write(cm, 0, 0); - synchronize_irq(); + synchronize_irq(cm->irq); free_irq(cm->irq, (void *)cm); } diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c --- a/sound/pci/cs4281.c Fri Jul 26 19:58:52 2002 +++ b/sound/pci/cs4281.c Fri Jul 26 19:58:52 2002 @@ -1300,7 +1300,8 @@ } #endif snd_cs4281_proc_done(chip); - synchronize_irq(); + if(chip->irq >= 0) + synchronize_irq(chip->irq); /* Mask interrupts */ snd_cs4281_pokeBA0(chip, BA0_HIMR, 0x7fffffff); @@ -1603,7 +1604,7 @@ BA0_HISR_DMA(1) | BA0_HISR_DMA(2) | BA0_HISR_DMA(3))); - synchronize_irq(); + synchronize_irq(chip->irq); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_cs4281_free(chip); diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c --- a/sound/pci/ens1370.c Fri Jul 26 19:58:51 2002 +++ b/sound/pci/ens1370.c Fri Jul 26 19:58:51 2002 @@ -1532,7 +1532,8 @@ outl(0, ES_REG(ensoniq, CONTROL)); /* switch everything off */ outl(0, ES_REG(ensoniq, SERIAL)); /* clear serial interface */ #endif - synchronize_irq(ensoniq->irq); + if(ensoniq->irq >= 0) + synchronize_irq(ensoniq->irq); pci_set_power_state(ensoniq->pci, 3); __hw_end: #ifdef CHIP1370 diff -Nru a/sound/pci/ice1712.c b/sound/pci/ice1712.c --- a/sound/pci/ice1712.c Fri Jul 26 19:58:52 2002 +++ b/sound/pci/ice1712.c Fri Jul 26 19:58:52 2002 @@ -4070,9 +4070,10 @@ /* --- */ __hw_end: snd_ice1712_proc_done(ice); - synchronize_irq(); - if (ice->irq) + if (ice->irq) { + synchronize_irq(ice->irq); free_irq(ice->irq, (void *) ice); + } if (ice->res_port) { release_resource(ice->res_port); kfree_nocheck(ice->res_port); @@ -4143,7 +4144,7 @@ pci_write_config_word(ice->pci, 0x40, 0x807f); pci_write_config_word(ice->pci, 0x42, 0x0006); snd_ice1712_proc_init(ice); - synchronize_irq(); + synchronize_irq(ice->irq); if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) { snd_ice1712_free(ice); diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c Fri Jul 26 19:58:51 2002 +++ b/sound/pci/intel8x0.c Fri Jul 26 19:58:51 2002 @@ -1104,7 +1104,8 @@ outb(ICH_RESETREGS, ICHREG(chip, PO_CR)); outb(ICH_RESETREGS, ICHREG(chip, MC_CR)); /* --- */ - synchronize_irq(chip->irq); + if(chip->irq >= 0) + synchronize_irq(chip->irq); __hw_end: if (chip->bdbars) snd_free_pci_pages(chip->pci, 3 * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr); diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c --- a/sound/pci/maestro3.c Fri Jul 26 19:58:51 2002 +++ b/sound/pci/maestro3.c Fri Jul 26 19:58:51 2002 @@ -2310,7 +2310,8 @@ vfree(chip->suspend_mem); #endif - synchronize_irq(); + if(chip->irq >= 0) + synchronize_irq(chip->irq); if (chip->iobase_res) { release_resource(chip->iobase_res); diff -Nru a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c --- a/sound/pci/nm256/nm256.c Fri Jul 26 19:58:52 2002 +++ b/sound/pci/nm256/nm256.c Fri Jul 26 19:58:52 2002 @@ -1346,7 +1346,8 @@ if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running) snd_nm256_capture_stop(chip); - synchronize_irq(); + if(chip->irq >= 0) + synchronize_irq(chip->irq); if (chip->cport) iounmap((void *) chip->cport); diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c --- a/sound/pci/via686.c Fri Jul 26 19:58:51 2002 +++ b/sound/pci/via686.c Fri Jul 26 19:58:51 2002 @@ -993,7 +993,8 @@ snd_via686a_channel_reset(chip, &chip->playback_fm); /* --- */ __end_hw: - synchronize_irq(); + if(chip->irq >= 0) + synchronize_irq(chip->irq); if (chip->tables) snd_free_pci_pages(chip->pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, chip->tables, chip->tables_addr); if (chip->res_port) { @@ -1055,7 +1056,7 @@ if (ac97_clock >= 8000 && ac97_clock <= 48000) chip->ac97_clock = ac97_clock; pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision); - synchronize_irq(); + synchronize_irq(pci->irq); /* initialize offsets */ chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS; diff -Nru a/sound/pci/via8233.c b/sound/pci/via8233.c --- a/sound/pci/via8233.c Fri Jul 26 19:58:51 2002 +++ b/sound/pci/via8233.c Fri Jul 26 19:58:51 2002 @@ -759,7 +759,8 @@ snd_via8233_channel_reset(chip, &chip->capture); /* --- */ __end_hw: - synchronize_irq(); + if (chip->irq) + synchronize_irq(chip->irq); if (chip->tables) snd_free_pci_pages(chip->pci, VIA_NUM_OF_DMA_CHANNELS * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, @@ -817,7 +818,7 @@ if (ac97_clock >= 8000 && ac97_clock <= 48000) chip->ac97_clock = ac97_clock; pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision); - synchronize_irq(); + synchronize_irq(chip->irq); /* initialize offsets */ #if 0